From c7aefa2cd7ef9bae68773df9f338da4b44a76d73 Mon Sep 17 00:00:00 2001 From: Jorge Arellano Cid Date: Tue, 26 May 2015 11:29:21 -0300 Subject: Fix view-source dpi to handle null characters correctly Although not allowed in text contexts, null characters should not stop/halt/fail dpi protocol, thus the patch. Test Example. Display a file with these contents: null padding^@^@ (two trailing null characters) and view source for it. Note that dillo will not _display_ the file completely correct, it will eat a char after each null, but this is not a problem in dpi nor dpip but in rendering, the cache gets it right. Adding code to correctly _display_ these anomalous pages is probably not worth the effort though. --- doc/Dpid.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'doc') diff --git a/doc/Dpid.txt b/doc/Dpid.txt index 82b81311..6c418f57 100644 --- a/doc/Dpid.txt +++ b/doc/Dpid.txt @@ -285,9 +285,10 @@ commented code in hello.c and start making changes! Debugging a dpi --------------- - The simplest way is to add printf() feedback using the MSG* + The simplest way is to add printf-like feedback using the MSG* macros. You can start the dpid by hand on a terminal to force -messages to go there. +messages to go there. Filter dpis use sdterr and server dpis +stdout. Sometimes more complex dpis need more than MSG*. In this case you can use gdb like this. -- cgit v1.2.3 From fcee2570a762a3fe7aecf714188c964f35820d73 Mon Sep 17 00:00:00 2001 From: corvid Date: Thu, 28 May 2015 18:53:58 +0000 Subject: update docs a bit --- dillorc | 2 +- doc/dillo.1.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'doc') diff --git a/dillorc b/dillorc index 9c783a03..18d52dd0 100644 --- a/dillorc +++ b/dillorc @@ -189,7 +189,7 @@ search_url="Google http://www.google.com/search?ie=UTF-8&oe=UTF-8&q=%s" # page/image/stylesheet. #http_persistent_conns=NO -# Set the proxy information for http. +# Set the proxy information for http/https. # Note that the http_proxy environment variable overrides this setting. # WARNING: FTP and downloads plugins use wget. To use a proxy with them, # you will need to configure wget accordingly. See diff --git a/doc/dillo.1.in b/doc/dillo.1.in index 3bb5fe03..f86d050c 100644 --- a/doc/dillo.1.in +++ b/doc/dillo.1.in @@ -11,7 +11,7 @@ dillo \- web browser Dillo is a lightweight graphical web browser that aims to be secure. It handles HTTP internally, and FILE, FTP, and DATA URIs are handled through a plugin system (dpi). In addition, -.I INSECURE +.I EXPERIMENTAL HTTPS support can be enabled. Both FTP and Dillo's download manager use the .BR wget (1) downloader. @@ -68,7 +68,7 @@ Error in command line arguments. User's home directory. .TP .B http_proxy -URL of proxy to send HTTP traffic through. +URL of proxy to send HTTP/HTTPS traffic through. .SH FILES .TP .I dpid -- cgit v1.2.3 From eb7ee4703ced8a02404eb0ebfa5b771fc5e916d5 Mon Sep 17 00:00:00 2001 From: Sebastian Geerken Date: Mon, 1 Jun 2015 21:36:41 +0200 Subject: Updated doc directory. --- doc/Images.txt | 3 + doc/Imgbuf.txt | 177 ------------------------------------------------------ doc/Makefile.am | 6 +- doc/Selection.txt | 149 --------------------------------------------- 4 files changed, 5 insertions(+), 330 deletions(-) delete mode 100644 doc/Imgbuf.txt delete mode 100644 doc/Selection.txt (limited to 'doc') diff --git a/doc/Images.txt b/doc/Images.txt index 6a36e6f5..62082e48 100644 --- a/doc/Images.txt +++ b/doc/Images.txt @@ -1,5 +1,8 @@ January 2009, --Jcid +Update June 2015: See also doc/dw-images-and-backgrounds.doc, or +../html/dw-images-and-backgrounds.html (generated by doxygen). + ------ IMAGES ------ diff --git a/doc/Imgbuf.txt b/doc/Imgbuf.txt deleted file mode 100644 index f4a56660..00000000 --- a/doc/Imgbuf.txt +++ /dev/null @@ -1,177 +0,0 @@ -Aug 2004, S.Geerken@ping.de - -============= -Image Buffers -============= - -General -======= - -Image buffers depend on the platform (see DwRender.txt), but have a -general, platform independant interface, which is described in this -section. The next section describes the Gdk version of Imgbuf. - -The structure ImgBuf will become part of the image processing, between -image data decoding and the widget DwImage. Its purposes are - - 1. storing the image data, - 2. handling scaled versions of this buffer, and - 3. drawing. - -The latter must be done independently from the window. - -Storing Image Data ------------------- -Imgbuf supports five image types, which are listed in the table -below. The representation defines, how the colors are stored within -the data, which is passed to a_Imgbuf_copy_row(). - - | bytes per | - type | pixel | representation - ---------------+-----------+------------------------- - RGB | 3 | red, green, blue - RGBA | 4 | red, green, blue, alpha - gray | 1 | gray value - indexed | 1 | index to colormap - indexed alpha | 1 | index to colormap - -The last two types need a colormap, which is set by -a_Imgbuf_set_cmap(), which must be called before -a_Imgbuf_copy_row(). This function expects the colors as 32 bit -unsigned integers, which have the format 0xrrbbgg (for indexed -images), or 0xaarrggbb (for indexed alpha), respectively. - -Scaling -------- -The buffer with the original size, which was created by -a_Imgbuf_new(), is called root buffer. Imgbuf provides the ability to -scale buffers. Generally, both root buffers, as well as scaled -buffers, may be shared, memory management is done by reference -counters. - -Via a_Imgbuf_get_scaled_buf(), you can retrieve a scaled buffer. The -way, how this function works in detail, is described in the code, but -generally, something like this works always, in an efficient way: - - old_buf = cur_buf; - cur_buf = a_Imgbuf_get_scaled_buf(old_buf, with, height); - a_Imgbuf_unref (old_buf); - -Old_buf may both be a root buffer, or a scaled buffer. - -(As an exception, there should always be a reference on the root -buffer, since scaled buffers cannot exist without the root buffer, but -on the other side, do not hold references on it. So, if in the example -above, old_buf would be a root buffer, and there would, at the -beginning, only be one reference on it, new_buf would also be -destroyed, along with old_buf. Therefore, an external reference must -be added to the root buffer, which is in dillo done within the dicache -module.) - -The root buffer keeps a list of all children, and all operations -operating on the image data (a_Imgbuf_copy_row() and -a_Imgbuf_set_cmap()) are delegated to the scaled buffers, when -processed, and inherited, when a new scaled buffer is created. This -means, that they must only be performed for the root buffer. - -Drawing -------- -There are two situations, when drawing is necessary: - - 1. To react on expose events, the function a_Imgbuf_draw() can be - used. Notice that the exact signature of this function is - platform dependant. - - 2. When a row has been copied, it has to be drawn. To determine the - area, which has to be drawn, the function - a_Imgbuf_get_row_area() should be used. In dillo, the dicache - module will first call a_Img_copy_row(), and then call - a_Dw_image_draw_row() for the images connected to this image - buffer. a_Dw_image_draw_row() will then call - p_Dw_widget_queue_draw(), with an area determined by - a_Imgbuf_get_row_area(). - - -The Gdk Implementation -====================== - -The Gdk implementation is used by the Gtk+ platform. [... todo] - - -Global Scalers -============== - -In some cases, there is a context, where images have to be scaled -often, by a relatively constant factor. For example, the preview -window (GtkDwPreview) draws images via the Imgbuf draw functions, but -uses scaled buffers. Scaling such a buffer each time it is needed, -causes huge performance losses. On the other hand, if the preview -window would keep these scaled buffers (e.g. by lazy mapping of the -original buffer to the scaled buffer), the scaled buffers get never -freed, since the view is not told about, when the original buffer is -not needed anymore. (n.b., that currently, the scaled buffers are -destroyed, when the original buffer is destroyed, but this may change, -and even this would leave "zombies" in this mapping structure, where -the values refer to dead pointers). - -It is sufficient, that references on the scaled buffers are referred -somehow, so that they do not get destroyed between different -usages. The caller (in this case the preview) simply requests a scaled -buffer, but the Imgbuf returns this from the list of already scaled -buffers. - -These references are hold by special structures, which are called -"scalers". There are two types of scalers, local scalers, which are -bound to image buffers, and global scalers, which refer to multiple -scalers. - -What happens in different situations: - - - The caller (e.g. the preview) requests a scaled buffer. For this, - it uses a special method, which also passes the global image - scaler, which was created before (for the preview, there is a 1-1 - association). The Imgbuf uses this global image scaler, to - identify the caller, and keeps a list of them. If this global - scaler is not yet in the list, it is added, and a local scaler is - created. - - - - - - -There are three images in the page, i1a, i1b, and i2. I1a and i1b -refer to the same image recource, represented by the root image buffer -iba, which original size is 200 x 200. I1a is displayed in original -size, while i1b is displayed at 100 x 100. I2 refers to an other -recource, ibb, which has the size 300 x 300. I2 is shown in original -size. - - - :DwRenderLayout ------------------- :DwPage ----------. - / \ | - ,----' `----. ,------ i1a:DwImage --+ - / \ | | - view1:GtkDwViewport view2:GtkDwPreview | ,---- i1b:DwImage --| - | | | | - ,------------------------------' | | ,-- i2: DwImage --' - | | | | - | ,-------------------------------------' | | - | | ,--------------------------------' | - | | | ,----' - | | | | - | V | V - | iba:Imgbuf | ibb:Imgbuf -- 30x30 - | | | V | ^ - | | +- 100x100 ,- 20x20 ,- 10x10 | | - | | | | ^ | ^ | | - | | `----------+----|---' | `--. ,--' - | | ,--------------' | | | - | | | ,------------------' | | - | | | | | | - | lca:ImgbufLSc lcb:ImgbufLSc - | (factor 1/10) (factor 1/10) - | \ / - | `-----------. ,-------------------' - | \ / - `------------------> scl:ImgbufGSc - (factor 1/10) diff --git a/doc/Makefile.am b/doc/Makefile.am index 8ade3d15..71c7c32d 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -11,8 +11,8 @@ EXTRA_DIST = \ dw-widget-sizes.doc \ dw-changes.doc \ dw-images-and-backgrounds.doc \ - dw-dw-out-of-flow.doc \ - dw-dw-out-of-flow-2.doc \ + dw-out-of-flow.doc \ + dw-out-of-flow-2.doc \ fltk-problems.doc \ rounding-errors.doc \ uml-legend.doc \ @@ -38,9 +38,7 @@ EXTRA_DIST = \ HtmlParser.txt \ IO.txt \ Images.txt \ - Imgbuf.txt \ NC_design.txt \ - Selection.txt \ Dpid.txt \ CCCwork.txt \ README \ diff --git a/doc/Selection.txt b/doc/Selection.txt deleted file mode 100644 index 7904bd94..00000000 --- a/doc/Selection.txt +++ /dev/null @@ -1,149 +0,0 @@ -Apr 2003, S.Geerken@ping.de -Last update: Dec 2004 - -========= -Selection -========= - -The selection module (selection.[ch]) handles selections, as well as -activation of links, which is closely related. - - -General Overview -================ - -The selection module defines a structure "Selection", which is -associated to GtkDwViewport, and so to a widget tree. The selection -state is controlled by "abstract events", which are sent by single -widgets by calling one of the following functions: - - a_Selection_button_press for button press events, - a_Selection_button_release for button release events, and - a_Selection_button_motion for motion events (with pressed mouse - button). - -The widget must construct simple iterators (DwIterator), which will be -transferred to extended iterators (DwExtIterator), see below for more -details. All event handling functions have the same signature, the -arguments in detail are: - - - DwIterator *it the iterator pointing on the item under - the mouse pointer, - - gint char_pos the exact (character) position within - the iterator, - - gint link if this item is associated with a link, - its number (see DwImage, section - "signals" for the meaning), otherwise - -1, - - GdkEventButton *event the event itself; only the button is - used, - - gboolean within_content TRUE, if there is some selectable - content unter the mouse cursor; if set - to FALSE, the "full screen" feature is - used on double click. - -In some cases, char_pos would be difficult to determine. E.g., when -the DwPage widget decides that the user is pointing on a position -_at_the_end_ of an image (DwImage), it constructs a simple iterator -pointing on this image widget. In a simple iterator, that fact that -the pointer is at the end, would be represented by char_pos == 1. But -when transferring this simple iterator into an extended iterator, this -simple iterator is discarded and instead the stack has an iterator -pointing to text at the top. As a result, only the first letter of the -ALT text would be copied. - -To avoid this problem, widgets should in this case pass SELECTION_EOW -(end of word) as char_pos, which is then automatically reduced to the -actual length of the extended(!) iterator. - -The return value is the same as in DwWidget event handling methods. -I.e., in most cases, they should simply return it. The events -"link_pressed", "link_released" and "link_clicked" (but not -"link_entered") are emitted by these functions, so that widgets which -let the selection module handle links, should only emit "link_entered" -for themselves. (See DwImage.txt for a description of this.) - - -Selection State -=============== - -Selection interferes with handling the activation of links, so the -latter is also handled by the selection module. Details are based on -following guidelines: - - 1. It should be simple to select links and to start selection in - links. The rule to distinguish between link activation and - selection is that the selection starts as soon as the user leaves - the link. (This is, IMO, a useful feature. Even after drag and - drop has been implemented in dillo, this should be somehow - preserved.) - - 2. The selection should stay as long as possible, i.e., the old - selection is only cleared when a new selection is started. - -The latter leads to a model with two states: the selection state and -the link handling state. - -The general selection works, for events not pointing on links, like -this (numbers in parantheses after the event denote the button, "n" -means arbitrary button): - - motion(1) - ,-----. - | | - press(1) on non-link V | - NONE -----------------------> SELECTING <----------------. - ^ | | - | | release(1) | - | | | press(1) - | no V yes | - `----------------------- Anything selected? --------> SELECTED - -The selected region is represented by two DwExtIterators. - -Links are handled by a different state machine: - - ,-----------------------------. - | | - | Switch to selection - | (SELECTING) for n == 1. - | ^ - | | no - | | yes - | Still the same link? --. - | ^ | - | | | - | | motion(n) | - V press(n) on links | | - NONE ---------------------> PRESSED(n) <-----' - ^ | - | | release(n) - | | - | V yes - | Still the same link? -----------------. - | | | - | | no V - | V Send "clicked" signal. - | Switch to selection | - | (SELECTED) for n == 1. | - | | | - |`----------------------------' | - | | - `----------------------------------------------------------' - -Switching to selection simply means that the selection state will -eventually be SELECTED/SELECTING, with the original and the actual -position making up the selection region. This happens for button 1, -events with buttons other than 1 do not affect selection at all. - - -TODO -==== - -* a_Selection_button_motion currently always assumes that button 1 has - been pressed (since otherwise it would not do anything). This should - be made a bit cleaner. - -* The selection should be cleared, when the user selects something - somewhere else (perhaps switched into "non-active" mode, as some - Gtk+ widgets do). -- cgit v1.2.3 From 1463c3936ce6a57352590b901c9dbd6bc2f2086d Mon Sep 17 00:00:00 2001 From: Sebastian Geerken Date: Mon, 1 Jun 2015 22:00:10 +0200 Subject: Split up user and developer documentation. --- Doxyfile | 4 +- devdoc/CCCwork.txt | 153 +++++++++ devdoc/Cache.txt | 166 +++++++++ devdoc/Dillo.txt | 96 ++++++ devdoc/Dpid.txt | 331 ++++++++++++++++++ devdoc/HtmlParser.txt | 124 +++++++ devdoc/IO.txt | 468 +++++++++++++++++++++++++ devdoc/Images.txt | 129 +++++++ devdoc/NC_design.txt | 127 +++++++ devdoc/README | 51 +++ devdoc/dw-changes.doc | 105 ++++++ devdoc/dw-example-screenshot.png | Bin 0 -> 2264 bytes devdoc/dw-floats-01.png | Bin 0 -> 3410 bytes devdoc/dw-grows.doc | 202 +++++++++++ devdoc/dw-images-and-backgrounds.doc | 235 +++++++++++++ devdoc/dw-layout-views.doc | 256 ++++++++++++++ devdoc/dw-layout-widgets.doc | 267 +++++++++++++++ devdoc/dw-line-breaking.doc | 470 ++++++++++++++++++++++++++ devdoc/dw-map.doc | 59 ++++ devdoc/dw-out-of-flow-2.doc | 69 ++++ devdoc/dw-out-of-flow-floats.doc | 121 +++++++ devdoc/dw-out-of-flow.doc | 214 ++++++++++++ devdoc/dw-overview.doc | 158 +++++++++ devdoc/dw-size-of-widget.png | Bin 0 -> 1749 bytes devdoc/dw-style-box-model.png | Bin 0 -> 3889 bytes devdoc/dw-style-length-absolute.png | Bin 0 -> 575 bytes devdoc/dw-style-length-percentage.png | Bin 0 -> 890 bytes devdoc/dw-style-length-relative.png | Bin 0 -> 868 bytes devdoc/dw-textblock-collapsing-spaces-1-1.png | Bin 0 -> 641 bytes devdoc/dw-textblock-collapsing-spaces-1-2.png | Bin 0 -> 521 bytes devdoc/dw-textblock-collapsing-spaces-2-1.png | Bin 0 -> 802 bytes devdoc/dw-textblock-collapsing-spaces-2-2.png | Bin 0 -> 586 bytes devdoc/dw-usage.doc | 375 ++++++++++++++++++++ devdoc/dw-viewport-with-scrollbar.png | Bin 0 -> 755 bytes devdoc/dw-viewport-without-scrollbar.png | Bin 0 -> 542 bytes devdoc/dw-widget-sizes.doc | 277 +++++++++++++++ devdoc/fltk-problems.doc | 180 ++++++++++ devdoc/index.doc | 48 +++ devdoc/lout.doc | 95 ++++++ devdoc/not-so-simple-container.png | Bin 0 -> 5738 bytes devdoc/rounding-errors.doc | 35 ++ devdoc/uml-legend.doc | 195 +++++++++++ doc/CCCwork.txt | 153 --------- doc/Cache.txt | 166 --------- doc/Dillo.txt | 96 ------ doc/Dpid.txt | 331 ------------------ doc/Dw.txt | 11 - doc/HtmlParser.txt | 124 ------- doc/IO.txt | 468 ------------------------- doc/Images.txt | 129 ------- doc/Makefile.am | 44 +-- doc/NC_design.txt | 127 ------- doc/README | 54 +-- doc/dw-changes.doc | 105 ------ doc/dw-example-screenshot.png | Bin 2264 -> 0 bytes doc/dw-floats-01.png | Bin 3410 -> 0 bytes doc/dw-grows.doc | 202 ----------- doc/dw-images-and-backgrounds.doc | 235 ------------- doc/dw-layout-views.doc | 256 -------------- doc/dw-layout-widgets.doc | 267 --------------- doc/dw-line-breaking.doc | 470 -------------------------- doc/dw-map.doc | 59 ---- doc/dw-out-of-flow-2.doc | 69 ---- doc/dw-out-of-flow-floats.doc | 121 ------- doc/dw-out-of-flow.doc | 214 ------------ doc/dw-overview.doc | 158 --------- doc/dw-size-of-widget.png | Bin 1749 -> 0 bytes doc/dw-style-box-model.png | Bin 3889 -> 0 bytes doc/dw-style-length-absolute.png | Bin 575 -> 0 bytes doc/dw-style-length-percentage.png | Bin 890 -> 0 bytes doc/dw-style-length-relative.png | Bin 868 -> 0 bytes doc/dw-textblock-collapsing-spaces-1-1.png | Bin 641 -> 0 bytes doc/dw-textblock-collapsing-spaces-1-2.png | Bin 521 -> 0 bytes doc/dw-textblock-collapsing-spaces-2-1.png | Bin 802 -> 0 bytes doc/dw-textblock-collapsing-spaces-2-2.png | Bin 586 -> 0 bytes doc/dw-usage.doc | 375 -------------------- doc/dw-viewport-with-scrollbar.png | Bin 755 -> 0 bytes doc/dw-viewport-without-scrollbar.png | Bin 542 -> 0 bytes doc/dw-widget-sizes.doc | 277 --------------- doc/fltk-problems.doc | 180 ---------- doc/index.doc | 48 --- doc/lout.doc | 95 ------ doc/not-so-simple-container.png | Bin 5738 -> 0 bytes doc/rounding-errors.doc | 35 -- doc/uml-legend.doc | 195 ----------- 85 files changed, 5015 insertions(+), 5059 deletions(-) create mode 100644 devdoc/CCCwork.txt create mode 100644 devdoc/Cache.txt create mode 100644 devdoc/Dillo.txt create mode 100644 devdoc/Dpid.txt create mode 100644 devdoc/HtmlParser.txt create mode 100644 devdoc/IO.txt create mode 100644 devdoc/Images.txt create mode 100644 devdoc/NC_design.txt create mode 100644 devdoc/README create mode 100644 devdoc/dw-changes.doc create mode 100644 devdoc/dw-example-screenshot.png create mode 100644 devdoc/dw-floats-01.png create mode 100644 devdoc/dw-grows.doc create mode 100644 devdoc/dw-images-and-backgrounds.doc create mode 100644 devdoc/dw-layout-views.doc create mode 100644 devdoc/dw-layout-widgets.doc create mode 100644 devdoc/dw-line-breaking.doc create mode 100644 devdoc/dw-map.doc create mode 100644 devdoc/dw-out-of-flow-2.doc create mode 100644 devdoc/dw-out-of-flow-floats.doc create mode 100644 devdoc/dw-out-of-flow.doc create mode 100644 devdoc/dw-overview.doc create mode 100644 devdoc/dw-size-of-widget.png create mode 100644 devdoc/dw-style-box-model.png create mode 100644 devdoc/dw-style-length-absolute.png create mode 100644 devdoc/dw-style-length-percentage.png create mode 100644 devdoc/dw-style-length-relative.png create mode 100644 devdoc/dw-textblock-collapsing-spaces-1-1.png create mode 100644 devdoc/dw-textblock-collapsing-spaces-1-2.png create mode 100644 devdoc/dw-textblock-collapsing-spaces-2-1.png create mode 100644 devdoc/dw-textblock-collapsing-spaces-2-2.png create mode 100644 devdoc/dw-usage.doc create mode 100644 devdoc/dw-viewport-with-scrollbar.png create mode 100644 devdoc/dw-viewport-without-scrollbar.png create mode 100644 devdoc/dw-widget-sizes.doc create mode 100644 devdoc/fltk-problems.doc create mode 100644 devdoc/index.doc create mode 100644 devdoc/lout.doc create mode 100644 devdoc/not-so-simple-container.png create mode 100644 devdoc/rounding-errors.doc create mode 100644 devdoc/uml-legend.doc delete mode 100644 doc/CCCwork.txt delete mode 100644 doc/Cache.txt delete mode 100644 doc/Dillo.txt delete mode 100644 doc/Dpid.txt delete mode 100644 doc/Dw.txt delete mode 100644 doc/HtmlParser.txt delete mode 100644 doc/IO.txt delete mode 100644 doc/Images.txt delete mode 100644 doc/NC_design.txt delete mode 100644 doc/dw-changes.doc delete mode 100644 doc/dw-example-screenshot.png delete mode 100644 doc/dw-floats-01.png delete mode 100644 doc/dw-grows.doc delete mode 100644 doc/dw-images-and-backgrounds.doc delete mode 100644 doc/dw-layout-views.doc delete mode 100644 doc/dw-layout-widgets.doc delete mode 100644 doc/dw-line-breaking.doc delete mode 100644 doc/dw-map.doc delete mode 100644 doc/dw-out-of-flow-2.doc delete mode 100644 doc/dw-out-of-flow-floats.doc delete mode 100644 doc/dw-out-of-flow.doc delete mode 100644 doc/dw-overview.doc delete mode 100644 doc/dw-size-of-widget.png delete mode 100644 doc/dw-style-box-model.png delete mode 100644 doc/dw-style-length-absolute.png delete mode 100644 doc/dw-style-length-percentage.png delete mode 100644 doc/dw-style-length-relative.png delete mode 100644 doc/dw-textblock-collapsing-spaces-1-1.png delete mode 100644 doc/dw-textblock-collapsing-spaces-1-2.png delete mode 100644 doc/dw-textblock-collapsing-spaces-2-1.png delete mode 100644 doc/dw-textblock-collapsing-spaces-2-2.png delete mode 100644 doc/dw-usage.doc delete mode 100644 doc/dw-viewport-with-scrollbar.png delete mode 100644 doc/dw-viewport-without-scrollbar.png delete mode 100644 doc/dw-widget-sizes.doc delete mode 100644 doc/fltk-problems.doc delete mode 100644 doc/index.doc delete mode 100644 doc/lout.doc delete mode 100644 doc/not-so-simple-container.png delete mode 100644 doc/rounding-errors.doc delete mode 100644 doc/uml-legend.doc (limited to 'doc') diff --git a/Doxyfile b/Doxyfile index df509910..68ffcea9 100644 --- a/Doxyfile +++ b/Doxyfile @@ -852,7 +852,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = doc +IMAGE_PATH = devdoc # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -1298,7 +1298,7 @@ QHP_NAMESPACE = # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_VIRTUAL_FOLDER = doc +QHP_VIRTUAL_FOLDER = devdoc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom diff --git a/devdoc/CCCwork.txt b/devdoc/CCCwork.txt new file mode 100644 index 00000000..1ea5d20e --- /dev/null +++ b/devdoc/CCCwork.txt @@ -0,0 +1,153 @@ +Last review: August 04, 2009 --jcid + + +---------------------------- +Internal working for the CCC +---------------------------- + + +HTTP protocol +------------- + + + Query: | + . + 1B --> 1B 1B --> 1B --> | -------------. + .----. .----. .----. . | +I |Capi| |http| | IO | | | + '----' '----' '----' . | + 1F <-- 1F 1F <-- 1F | V + . + | [Server] + Answer: . + + 2B --> 2B 2B --> 2B | | + .----. .----. .----. . | +II |Capi| |Dpi | | IO | | | + '----' '----' '----' . | + 2F <-- 2F 2F <-- 2F <-- | <------------' + . + | + +* a_Capi_open_url() builds both the Answer and Query chains at +once (Answer first then Query), to ensure a uniform structure +that avoids complexity (e.g. race conditions). + +* Http_get() sets a callback for the DNS hostname resolve. +Normally it comes later, but may also by issued immediately if +the hostname is cached. + +* The socket FD is passed by means of OpSend by the http module +once the remote IP is known and the socket is connected. + + + +Function calls for HTTP CCC +--------------------------- + + a_Capi_open_url + if (reload) + Capi OpStart 2B (answer) [Capi] --> [dpi] --> [IO] + Capi OpStart 1B (query) [Capi] --> [http] --> [IO] + Http_get + a_Cache_open_url + if URL_E2EReload -> prepare reload + if cached + client enqueue + delayed process queue + else + Cache_entry_add + client enqueue + + -//-> + a_Http_dns_cb + Http_connect_socket + OpSend FD, BCK + OpSend FD, FWD + Http_send_query + a_Http_make_query_str + OpSend, BCK + IO_submit + a_IOwatch_add_fd (DIO_WRITE, ...) + + + Note about 'web' structures. They're created using a_Web_new(). +The web.c module keeps a list of valid webs, so anytime you're +unsure of a weak reference to 'web', it can be checked with +a_Web_valid(web). + + + +------------ +Dpi protocol +------------ + + + Query: | + . + 1B --> 1B 1B --> 1B --> | -------------. + .----. .----. .----. . | +I |Capi| |Dpi | | IO | | | + '----' '----' '----' . | + 1F <-- 1F 1F <-- 1F | V + . + | [Server] + . + Answer (same as HTTP): | | + . | + 2B --> 2B 2B --> 2B | | + .----. .----. .----. . | +II |Capi| |Dpi | | IO | | | + '----' '----' '----' . | + 2F <-- 2F 2F <-- 2F <-- | <------------' + . + | + + +CCC Construction: + + a_Capi_open_url() calls a_Capi_dpi_send_cmd() when the URL +belongs to a dpi and it is not cached. + + a_Capi_dpi_send_cmd() builds both the Answer and Query chains +at once (Answer first then Query), in the same way as HTTP does. +Note that the answer chain is the same for both, and the query +chain only differs in the module in the middle ([http] or [dpi]). + + +Function calls for DPI CCC +-------------------------- + + a_Capi_open_url + a_Capi_dpi_send_cmd + Capi OpStart 2B (answer) [Capi] --> [dpi] --> [IO] + Capi OpStart 1B (query) [Capi] --> [http] --> [IO] + a_Cache_open_url + [...] + + +Normal termination: + + When the dpi server is done, it closes the FD, and OpEnd flows +from IO to Capi (answer branch). When in Capi, capi propagates +OpEnd to the query branch. + +Abnormal termination: + + The transfer may be aborted by a_Capi_conn_abort_by_url(). The +OpAbort is not yet standardized and has an ad-hoc implementation. +One idea is to have OpAbort always propagate BCK and then FWD and +to jump into the other chain when it gets to [Capi]. + + +Debugging CCC +------------- + + A simple way to "look" inside it, is to "#define VERBOSE 1" in +chain.c, and then to follow its work with a printed copy of the +diagrams in this document. + + Each new data request generates a CCC, so if you want to debug, +it's good to refine the testcase to the minimum possible number +of connections. + diff --git a/devdoc/Cache.txt b/devdoc/Cache.txt new file mode 100644 index 00000000..4e885df2 --- /dev/null +++ b/devdoc/Cache.txt @@ -0,0 +1,166 @@ + June 2000, --Jcid + Last update: Jul 09 + + ------- + CACHE + ------- + + The cache module is the main abstraction layer between +rendering and networking. + + The capi module acts as a discriminating wrapper which either +calls the cache or the dpi routines depending on the type of +request. + + Every URL must be requested using a_Capi_open_url, which +sends the request to the cache if the data is cached, to dillo's +http module for http: URLs, and through dillo's DPI system for +other URLs. + + Here we'll document non dpi requests. + + + ---------------- + CACHE PHILOSOPHY + ---------------- + + Dillo's cache is very simple; every single resource that's +retrieved (URL) is kept in memory. NOTHING is saved to disk. +This is mainly for three reasons: + + - Dillo encourages personal privacy and it assures there'll be +no recorded tracks of the sites you visited. + + - The Network is full of intermediate transparent proxys that +serve as caches. + + - If you still want to have cached stuff, you can install an +external cache server (such as WWWOFFLE), and benefit from it. + + + --------------- + CACHE STRUCTURE + --------------- + + Currently, dillo's cache code is spread in different sources: +mainly in cache.[ch], dicache.[ch] and it uses some other +functions from mime.c and web.cc. + + Cache.c is the principal source, and it also is the one +responsible for processing cache-clients (held in a queue). +Dicache.c is the interface to the decompressed RGB representations +of currently-displayed images held in DW's imgbuf. + + mime.c and web.cc are used for secondary tasks such as +assigning the right "viewer" or "decoder" for a given URL. + + +---------------- +A bit of history +---------------- + + Some time ago, the cache functions, URL retrieval and +external protocols were a whole mess of mixed code, and it was +getting REALLY hard to fix, improve or extend the functionality. +The main idea of this "layering" is to make code-portions as +independent as possible so they can be understood, fixed, +improved or replaced without affecting the rest of the browser. + + An interesting part of the process is that, as resources are +retrieved, the client (dillo in this case) doesn't know the +Content-Type of the resource at request-time. It only becomes known +when the resource header is retrieved (think of http). This +happens when the cache has control, so the cache sets the +proper viewer for it (unless the Callback function was already +specified with the URL request). + + You'll find a good example in http.c. + + Note: All resources received by the cache have HTTP-style headers. + The file/data/ftp DPIs generate these headers when sending their + non-HTTP resources. Most importantly, a Content-Type header is + generated based on file extension or file contents. + + +------------- +Cache clients +------------- + + Cache clients MUST use a_Capi_open_url to request an URL. The +client structure and the callback-function prototype are defined, +in cache.h, as follows: + +struct _CacheClient { + int Key; /* Primary Key for this client */ + const DilloUrl *Url; /* Pointer to a cache entry Url */ + int Version; /* Dicache version of this Url (0 if not used) */ + void *Buf; /* Pointer to cache-data */ + uint_t BufSize; /* Valid size of cache-data */ + CA_Callback_t Callback; /* Client function */ + void *CbData; /* Client function data */ + void *Web; /* Pointer to the Web structure of our client */ +}; + +typedef void (*CA_Callback_t)(int Op, CacheClient_t *Client); + + + Notes: + + * Op is the operation that the callback is asked to perform + by the cache. { CA_Send | CA_Close | CA_Abort }. + + * Client: The Client structure that originated the request. + + + +-------------------------- +Key-functions descriptions +-------------------------- + +································································ +int a_Cache_open_url(void *Web, CA_Callback_t Call, void *CbData) + + if Web->url is not cached + Create a cache-entry for that URL + Send client to cache queue + else + Feed our client with cached data + +································································ + +---------------------- +Redirections mechanism + (HTTP 30x answers) +---------------------- + + This is by no means complete. It's a work in progress. + + Whenever an URL is served under an HTTP 30x header, its cache +entry is flagged with 'CA_Redirect'. If it's a 301 answer, the +additional 'CA_ForceRedirect' flag is also set, if it's a 302 +answer, 'CA_TempRedirect' is also set (this happens inside the +Cache_parse_header() function). + + Later on, in Cache_process_queue(), when the entry is flagged +with 'CA_Redirect' Cache_redirect() is called. + + + + + + + +----------- +Notes +----------- + + The whole process is asynchronous and very complex. I'll try +to document it in more detail later (source is commented). + Currently I have a drawing to understand it; hope the ASCII +translation serves the same as the original. + If you're planning to understand the cache process thoroughly, +write me a note and I will assign higher priority to further +improvement of this doc. + Hope this helps! + + diff --git a/devdoc/Dillo.txt b/devdoc/Dillo.txt new file mode 100644 index 00000000..a63c9588 --- /dev/null +++ b/devdoc/Dillo.txt @@ -0,0 +1,96 @@ +"Eliminate the guesswork and quality goes up." + + + ------- + DILLO + ------- + + These notes are written with a view to make it less hard, not +easier yet ;), to get into Dillo development. + When I first got into it, I was totally unaware of the browser +internals. Now that I've made my way deep into the core of it, +(we rewrote it 90% and modified the rest), is time to write some +documentation, just to make a less steep learning curve for new +developers. + + --Jcid + + + + -------- + OVERVIEW + -------- + + Dillo can be viewed as the sum of five main parts: + + 1.- Dillo Widget: A custom widget, FLTK-based, that holds the +necessary data structures and mechanisms for graphical rendering. +(Described in Dw*.txt, dw*.c files among the sources.) + + 2.- Dillo Cache: Integrated with a signal driven Input/Output +engine that handles file descriptor activity, the cache acts as +the main abstraction layer between rendering and networking. + Every URL, whether cached or not, must be retrieved using +a_Capi_open_url (Described briefly in Cache.txt, source +contained in capi.c). + IO is described in IO.txt (recommended), source in src/IO/. + + 3.- The HTML parser: A streamed parser that joins the Dillo +Widget and the Cache functionality to make browsing possible +(Described in HtmlParser.txt, source mainly inside html.cc). + + 4.- Image processing code: The part that handles image +retrieval, decoding, caching and displaying. (Described in +Images.txt. Sources: image.c, dw/image.cc, dicache.c, gif.c, +jpeg.c and png.c) + + 5.- The dpi framework: a gateway to interface the browser with +external programs (Example: the bookmarks server plugin). +Dpi spec: http://www.dillo.org/dpi1.html + + + ------------------------- + HOW IS THE PAGE RENDERED? + ------------------------- + +(A short description of the internal function calling process) + + When the user requests a new URL, a_UIcmd_open_url +is queried to do the job; it calls a_Nav_push (The highest level +URL dispatcher); a_Nav_push updates current browsing history and +calls Nav_open_url. Nav_open_url closes all open connections by +calling a_Bw_stop_clients, and then calls +a_Capi_open_url which calls a_Cache_open_url (or the dpi module if +this gateway is used). + + If Cache_entry_search hits (due to a cached url :), the client is +fed with cached data, but if the URL isn't cached yet, a new CCC +(Concomitant Control Chain) is created and committed to fetch the +URL. + + The next CCC link is dynamically assigned by examining the +URL's protocol. It can be a_Http_ccc or a_Dpi_ccc. + + If we have an HTTP URL, a_Http_ccc will succeed, and the http +module will be linked; it will create the proper HTTP query and +link the IO module to submit and deliver the answer. + + Note that as the Content-Type of the URL is not always known +in advance, the answering branch decides where to dispatch it to +upon HTTP header arrival. + + + What happens then? + + Well, the html parser gets fed, and proper functions are +called for each tag (to parse and call the appropriate methods) +and the whole page is contructed in a streamed way. + Somewhere in the middle of it, resize and repaint functions +are activated and idle functions draw to screen what has been +processed. + + (The process for images is described in Images.txt) + + + + diff --git a/devdoc/Dpid.txt b/devdoc/Dpid.txt new file mode 100644 index 00000000..6c418f57 --- /dev/null +++ b/devdoc/Dpid.txt @@ -0,0 +1,331 @@ +Aug 2003, Jorge Arellano Cid, + Ferdi Franceschini -- +Last update: Nov 2009 + + + ------ + dpid + ------ + +------------- +Nomenclature: +------------- + + dpi: + generic term referring to dillo's plugin system (version1). + + dpi1: + specific term for dillo's plugin spec version 1. + at: http://www.dillo.org/dpi1.html + + dpi program: + any plugin program itself. + + dpi framework: + the code base inside and outside dillo that makes dpi1 + working possible (it doesn't include dpi programs). + + dpip: + dillo plugin protocol. The HTML/XML like set of command tags + and information that goes inside the communication sockets. + Note: not yet fully defined, but functional. + Note2: it was designed to be extensible. + + dpid: + dillo plugin daemon. + + server plugin: + A plugin that is capable of accepting connections on a socket. Dpid will + never run more than one instance of a server plugin at a time. + + filter plugin: + A dpi program that reads from stdin and writes to stdout, and that + exits after its task is done (they don't remain as server plugins). + Warning, dpid will run multiple instances of filter plugins if requested. + +----------- +About dpid: +----------- + + * dpid is a program which manages dpi connections. + * dpid is a daemon that serves dillo using IDS sockets. + * dpid launches dpi programs and arranges socket communication + between the dpi program and dillo. + + The concept and motivation is similar to that of inetd. The +plugin manager (dpid) listens for a service request on a socket +and returns the socket/port pair of a plugin that handles the +service. It also watches sockets of inactive plugins and starts +them when a connection is requested. + + +----------------------------------------------------------- +What's the problem with managing dpi programs inside dillo? +----------------------------------------------------------- + + That's the other way to handle it, but it started to show some +problems (briefly outlined here): + + * When having two or more running instances of Dillo, one + should prevail, and take control of dpi managing (but all + dillos carry the managing code). + * If the managing-dillo exits, it must pass control to another + instance, or leave it void if there's no other dillo running! + * The need to synchronize all the running instances of + dillo arises. + * If the controlling instance finishes and quits, all the + dpi-program PIDs are lost. + * Terminating hanged dpis is hard if it's not done with signals + (PIDs) + * Forks can be expensive (Dillo had to fork its dpis). + * When a managing dillo exits, the new one is no longer the + parent of the forked dpis. + * If Unix domain sockets for the dpis were to be named + randomly, it gets very hard to recover their names if the + controlling instance of dillo exits and another must "take + over" the managing. + * It increments dillo's core size. + * If dillo hangs/crashes, dpi activity is lost (e.g. downloads) + * ... + + That's why the managing daemon scheme was chosen. + + +---------------------- +What does dpid handle? +---------------------- + + It solves all the above mentioned shortcomings and also can do: + + * Multiple dillos: + dpid can communicate and serve more than one instance + of dillo. + + * Multiple dillo windows: + two or more windows of the same dillo instance accessing dpis + at the same time. + + * Different implementations of the same service + dpi programs ("dpis") are just an implementation of a + service. There's no problem in implementing a different one + for the same service (e.g. downloads). + + * Upgrading a service: + to a new version or implementation without requiring + patching dillo's core or even bringing down the dpid. + + + And finally, being aware that this design can support the +following functions is very helpful: + + SCHEME Example + ------------------------------------------------------------ + * "one demand/one response" man, preferences, ... + * "resident while working" downloads, mp3, ... + * "resident until exit request" bookmarks, ... + + * "one client only" cd burner, ... + * "one client per instance" man, ... + * "multiple clients/one instance" downloads, cookies ... + + +-------- +Features +-------- + * Dpi programs go in: "EPREFIX/dillo/dpi" or "~/.dillo/dpi". The binaries + are named .dpi as "bookmarks.dpi" and .filter.dpi as in + "hello.filter.dpi". The ".filter" plugins simply read from stdin + and write to stdout. + * Register/update/remove dpis from list of available dpis when a + 'register_all' command is received. + * dpid terminates when it receives a 'DpiBye' command. + * dpis can be terminated with a 'DpiBye' command. + * dpidc control program for dpid, currently allows register and stop. + + +----- +todo: +----- + + These features are already designed, waiting for implementation: + + * dpidc remove // May be not necessary after all... + + +----------------- +How does it work? +----------------- + +o on startup dpid reads dpidrc for the path to the dpi directory + (usually EPREFIX/lib/dillo/dpi). ~/.dillo/dpi is scanned first. + +o both directories are scanned for the list of available plugins. + ~/.dillo/dpi overrides system-wide dpis. + +o next it creates internet domain sockets for the available plugins and + then listens for service requests on its own socket, + and for connections to the sockets of inactive plugins. + +o dpid returns the port of a plugin's socket when a client (dillo) + requests a service. + +o if the requested plugin is a 'server' then + 1) dpid stops watching the socket for activity + 2) forks and starts the plugin + 3) resumes watching the socket when the plugin exits + +o if the requested plugin is a 'filter' then + 1) dpid accepts the connection + 2) maps the socket fd to stdin/stdout (with dup2) + 3) forks and starts the plugin + 4) continues to watch the socket for new connections + + + + +--------------------------- +dpi service process diagram +--------------------------- + + These drawings should be worth a thousand words! :) + + +(I) + .--- s1 s2 s3 ... sn + | + [dpid] [dillo] + | + '--- srs + + The dpid is running listening on several sockets. + + +(II) + .--- s1 s2 s3 ... sn + | + [dpid] [dillo] + | | + '--- srs ------------------' + + dillo needs a service so it connects to the service request + socket of the dpid (srs) and asks for the socket name of the + required plugin (using dpip). + + +(III) + .--- s1 s2 s3 ... sn + | | + [dpid] | [dillo] + | | | + '--- srs '---------------' + + then it connects to that socket (s3, still serviced by dpid!) + + +(IV) + .--- s1 s2 s3 ... sn + | | + .[dpid] | [dillo] + . | | | + . '--- srs '---------------' + . + .............[dpi program] + + when s3 has activity (incoming data), dpid forks the dpi + program for it... + + +(V) + .--- s1 s2 (s3) ... sn + | + [dpid] [dillo] + | | + '--- srs .---------------' + | + [dpi program] + + ... and lets it "to take over" the socket. + + Once there's a socket channel for dpi and dillo, the whole +communication process takes place until the task is done. When +the dpi program exits, dpid resumes listening on the socket (s3). + + +-------------------------------- +So, how do I make my own plugin? +-------------------------------- + + Maybe the simplest way to get started is to understand a few +concepts and then to use the hands-on method by using/modifying +the hello dpi. It's designed as an example to get developers +started. + + --------- + Concepts: + --------- + + * Dillo plugins work by communicating two processes: dillo + and the dpi. + * The underlying protocol (DPIP) has a uniform API which is + powerful enough for both blocking and nonblocking IO, and + filter or server dpis. + * The simplest example is one-request one-answer (for example + dillo asks for a URL and the dpi sends it). You'll find + this and more complex examples in hello.c + + First, you should get familiar with the hello dpi as a user: + + $dillo dpi:/hello/ + + Once you've played enough with it, start reading the well +commented code in hello.c and start making changes! + + + --------------- + Debugging a dpi + --------------- + + The simplest way is to add printf-like feedback using the MSG* +macros. You can start the dpid by hand on a terminal to force +messages to go there. Filter dpis use sdterr and server dpis +stdout. + + Sometimes more complex dpis need more than MSG*. In this case +you can use gdb like this. + + 1.- Add an sleep(20) statement just after the dpi starts. + 2.- Start dillo and issue a request for your dpi. This will + get your dpi started. + 3.- Standing in the dpi source directory: + ps aux|grep dpi + 4.- Take note of the dpi's PID and start gdb, then: + (gdb) attach + 5.- Continue from there... + + + ------------ + Final Notes: + ------------ + + 1.- If you already understand the hello dpi and want to try +something more advanced: + + * bookmarks.c is a good example of a blocking server + * file.c is an advanced example of a server handling multiple + non-blocking connections with select(). + + 2.- Multiple instances of a filter plugin may be run +concurrently, this could be a problem if your plugin records data +in a file, however it is safe if you simply write to stdout. +Alternatively you could write a 'server' plugin instead as they +are guaranteed not to run concurrently. + + 3.- The hardest part is to try to modify the dpi framework code +inside dillo; you have been warned! It already supports a lot of +functionality, but if you need to do some very custom stuff, try +extending the "chat" command, or asking in dillo-dev. + + + + >>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< + diff --git a/devdoc/HtmlParser.txt b/devdoc/HtmlParser.txt new file mode 100644 index 00000000..2eb8be63 --- /dev/null +++ b/devdoc/HtmlParser.txt @@ -0,0 +1,124 @@ + October 2001, --Jcid + Last update: Jul 2009 + + --------------- + THE HTML PARSER + --------------- + + + Dillo's parser is more than just a HTML parser, it does XHTML +and plain text also. It has parsing 'modes' that define its +behaviour while working: + + typedef enum { + DILLO_HTML_PARSE_MODE_INIT = 0, + DILLO_HTML_PARSE_MODE_STASH, + DILLO_HTML_PARSE_MODE_STASH_AND_BODY, + DILLO_HTML_PARSE_MODE_BODY, + DILLO_HTML_PARSE_MODE_VERBATIM, + DILLO_HTML_PARSE_MODE_PRE + } DilloHtmlParseMode; + + + The parser works upon a token-grained basis, i.e., the data +stream is parsed into tokens and the parser is fed with them. The +process is simple: whenever the cache has new data, it is +passed to Html_write, which groups data into tokens and calls the +appropriate functions for the token type (tag, space, or word). + + Note: when in DILLO_HTML_PARSE_MODE_VERBATIM, the parser +doesn't try to split the data stream into tokens anymore; it +simply collects until the closing tag. + +------ +TOKENS +------ + + * A chunk of WHITE SPACE --> Html_process_space + + + * TAG --> Html_process_tag + + The tag-start is defined by two adjacent characters: + + first : '<' + second: ALPHA | '/' | '!' | '?' + + Note: comments are discarded ( ) + + + The tag's end is not as easy to find, nor to deal with!: + + 1) The HTML 4.01 sec. 3.2.2 states that "Attribute/value + pairs appear before the final '>' of an element's start tag", + but it doesn't define how to discriminate the "final" '>'. + + 2) '<' and '>' should be escaped as '<' and '>' inside + attribute values. + + 3) The XML SPEC for XHTML states: + AttrValue ::== '"' ([^<&"] | Reference)* '"' | + "'" ([^<&'] | Reference)* "'" + + Current parser honors the XML SPEC. + + As it's a common mistake for human authors to mistype or + forget one of the quote marks of an attribute value; the + parser solves the problem with a look-ahead technique + (otherwise the parser could skip significant amounts of + properly-written HTML). + + + + * WORD --> Html_process_word + + A word is anything that doesn't start with SPACE, that's + outside of a tag, up to the first SPACE or tag start. + + SPACE = ' ' | \n | \r | \t | \f | \v + + +----------------- +THE PARSING STACK +----------------- + + The parsing state of the document is kept in a stack: + + class DilloHtml { + [...] + lout::misc::SimpleVector *stack; + [...] + }; + + struct _DilloHtmlState { + CssPropertyList *table_cell_props; + DilloHtmlParseMode parse_mode; + DilloHtmlTableMode table_mode; + bool cell_text_align_set; + DilloHtmlListMode list_type; + int list_number; + + /* TagInfo index for the tag that's being processed */ + int tag_idx; + + dw::core::Widget *textblock, *table; + + /* This is used to align list items (especially in enumerated lists) */ + dw::core::Widget *ref_list_item; + + /* This is used for list items etc; if it is set to TRUE, breaks + have to be "handed over" (see Html_add_indented and + Html_eventually_pop_dw). */ + bool hand_over_break; + }; + + Basically, when a TAG is processed, a new state is pushed into +the 'stack' and its 'style' is set to reflect the desired +appearance (details in DwStyle.txt). + + That way, when a word is processed later (added to the Dw), all +the information is within the top state. + + Closing TAGs just pop the stack. + + diff --git a/devdoc/IO.txt b/devdoc/IO.txt new file mode 100644 index 00000000..cd62a4f5 --- /dev/null +++ b/devdoc/IO.txt @@ -0,0 +1,468 @@ + +This is the updated base of a paper I wrote with Horst. +It provides a good introduction to Dillo's internals. +(Highly recommended if you plan to patch or develop in Dillo) + +It may not be exactly accurate (it's quite old), but it explains +the theory behind in some detail, so it's more than recommended +reading material. +--Jcid + + +----------------------------------------------------- +Parallel network programming of the Dillo web browser +----------------------------------------------------- + + Jorge Arellano-Cid + Horst H. von Brand + + +-------- +Abstract +-------- + + Network programs face several delay sources when sending or +retrieving data. This is particularly problematic in programs +which interact directly with the user, most notably web browsers. +We present a hybrid approach using threads communicated through +pipes and signal driven I/O, which allows a non-blocking main +thread and overlapping waiting times. + + +------------ +Introduction +------------ + + The Dillo project didn't start from scratch but mainly working +on the code base of gzilla (a light web browser written by Raph +Levien). As the project went by, the code of the whole source was +standardized, and the networking engine was replaced with a new, +faster design. Later, the parser was changed, the streamed +handling of data and its error control was put under the control +of the CCC (Concomitant Control Chain), and the old widget system +was replaced with a new one (Dw). The source code is currently +regarded as "very stable beta", and is available at +. Dillo is a project licensed under the GNU +General Public License. + + This paper covers basic design aspects of the hybrid approach +that the Dillo web browser uses to solve several latency +problems. After introducing the main delay-sources, the main +points of the hybrid design will be addressed. + + +------------- +Delay sources +------------- + + Network programs face several delay-sources while sending or +retrieving data. In the particular case of a web browser, they +are found in: + + DNS querying: + The time required to solve a name. + + Initiating the TCP connection: + The three way handshake of the TCP protocol. + + Sending the query: + The time spent uploading queries to the remote server. + + Retrieving data: + The time spent expecting and receiving the query answer. + + Closing the TCP connection: + The four packet-sending closing sequence of the TCP protocol. + + In a WAN context, every single item of this list has an +associated delay that is non deterministic and often measured in +seconds. If we add several connections per browsed page (each one +requiring at least the 4 last steps), the total latency can be +considerable. + + +----------------------------------- +The traditional (blocking) approach +----------------------------------- + + The main problems with the blocking approach are: + + When issuing an operation that can't be completed + immediately, the process is put to sleep waiting for + completion, and the program doesn't do any other + processing in the meantime. + + When waiting for a specific socket operation to complete, + packets that belong to other connections may be arriving, + and have to wait for service. + + Web browsers handle many small transactions, + if waiting times are not overlapped + the latency perceived by the user can be very annoying. + + If the user interface is just put to sleep during network + operations, the program becomes unresponsive, confusing + and perhaps alarming the user. + + Not overlapping waiting times and processing makes + graphical rendering (which is arguably the central function + of a browser) unnecessarily slow. + + +--------------------- +Dillo's hybrid design +--------------------- + + Dillo uses threads and signal driven I/O extensively to +overlap waiting times and computation. Handling the user +interface in a thread that never blocks gives a good interactive +``feel.'' The use of GTK+, a sophisticated widget framework for +graphical user interfaces, helped very much to accomplish this +goal. All the interface, rendering and I/O engine was built upon +its facilities. + + The design is said to be ``hybrid'' because it uses threads +for DNS querying and reading local files, and signal driven I/O +for TCP connections. The threaded DNS scheme is potentially +concurrent (this depends on underlying hardware), while the I/O +handling (both local files and remote connections) is +definitively parallel. + + To simplify the structure of the browser, local files are +encapsulated into HTTP streams and presented to the rest of the +browser as such, in exactly the same way a remote connection is +handled. To create this illusion, a thread is launched. This +thread opens a pipe to the browser, it then synthesizes an +appropriate HTTP header, sends it together with the file to the +browser proper. In this way, all the browser sees is a handle, +the data on it can come from a remote connection or from a local +file. + + To handle a remote connection is more complex. In this case, +the browser asks the cache manager for the URL. The name in the +URL has to be resolved through the DNS engine, a socket TCP +connection must be established, the HTTP request has to be sent, +and finally the result retrieved. Each of the steps mentioned +could give rise to errors, which have to be handled and somehow +communicated to the rest of the program. For performance reasons, +it is critical that responses are cached locally, so the remote +connection doesn't directly hand over the data to the browser; +the response is passed to the cache manager which then relays it +to the rest of the browser. The DNS engine caches DNS responses, +and either answers them from the cache or by querying the DNS. +Querying is done in a separate thread, so that the rest of the +browser isn't blocked by long waits here. + + The activities mentioned do not happen strictly in the order +stated above. It is even possible that several URLs are being +handled at the same time, in order to overlap waiting and +downloading. The functions called directly from the user +interface have to return quickly to maintain interactive +response. Sometimes they return connection handlers that haven't +been completely set up yet. As stated, I/O is signal-driven, when +one of the descriptors is ready for data transfer (reading or +writing), it wakes up the I/O engine. + + Data transfer between threads inside the browser is handled by +pipes, shared memory is little used. This almost obviates the +need for explicit synchronization, which is one of the main areas +of complexity and bugs in concurrent programs. Dillo handles its +threads in a way that its developers can think of it as running +on a single thread of control. This is accomplished by making the +DNS engine call-backs happen within the main thread, and by +isolating file loading with pipes. + + Using threads in this way has three big advantages: + + The browser doesn't block when one of its child threads + blocks. In particular, the user interface is responsive + even while resolving a name or downloading a file. + + Developers don't need to deal with complex concurrent + concerns. Concurrency is hard to handle, and few developers + are adept at this. This gives access a much larger pool of + potential developers, something which can be critical + in an open-source development project. + + By making the code mostly sequential, debugging the code + with traditional tools like gdb is possible. Debugging + parallel programs is very hard, and appropriate tools are + hard to come by. + + Because of simplicity and portability concerns, DNS querying +is done in a separate thread. The standard C library doesn't +provide a function for making DNS queries that don't block. The +alternative is to implement a new, custom DNS querying function +that doesn't block. This is certainly a complex task, integrating +this mechanism into the thread structure of the program is much +simpler. + + Using a thread and a pipe to read a local file adds a +buffering step to the process (and a certain latency), but it has +a couple of significative advantages: + + By handling local files in the same way as remote + connections, a significant amount of code is reused. + + A preprocessing step of the file data can be added easily, + if needed. In fact, the file is encapsulated into an HTTP + data stream. + + +----------- +DNS queries +----------- + + Dillo handles DNS queries with threads, letting a child thread +wait until the DNS server answers the request. When the answer +arrives, a call-back function is called, and the program resumes +what it was doing at DNS-request time. The interesting thing is +that the call-back happens in the main thread, while the child +thread simply exits when done. This is implemented through a +server-channel design. + + +The server channel +------------------ + + There is one thread for each channel, and each channel can +have multiple clients. When the program requests an IP address, +the server first looks for a cached match; if it hits, the client +call-back is invoked immediately, but if not, the client is put +into a queue, a thread is spawned to query the DNS, and a GTK+ +idle client is set to poll the channel 5~times per second for +completion, and when it finally succeeds, every client of that +channel is serviced. + + This scheme allows all the further processing to continue on +the same thread it began: the main thread. + + +------------------------ +Handling TCP connections +------------------------ + + Establishing a TCP connection requires the well known +three-way handshake packet-sending sequence. Depending on network +traffic and several other issues, significant delay can occur at +this phase. + + Dillo handles the connection by a non blocking socket scheme. +Basically, a socket file descriptor of AF_INET type is requested +and set to non-blocking I/O. When the DNS server has resolved the +name, the socket connection process begins by calling connect(2); + {We use the Unix convention of identifying the manual section + where the concept is described, in this case + section 2 (system calls).} +which returns immediately with an EINPROGRESS error. + + After the connection reaches the EINPROGRESS ``state,'' the +socket waits in background until connection succeeds (or fails), +when that happens, a callback function is awaked to perform the +following steps: set the I/O engine to send the query and expect +its answer (both in background). + + The advantage of this scheme is that every required step is +quickly done without blocking the browser. Finally, the socket +will generate a signal whenever I/O is possible. + + +---------------- +Handling queries +---------------- + + In the case of a HTTP URL, queries typically translate into a +short transmission (the HTTP query) and a lengthy retrieval +process. Queries are not always short though, specially when +requesting forms (all the form data is attached within the +query), and also when requesting CGI programs. + + Regardless of query length, query sending is handled in +background. The thread that was initiated at TCP connecting time +has all the transmission framework already set up; at this point, +packet sending is just a matter of waiting for the +write signal (G_IO_OUT) to come and then sending the data. When +the socket gets ready for transmission, the data is sent using +IO_write. + + +-------------- +Receiving data +-------------- + + Although conceptually similar to sending queries, retrieving +data is very different as the data received can easily exceed the +size of the query by many orders of magnitude (for example when +downloading images or files). This is one of the main sources of +latency, the retrieval can take several seconds or even minutes +when downloading large files. + + The data retrieving process for a single file, that began by +setting up the expecting framework at TCP connecting time, simply +waits for the read signal (G_IO_IN). When it happens, the +low-level I/O engine gets called, the data is read into +pre-allocated buffers and the appropriate call-backs are +performed. Technically, whenever a G_IO_IN event is generated, +data is received from the socket file descriptor, by using the +IO_read function. This iterative process finishes upon EOF (or on +an error condition). + + +---------------------- +Closing the connection +---------------------- + + Closing a TCP connection requires four data segments, not an +impressive amount but twice the round trip time, which can be +substantial. When data retrieval finishes, socket closing is +triggered. There's nothing but a IO_close_fd call on the socket's +file descriptor. This process was originally designed to split +the four segment close into two partial closes, one when query +sending is done and the other when all data is in. This scheme is +not currently used because the write close also stops the reading +part. + + +The low-level I/O engine +------------------------ + + Dillo I/O is carried out in the background. This is achieved +by using low level file descriptors and signals. Anytime a file +descriptor shows activity, a signal is raised and the signal +handler takes care of the I/O. + + The low-level I/O engine ("I/O engine" from here on) was +designed as an internal abstraction layer for background file +descriptor activity. It is intended to be used by the cache +module only; higher level routines should ask the cache for its +URLs. Every operation that is meant to be carried out in +background should be handled by the I/O engine. In the case of +TCP sockets, they are created and submitted to the I/O engine for +any further processing. + + The submitting process (client) must fill a request structure +and let the I/O engine handle the file descriptor activity, until +it receives a call-back for finally processing the data. This is +better understood by examining the request structure: + + typedef struct { + gint Key; /* Primary Key (for klist) */ + gint Op; /* IORead | IOWrite | IOWrites */ + gint FD; /* Current File Descriptor */ + gint Flags; /* Flag array */ + glong Status; /* Number of bytes read, or -errno code */ + + void *Buf; /* Buffer place */ + size_t BufSize; /* Buffer length */ + void *BufStart; /* PRIVATE: only used inside IO.c! */ + + void *ExtData; /* External data reference (not used by IO.c) */ + void *Info; /* CCC Info structure for this IO */ + GIOChannel *GioCh; /* IO channel */ + guint watch_id; /* glib's event source id */ + } IOData_t; + + To request an I/O operation, this structure must be filled and +passed to the I/O engine. + + 'Op' and 'Buf' and 'BufSize' MUST be provided. + + 'ExtData' MAY be provided. + + 'Status', 'FD' and 'GioCh' are set by I/O engine internal +routines. + + When there is new data in the file descriptor, 'IO_callback' +gets called (by glib). Only after the I/O engine finishes +processing the data are the upper layers notified. + + +The I/O engine transfer buffer +------------------------------ + + The 'Buf' and 'BufSize' fields of the request structure +provide the transfer buffer for each operation. This buffer must +be set by the client (to increase performance by avoiding copying +data). + + On reads, the client specifies the amount and where to place +the retrieved data; on writes, it specifies the amount and source +of the data segment that is to be sent. Although this scheme +increases complexity, it has proven very fast and powerful. For +instance, when the size of a document is known in advance, a +buffer for all the data can be allocated at once, eliminating the +need for multiple memory reallocations. Even more, if the size is +known and the data transfer is taking the form of multiple small +chunks of data, the client only needs to update 'Buf' and +BufSize' to point to the next byte in its large preallocated +reception buffer (by adding the chunk size to 'Buf'). On the +other hand, if the size of the transfer isn't known in advance, +the reception buffer can remain untouched until the connection +closes, but the client must then accomplish the usual buffer +copying and reallocation. + + The I/O engine also lets the client specify a full length +transfer buffer when sending data. It doesn't matter (from the +client's point of view) if the data fits in a single packet or +not, it's the I/O engine's job to divide it into smaller chunks +if needed and to perform the operation accordingly. + + +------------------------------------------ +Handling multiple simultaneous connections +------------------------------------------ + + The previous sections describe the internal work for a single +connection, the I/O engine handles several of them in parallel. +This is the normal downloading behavior of a web page. Normally, +after retrieving the main document (HTML code), several +references to other files (typically images) and sometimes even +to other sites (mostly advertising today) are found inside the +page. In order to parse and complete the page rendering, those +other documents must be fetched and displayed, so it is not +uncommon to have multiple downloading connections (every one +requiring the whole fetching process) happening at the same time. + + Even though socket activity can reach a hectic pace, the +browser never blocks. Note also that the I/O engine is the one +that directs the execution flow of the program by triggering a +call-back chain whenever a file descriptor operation succeeds or +fails. + + A key point for this multiple call-back chained I/O engine is +that every single function in the chain must be guaranteed to +return quickly. Otherwise, the whole system blocks until it +returns. + + +----------- +Conclusions +----------- + + Dillo is currently in very stable beta state. It already shows +impressive performance, and its interactive ``feel'' is much +better than that of other web browsers. + + The modular structure of Dillo, and its reliance on GTK1 allow +it to be very small. Not every feature of HTML-4.01 has been +implemented yet, but no significant problems are foreseen in +doing this. + + The fact that Dillo's central I/O engine is written using +advanced features of POSIX and TCP/IP networking makes its +performance possible, but on the other hand this also means that +only a fraction of the interested hackers are able to work on it. + + A simple code base is critical when trying to attract hackers +to work on a project like this one. Using the GTK+ framework +helped both in creating the graphical user interface and in +handling the concurrency inside the browser. By having threads +communicate through pipes the need for explicit synchronization +is almost completely eliminated, and with it most of the +complexity of concurrent programming disappears. + + A clean, strictly applied layering approach based on clear +abstractions is vital in each programming project. A good, +supportive framework is of much help here. + + diff --git a/devdoc/Images.txt b/devdoc/Images.txt new file mode 100644 index 00000000..62082e48 --- /dev/null +++ b/devdoc/Images.txt @@ -0,0 +1,129 @@ + January 2009, --Jcid + +Update June 2015: See also doc/dw-images-and-backgrounds.doc, or +../html/dw-images-and-backgrounds.html (generated by doxygen). + + ------ + IMAGES + ------ + +* When a image tag is found within a HTML page, Html_tag_open_img +handles it by: + + - Parsing & getting attribute values. + - Creating a new image structure (DilloImage) and its + associated widget (DwImage). + i.e. If 'Image' is the var for the structure, then + 'Image->dw' is the widget. + - Requesting the image to be feeded by the cache. + - Sending some info to the browser interface. + +* The cache can either request the image data from the net, or +feed it directly from the dicache (decompressed image cache). + +* Both processes are somewhat different because the first one +requires to decode the image data into RGB format, and the second +one has the whole data already decoded. + +* Regardless of the RGB-data feeding method, the decoded data is +passed to the widget (DwImage) and drawn in a streamed way. + Note that INDEXED images are also decoded into RGB format. + + Html_tag_open_img // IMG element processing + Html_add_new_image // Read attributes, create image, add to HTML page + a_Image_new // Create a 'DilloImage' data structure, to coordinate + // decoded image-data transfer to an 'Imgbuf'. + Html_add_widget // Adds the dw::Image to the page + Html_load_image // Tells cache to retrieve image + + +--------------------- +Fetching from the net +--------------------- + +* a_Capi_open_url initiates the resource request, and when +finally the answer arrives, the HTTP header is examined for MIME +type and either the GIF or PNG or JPEG decoder is set to handle +the incoming data stream. + + Decoding functions: + a_Gif_callback, a_Jpeg_callback and a_Png_callback. + +* The decoding function calls the following dicache methods as +the data is processed (listed in order): + + a_Dicache_set_parms + a_Dicache_set_cmap (only for indexed-GIF images) + a_Dicache_write + a_Dicache_new_scan (MAY be called here or after set_cmap) + a_Dicache_close + + +* The dicache methods call the necessary functions to connect +with the widget code. This is done by calling image.c functions: + + a_Image_set_parms + a_Image_set_cmap + a_Image_write + a_Image_new_scan + a_Image_close + +* The functions in image.c make the required Dw calls. + + +------------------------- +Fetching from the dicache +------------------------- + +* a_Capi_open_url() tests the cache for the image, and the cache, +via a_Cache_open_url(), enqueues a client for it, without asking +the network for the data. When the client queue is processed (a +bit later), Dicache_image() is set as the callback. + +* When Dicache_image() is called, it sets the proper image data +decoder (RGB) and its data structure based on the entry's Type. +Then it substitutes itself with a_Dicache_callback() as the +handling function, and gets out of the way. + +* Thenceforth the rest of the functions calls is driven by +a_Dicache_callback(). + + +----------- +Misc. notes +----------- + +* Repeated images generate new cache clients, but they may share +the imgbuf. + Note: Currently there's no proper support for transparent +images (i.e. decode to RGBA), but most of the time they render +the background color OK. This is: when first loaded, repeated +images share a background color, but when cached they render +correctly ;-). There's no point in trying to fix this because the +correct solution is to decode to RGBA and let the toolkit (FLTK) +handle the transparency. + +* The first cache-client callback (Dicache_image()) is set when +the Content-type of the image is got. + +* Later on, when there's a shared imgbuf, the dicache's logic +avoids decoding it multiple times and reuses what's already done. + +* The dicache-entry and the Image structure hold bit arrays that +represent which rows have been decoded. + +* The image processing can be found in the following sources: + + - image.{cc,hh} + - dicache.[ch] + - gif.[ch], png.[ch], jpeg.[ch] + - dw/image.{cc,hh} + +* Bear in mind that there are four data structures for image +code: + + - DilloImage (image.hh) + - DICacheEntry (dicache.h) + - dw::Image (class Image in dw/image.hh) + - core::Imgbuf (imgbuf.hh) + diff --git a/devdoc/NC_design.txt b/devdoc/NC_design.txt new file mode 100644 index 00000000..380787f6 --- /dev/null +++ b/devdoc/NC_design.txt @@ -0,0 +1,127 @@ + + _________________________________________________________________ + + Naming&Coding design + _________________________________________________________________ + + Dillo's code is divided into modules. For instance: bookmark, cache, + dicache, gif. + + Let's think of a module named "menu", then: + * Every internal routine of the module, should start with "Menu_" + prefix. + * "Menu_" prefixed functions are not meant to be called from outside + the module. + * If the function is to be exported to other modules (i.e. it will + be called from the outside), it should be wrapped with an "a_" + prefix. + + For instance: if the function name is "Menu_create", then it's an + internal function, but if we need to call it from the outside, then it + should be renamed to "a_Menu_create". + + Why the "a_" prefix? + Because of historical reasons. + And "a_Menu_create" reads better than "d_Menu_create" because the + first one suggests "a Menu create" function! + + Another way of understanding this is thinking of "a_" prefixed + functions as Dillo's internal library, and the rest ("Menu_" prefixed + in our example) as a private module-library. + + Indentation: + + Source code must be indented with 3 blank spaces, no Tabs. + Why? + Because different editors expand or treat tabs in several ways; 8 + spaces being the most common, but that makes code really wide and + we'll try to keep it within the 80 columns bounds (printer friendly). + + You can use: indent -kr -sc -i3 -bad -nbbo -nut -l79 myfile.c + + Function commenting: + + Every single function of the module should start with a short comment + that explains its purpose; three lines must be enough, but if you + think it requires more, enlarge it. + + /* + * Try finding the url in the cache. If it hits, send the contents + * to the caller. If it misses, set up a new connection. + */ + int a_Cache_open_url(const char *url, void *Data) + { + ... + ... + ... + } + + We also have the BUG:, TODO:, and WORKAROUND: tags. + Use them within source code comments to spot hidden issues. For + instance: + + /* BUG: this counter is not accurate */ + ++i; + + /* TODO: get color from the right place */ + a = color; + + /* WORKAROUND: the canonical way of doing it doesn't work yet. */ + ++a; ++a; ++a; + + Function length: + + Let's try to keep functions within the 45 lines boundary. This eases + code reading, following, understanding and maintenance. + + Functions with a single exit: + + It's much easier to follow and maintain functions with a single exit + point at the bottom (instead of multiple returns). The exception to + the rule are calls like dReturn_if_fail() at its head. + + dlib functions: + + * Dillo uses dlib extensively in its C sources. Before starting + to code something new, a good starting point is to check what + this library has to offer (check dlib/dlib.h). + * Memory management must be done using dNew, dNew0, dMalloc, dFree + and their relatives. + * For debugging purposes and error catching (not for normal flow): + dReturn_if_fail, dReturn_val_if_fail etc. are encouraged. + * The MSG macro is extensively used to output additional information + to the calling terminal. + + _________________________________________________________________ + + C++ + + Source code in C++ should follow the same rules with these exceptions: + + * Class method names are camel-cased and start with lowercase + e.g. appendInputMultipart + * Classes and types start uppercased + e.g. class DilloHtmlReceiver + * Class methods don't need to prefix its module name + e.g. links->get() + + We also try to keep the C++ relatively simple. Dillo does use + inheritance and templates, but that's about all. + + _________________________________________________________________ + + What do we get with this? + + * A clear module API for Dillo; every function prefixed "a_" is to + be used outside the module. + * A way to identify where the function came from (the + capitalized word is the module name). + * An inner ADT (Abstract data type) for the module that can be + isolated, tested and replaced independently. + * A two stage instance for bug-fixing. You can change the exported + function algorithms while someone else fixes the internal + module-ADT! + * A coding standard ;) + _________________________________________________________________ + + Naming&Coding design by Jorge Arellano Cid diff --git a/devdoc/README b/devdoc/README new file mode 100644 index 00000000..9736a32b --- /dev/null +++ b/devdoc/README @@ -0,0 +1,51 @@ +README: Last update Jul 2009 + +These documents cover dillo's internals. +For user help, see http://www.dillo.org/dillo3-help.html + +-------------------------------------------------------------------------- + +These documents need a review. +*.txt were current with Dillo1, but many have since become more or + less out-of-date. +*.doc are doxygen source for the Dillo Widget (dw) component, and + were written for Dillo2. + +They will give you an overview of what's going on, but take them +with a pinch of salt. + + Of course I'd like to have *.txt as doxygen files too! +If somebody wants to make this conversion, please let me know +to assign higher priority to updating these docs. + +-- +Jorge.- + + -------------------------------------------------------------------------- + FILE DESCRIPTION STATE + -------------------------------------------------------------------------- + NC_design.txt Naming&Coding design (Be sure to Current + read it before any other doc) + Dillo.txt General overview of the program Current + IO.txt Extensive introduction Current + Cache.txt Informative description Current + Images.txt Image handling and processing Current + HtmlParser.txt A versatile parser Current + Dw.txt The New Dillo Widget (Overview) Current + Imgbuf.txt Image buffers Pending + Selection.txt Selections, and link activation Current (?) + Cookies.txt Explains how to enable cookies Current + Dpid.txt Dillo plugin daemon Current + -------------------------------------------------------------------------- + + + * BTW, there's a small program (srch) within the src/ dir. It searches + tokens within the whole code (*.[ch]). It has proven very useful. + Ex: ./srch a_Image_write + ./srch todo: + + * Please submit your patches with 'hg diff'. + + + Happy coding! + --Jcid diff --git a/devdoc/dw-changes.doc b/devdoc/dw-changes.doc new file mode 100644 index 00000000..7050df9a --- /dev/null +++ b/devdoc/dw-changes.doc @@ -0,0 +1,105 @@ +/** \page dw-changes Changes to the GTK+-based Release Version + +

Changes in Dw

+ +Related to the FLTK port, there have been many changes, this is a +(hopefully complete) list: + +
    +
  • Rendering abstraction, read \ref dw-overview and \ref dw-layout-views + for details. Some important changes: + +
      +
    • The underlying platform (e.g. the UI toolkit) is fully abstract, + there are several platform independent structures replacing + GTK+ structures, e.g. dw::core::Event. + +
    • The central class managing the widget tree is not anymore + GtkDwViewport, but dw::core::Layout. + +
    • Drawing is done via dw::core::View, a pointer is passed to + dw::core::Widget::draw. + +
    • The distinction between viewport coordinates and canvas + coordinates (formerly world coordinates) has been mostly + removed. (Only for views, it sometimes plays a role, see + \ref dw-layout-views). +
    + +
  • Cursors have been moved to dw::core::style, see + dw::core::style::Style::cursor. dw::core::Widget::setCursor is now + protected (and so only called by widget implementations). + +
  • World coordinates are now called canvas coordinates. + +
  • There is now a distinction between dw::core::style::StyleAttrs and + dw::core::style::Style. + +
  • There is no base class for container widgets anymore. The former + DwContainer::for_all has been removed, instead this functionality + is now done via iterators (dw::core::Widget::iterator, + dw::core::Iterator). + +
  • DwPage is now called dw::Textblock, and DwAlignedPage + dw::AlignedTextblock. + +
  • dw::Textblock, all sub classes of it, and dw::Table do not read + "limit_text_width" from the preferences, but get it as an argument. + (May change again.) + +
  • dw::Table has been rewritten. + +
  • Instead of border_spacing in the old DwStyle, there are two attributes, + dw::core::style::Style::hBorderSpacing and + dw::core::style::Style::vBorderSpacing, since CSS allowes to specify + two values. Without CSS, both attributes should have the same value. + +
  • Images are handled differently, see \ref dw-images-and-backgrounds. + +
  • Embedded UI widgets (formerly GtkWidget's) are handled differently, + see dw::core::ui. + +
  • DwButton has been removed, instead, embedded UI widgets are used. See + dw::core::ui and dw::core::ui::ComplexButtonResource. +
+ +Dw is now written C++, the transition should be obvious. All "Dw" +prefixes have been removed, instead, namespaces are used now: + +
    +
  • dw::core contains the core, +
  • dw::core::style styles, +
  • dw::core::ui embedded UI resources, +
  • dw::fltk classes related to FLTK, and +
  • ::dw the widgets. +
+ +

Documentation

+ +The old documentation has been moved to: + + +
Old New +
Dw.txt + general part \ref dw-overview, \ref dw-usage, + \ref dw-layout-widgets, + \ref dw-widget-sizes +
remarks on specific widgets respective source files: dw::Bullet, + dw::core::ui::Embed +
DwImage.txt + signals dw::core::Layout::LinkReceiver +
rest dw::Image, + \ref dw-images-and-backgrounds +
Imgbuf.txt dw::core::Imgbuf, + \ref dw-images-and-backgrounds +
DwPage.txt dw::Textblock +
DwRender.txt \ref dw-overview, \ref dw-layout-views, + dw::core::ui +
DwStyle.txt dw::core::style +
DwTable.txt dw::Table +
DwWidget.txt dw::core::Widget, \ref dw-layout-widgets, + \ref dw-widget-sizes +
Selection.txt dw::core::SelectionState +
+ +*/ diff --git a/devdoc/dw-example-screenshot.png b/devdoc/dw-example-screenshot.png new file mode 100644 index 00000000..94f272ab Binary files /dev/null and b/devdoc/dw-example-screenshot.png differ diff --git a/devdoc/dw-floats-01.png b/devdoc/dw-floats-01.png new file mode 100644 index 00000000..116d36b3 Binary files /dev/null and b/devdoc/dw-floats-01.png differ diff --git a/devdoc/dw-grows.doc b/devdoc/dw-grows.doc new file mode 100644 index 00000000..a0304ef9 --- /dev/null +++ b/devdoc/dw-grows.doc @@ -0,0 +1,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. + +
+ Update: 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.
+ +**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.) + +
+ Notice: Currently, dw::core::Widget::getExtremesImpl must + set all four members in dw::core::Extremes; this may change.
+ +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 adjust_min_width, +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. 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. + +*/ diff --git a/devdoc/dw-images-and-backgrounds.doc b/devdoc/dw-images-and-backgrounds.doc new file mode 100644 index 00000000..8f07766a --- /dev/null +++ b/devdoc/dw-images-and-backgrounds.doc @@ -0,0 +1,235 @@ +/** \page dw-images-and-backgrounds Images and Backgrounds in Dw + +Image Buffers +============= + +Representation of the image data is done by dw::core::Imgbuf, see +there for details. Drawing is done by dw::core::View +(dw::core::View::drawImage). + +Since dw::core::Imgbuf provides memory management based on reference +counting, there may be an 1-to-n relation from image renderers (image +widgets or backgrounds, see below) and dw::core::Imgbuf. Since +dw::core::Imgbuf does not know about renderers, but just provides +rendering functionality, the caller must (typically after calling +dw::core::Imgbuf::copyRow) notify all renderers connected to the +buffer. + + +Image Renderer +============== + +Generally, there are no restrictions on how to manage +dw::core::Imgbuf; but to handle image data from web resources, the +interface dw::core::ImgRenderer should be implemented. It is again +wrapped by DilloImage (to make access from the C part possible, since +dw::core::ImgRenderer is written in C++), which is referenced by +DilloWeb. There are two positions where retrieving image data is +initiated: + +- Html_load_image: for embedded images (implemented by dw::Image, + which implements dw::core::ImgRenderer); +- StyleEngine::apply (search for "case + CSS_PROPERTY_BACKGROUND_IMAGE"): for backgrond images; there are + some implementations of dw::core::ImgRenderer within the context of + dw::core::style::StyleImage. + +Both are described in detail below. Notice that the code is quite +similar; only the implementation of dw::core::ImgRenderer differs. + +At this time, dw::core::ImgRenderer has got two methods (see more +documentation there): + +- dw::core::ImgRenderer::setBuffer, +- dw::core::ImgRenderer::drawRow, +- dw::core::ImgRenderer::finish, and +- dw::core::ImgRenderer::fatal. + + +Images +====== + +This is the simplest renderer, displaying an image. For each row to be +drawn, + +- first dw::core::Imgbuf::copyRow, and then +- for each dw::Image, dw::Image::drawRow must be called, with the same + argument (no scaling is necessary). + +dw::Image automatically scales the dw::core::Imgbuf, the root buffer +should be passed to dw::Image::setBuffer. + +\see dw::Image for more details. + + +Background Images +================= + +Since background images are style resources, they are associated with +dw::core::style::Style, as dw::core::style::StyleImage, which is +handled in a similar way (reference counting etc.) as +dw::core::style::Color and dw::core::style::Font, although it is +concrete and not platform-dependant. + +The actual renderer (passed to Web) is an instance of +dw::core::ImgRendererDist (distributes all calls to a set of other +instances of dw::core::ImgRenderer), which contains two kinds of +renderers: + +- one instance of dw::core::style::StyleImage::StyleImgRenderer, which + does everything needed for dw::core::style::StyleImage, and +- other renderers, used externally (widgets etc.), which are added by + dw::core::style::StyleImage::putExternalImgRenderer (and removed by + dw::core::style::StyleImage::removeExternalImgRenderer). + +This diagram gives an comprehensive overview: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", dir="both", arrowtail="none", + labelfontname=Helvetica, labelfontsize=10, color="#404040", + labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + subgraph cluster_dw_style { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + + Style [URL="\ref dw::core::style::Style"]; + StyleImage [URL="\ref dw::core::style::StyleImage"]; + Imgbuf [URL="\ref dw::core::Imgbuf", color="#a0a0a0"]; + StyleImgRenderer + [URL="\ref dw::core::style::StyleImage::StyleImgRenderer"]; + ImgRenderer [URL="\ref dw::core::ImgRenderer", color="#ff8080"]; + ImgRendererDist [URL="\ref dw::core::ImgRendererDist"]; + ExternalImgRenderer + [URL="\ref dw::core::style::StyleImage::ExternalImgRenderer", + color="#a0a0a0"]; + ExternalWidgetImgRenderer + [URL="\ref dw::core::style::StyleImage::ExternalWidgetImgRenderer", + color="#a0a0a0"]; + } + + subgraph cluster_dw_layout { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + + Layout [URL="\ref dw::core::Layout"]; + LayoutImgRenderer [URL="\ref dw::core::Layout::LayoutImgRenderer"]; + } + + subgraph cluster_dw_widget { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + WidgetImgRenderer [URL="\ref dw::core::Widget::WidgetImgRenderer"]; + } + + subgraph cluster_dw_textblock { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + + Textblock [URL="\ref dw::Textblock"]; + Word [URL="\ref dw::Textblock::Word"]; + WordImgRenderer [URL="\ref dw::Textblock::WordImgRenderer"]; + SpaceImgRenderer [URL="\ref dw::Textblock::SpaceImgRenderer"]; + } + + Style -> StyleImage [headlabel="*", taillabel="1"]; + StyleImage -> Imgbuf [headlabel="*", taillabel="1"]; + StyleImage -> StyleImgRenderer [headlabel="1", taillabel="1"]; + StyleImage -> ImgRendererDist [headlabel="1", taillabel="1"]; + ImgRendererDist -> StyleImgRenderer [headlabel="1", taillabel="1"]; + ImgRendererDist -> ImgRenderer [headlabel="1", taillabel="*"]; + + ImgRenderer -> ImgRendererDist [arrowhead="none", arrowtail="empty", + dir="both", style="dashed"]; + ImgRenderer -> StyleImgRenderer [arrowhead="none", arrowtail="empty", + dir="both", style="dashed"]; + ImgRenderer -> ExternalImgRenderer [arrowhead="none", arrowtail="empty", + dir="both", style="dashed"]; + ExternalImgRenderer -> ExternalWidgetImgRenderer [arrowhead="none", + arrowtail="empty", dir="both", style="dashed"]; + + Layout -> LayoutImgRenderer [headlabel="1", taillabel="0..1"]; + ExternalImgRenderer -> LayoutImgRenderer [arrowhead="none", + arrowtail="empty", dir="both", style="dashed"]; + + Widget -> WidgetImgRenderer [headlabel="1", taillabel="0..1"]; + ExternalWidgetImgRenderer -> WidgetImgRenderer [arrowhead="none", + arrowtail="empty", dir="both", style="dashed"]; + + Textblock -> Word [headlabel="1", taillabel="*"]; + Word -> WordImgRenderer [headlabel="1", taillabel="0..1"]; + Word -> SpaceImgRenderer [headlabel="1", taillabel="0..1"]; + ExternalWidgetImgRenderer -> WordImgRenderer [arrowhead="none", + arrowtail="empty", dir="both", style="dashed"]; + WordImgRenderer -> SpaceImgRenderer [arrowhead="none", arrowtail="empty", + dir="both", style="dashed"]; +} +\enddot + +
[\ref uml-legend "legend"]
+ + +Memory management +----------------- + +dw::core::style::StyleImage extends lout::signal::ObservedObject, so +that deleting this instance can be connected to code dealing with +cache clients etc. See StyleImageDeletionReceiver and how it is +attached in StyleEngine::apply ("case CSS_PROPERTY_BACKGROUND_IMAGE"). + + +Bugs and Things Needing Improvement +=================================== + +(Mostly related to image backgrounds, when not otherwise mentioned.) + +High Priority +------------- + +**Configurability, security/privacy aspects, etc.,** which are +currently available for image widgets, should be adopted. Perhaps some +more configuration options specially for background images. + + +Medium Priority +--------------- + +**Background-attachment** is not yet implemented, and will be postponed. + +**Calls to dw::core::ImgRenderer::fatal** are incomplete. As an +example, it is not called, when connecting to a server fails. (And so, +as far as I see, no cache client is started.) + + +Low Priority +------------ + +**Alpha support:** (not related to image backgrounds) currently alpha +support (and also colormap management) is done in dicache, while +dw::Image is only created with type RGB. This leads to several problems: + +- One dicache entry (representing an image related to the same URL), + which has only one background color, may refer to different images + with different background colors. +- The dicache only handles background colors, not background images. + +The solution is basicly simple: keep alpha support out of dicache; +instead implement RGBA in dw::Image. As it seems, the main problem is +alpha support in FLTK/X11. + + +Solved (Must Be Documented) +--------------------------- + +*Drawing background images row by row may become slow. As an +alternative, dw::core::ImgRenderer::finish could be used. However, +drawing row by row could become an option.* There is now +dw::core::style::drawBackgroundLineByLine, which can be changed in the +code, and is set to *false*. The old code still exists, so changing +this to *true* activates again drawing line by line. + +(For image widgets, this could also become an option: in contexts, +when image data is retrieved in a very fast way.) + +*/ diff --git a/devdoc/dw-layout-views.doc b/devdoc/dw-layout-views.doc new file mode 100644 index 00000000..d1118489 --- /dev/null +++ b/devdoc/dw-layout-views.doc @@ -0,0 +1,256 @@ +/** \page dw-layout-views Layout and Views + +Rendering of Dw is done in a way resembling the model-view pattern, at +least formally. Actually, the counterpart of the model, the layout +(dw::core::Layout), does a bit more than a typical model, namely the +layouting (delegated to the widget tree, see \ref dw-layout-widgets), +and the view does a bit less than a typical view, i.e. only the actual +drawing. + +Additionally, there is a structure representing common properties of +the platform. A platform is typically related to the underlying UI +toolkit, but other uses may be thought of. + +This design helps to archieve two important goals: + +
    +
  • Abstraction of the actual drawing, by different implementations + of dw::core::View. + +
  • It makes portability simple. +
+ + +

Viewports

+ +Although the design implies that the usage of viewports should be +fully transparent to the layout module, this cannot be fully achieved, +for the following reasons: + +
    +
  • Some features, which are used on the level of dw::core::Widget, + e.g. anchors, refer to scrolling positions. + +
  • Size hints (see \ref dw-layout-widgets) depend on the viewport + sizes, e.g. when the user changes the window size, and so also + the size of a viewport, the text within should be rewrapped. +
+ +Therefore, dw::core::Layout keeps track of the viewport size, the +viewport position, and even the thickness of the scrollbars, they are +relevant, see below for more details. +If a viewport is not used, however, the size is not defined. + +Whether a given dw::core::View implementation is a viewport or not, is +defined by the return value of dw::core::View::usesViewport. If this +method returns false, the following methods need not to be implemented +at all: + +
    +
  • dw::core::View::getHScrollbarThickness, +
  • dw::core::View::getVScrollbarThickness, +
  • dw::core::View::scrollTo, and +
  • dw::core::View::setViewportSize. +
+ +

Scrolling Positions

+ +The scrolling position is the canvas position at the upper left corner +of the viewport. Views using viewports must + +
    +
  1. change this value on request (dw::core::View::scrollTo), and +
  2. tell other changes to the layout, e.g. caused by user events + (dw::core::Layout::scrollPosChanged). +
+ +Applications of scrolling positions (anchors, test search etc.) are +handled by the layout, in a way fully transparent to the view. + +

Scrollbars

+ +A feature of the viewport size model are scrollbars. There may be a +vertical scrollbar and a horizontal scrollbar, displaying the +relationship between canvas and viewport height or width, +respectively. If they are not needed, they are hidden, to save screen +space. + +Since scrollbars decrease the usable space of a view, dw::core::Layout +must know how much space they take. The view returns, via +dw::core::View::getHScrollbarThickness and +dw::core::View::getVScrollbarThickness, how thick they will be, when +visible. + +Viewport sizes, which denote the size of the viewport widgets, include +scrollbar thicknesses. When referring to the viewport \em excluding +the scrollbars space, we will call it "usable viewport size", this is +the area, which is used to display the canvas. + +

Drawing

+ +A view must implement several drawing methods, which work on the whole +canvas. If it is necessary to convert them (e.g. into +dw::fltk::FltkViewport), this is done in a way fully transparent to +dw::core::Widget and dw::core::Layout, instead, this is done by the +view implementation. + +There exist following situations: + +
    +
  • A view gets an expose event: It will delegate this to the + layout (dw::core::Layout::draw), which will then pass it to the + widgets (dw::core::Widget::draw), with the view as a parameter. + Eventually, the widgets will call drawing methods of the view. + +
  • A widget requests a redraw: In this case, the widget will + delegate this to the layout (dw::core::Layout::queueDraw), which + delegates it to the view (dw::core::View::queueDraw). + Typically, the view will queue these requests for efficiency. + +
  • A widget requests a resize: This case is described below, in short, + dw::core::View::queueDrawTotal is called for the view. +
+ +If the draw method of a widget is implemented in a way that it may +draw outside of the widget's allocation, it should draw into a +clipping view. A clipping view is a view related to the actual +view, which guarantees that the parts drawn outside are discarded. At +the end, the clipping view is merged into the actual view. Sample +code: + +\code +void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) +{ + // 1. Create a clipping view. + dw::core::View clipView = + view->getClippingView (allocation.x, allocation.y, + allocation.width, getHeight ()); + + // 2. Draw into clip_view + clipView->doSomeDrawing (...); + + // 3. Draw the children, they receive the clipping view as argument. + dw::core::Rectangle *childArea + for () { + if (child->intersects (area, &childArea)) + child->draw (clipView, childArea); + } + + // 4. Merge + view->mergeClippingView (clipView); +} +\endcode + +A drawing process is always embedded into calls of +dw::core::View::startDrawing and dw::core::View::finishDrawing. An +implementation of this may e.g. use backing pixmaps, to prevent +flickering. + + +

Sizes

+ +In the simplest case, the view does not have any influence on +the canvas size, so it is told about changes of the +canvas size by a call to dw::core::View::setCanvasSize. This happens +in the following situations: + +
    +
  • dw::core::Layout::addWidget, +
  • dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), + and +
  • dw::core::Layout::queueResize (called by + dw::core::Widget::queueResize, when a widget itself requests a size + change). +
+ +

Viewports

+ +There are two cases where the viewport size changes: + +
    +
  • As an reaction on a user event, e.g. when the user changes the + window size. In this case, the view delegates this + change to the layout, by calling + dw::core::Layout::viewportSizeChanged. + +
  • The viewport size may also depend on the visibility of UI + widgets, which depend on the world size, e.g scrollbars, + generally called "viewport markers". This is described in a separate + section. +
+ +After the creation of the layout, the viewport size is undefined. When +a view is attached to a layout, and this view can already specify +its viewport size, it may call +dw::core::Layout::viewportSizeChanged within the implementation of +dw::core::Layout::setLayout. If not, it may do this as soon as the +viewport size is known. + +Generally, the scrollbars have to be considered. If e.g. an HTML page +is rather small, it looks like this: + +\image html dw-viewport-without-scrollbar.png + +If some more data is retrieved, so that the height exceeds the +viewport size, the text has to be rewrapped, since the available width +gets smaller, due to the vertical scrollbar: + +\image html dw-viewport-with-scrollbar.png + +Notice the different line breaks. + +This means circular dependencies between these different sizes: + +
    +
  1. Whether the scrollbars are visible or not, determines the + usable space of the viewport. + +
  2. From the usable space of the viewport, the size hints for the + toplevel are calculated. + +
  3. The size hints for the toplevel widgets may have an effect on its + size, which is actually the canvas size. + +
  4. The canvas size determines the visibility of the scrollbarss. +
+ +To make an implementation simpler, we simplify the model: + +
    +
  1. For the calls to dw::core::Widget::setAscent and + dw::core::Widget::setDescent, we will always exclude the + horizontal scrollbar thickness (i.e. assume the horizontal + scrollbar is used, although the visibility is determined correctly). + +
  2. For the calls to dw::core::Widget::setWidth, we will calculate + the usable viewport width, but with the general assumption, that + the widget generally gets higher. +
+ +This results in the following rules: + +
    +
  1. Send always (when it changes) dw::core::Layout::viewportHeight + minus the maximal value of dw::core::View::getHScrollbarThickness as + argument to dw::core::Widget::setAscent, and 0 as argument to + dw::core::Widget::setDescent. + +
  2. There is a flag, dw::core::Layout::canvasHeightGreater, which is set + to false in the following cases: + +
      +
    • dw::core::Layout::addWidget, +
    • dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), + and +
    • dw::core::Layout::viewportSizeChanged. +
    + + Whenever the canvas size is calculated (dw::core::Layout::resizeIdle), + and dw::core::Layout::canvasHeightGreater is false, a test is made, + whether the widget has in the meantime grown that high, that the second + argument should be set to true (i.e. the vertical scrollbar gets visible). + As soon as and dw::core::Layout::canvasHeightGreater is true, no such test + is done anymore. +
+ +*/ diff --git a/devdoc/dw-layout-widgets.doc b/devdoc/dw-layout-widgets.doc new file mode 100644 index 00000000..e0215562 --- /dev/null +++ b/devdoc/dw-layout-widgets.doc @@ -0,0 +1,267 @@ +/** \page dw-layout-widgets Layout and Widgets + +Both, the layouting and the drawing is delegated to a tree of +widgets. A widget represents a given part of the document, e.g. a text +block, a table, or an image. Widgets may be nested, so layouting and +drawing may be delegated by one widget to its child widgets. + +Where to define the borders of a widget, whether to combine different +widgets to one, or to split one widget into multiple ones, should be +considered based on different concerns: + +
    +
  • First, there are some restrictions of Dw: + +
      +
    • The allocation (this is the space a widget allocates at + a time) of a dillo widget is always rectangular, and +
    • the allocation of a child widget must be a within the allocation + of the parent widget. +
    + +
  • Since some widgets are already rather complex, an important goal + is to keep the implementation of the widget simple. + +
  • Furthermore, the granularity should not be too fine, because of the + overhead each single widget adds. +
+ +For CSS, there will be a document tree on top of Dw, this will be +flexible enough when mapping the document structure on the widget +structure, so you should not have the document structure in mind. + +

Sizes

+ +\ref dw-widget-sizes + + +

Styles

+ +Each widget is assigned a style, see dw::core::style for more +informations. + + +

Iterators

+ +Widgets must implement dw::core::Widget::iterator. There are several +common iterators: + +
    +
  • dw::core::EmptyIterator, and +
  • dw::core::TextIterator. +
+ +Both hide the constructor, use the \em create method. + +These simple iterators only iterate through one widget, it does not +have to iterate recursively through child widgets. Instead, the type +dw::core::Content::WIDGET is returned, and the next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +This makes implementation much simpler, for recursive iteration, there +is dw::core::DeepIterator. + + +

Anchors and Scrolling

+ +\todo This section is not implemented yet, after the implementation, + the documentation should be reviewed. + +Here is a description, what is to be done for a widget +implementation. How to jump to anchors, set scrolling positions +etc. is described in \ref dw-usage. + +

Anchors

+ +Anchors are position markers, which are identified by a name, which is +unique in the widget tree. The widget must care about anchors in three +different situations: + +
    +
  1. Adding an anchor is inititiated by a specific widget method, e.g. + dw::Textblock::addAnchor. Here, dw::core::Widget::addAnchor must be + called, + +
  2. Whenever the position of an anchor is changed, + dw::core::Widget::changeAnchor is called (typically, this is done + in the implementation of dw::core::Widget::sizeAllocateImpl). + +
  3. When a widget is destroyed, the anchor must be removed, by calling + dw::core::Widget::removeAnchor. +
+ +All these methods are delegated to dw::core::Layout, which manages +anchors centrally. If the anchor in question has been set to jump to, +the viewport position is automatically adjusted, see \ref +dw-usage. + + +

Drawing

+ +In two cases, a widget has to be drawn: + +
    +
  1. as a reaction on an expose event, +
  2. if the widget content has changed and it needs to be redrawn. +
+ +In both cases, drawing is done by the implementation of +dw::core::Widget::draw, which draws into the view. + + +Each view provides some primitive methods for drawing, most should be +obvious. Note that the views do not know anything about dillo +widgets, and so coordinates have to be passed as canvas coordinates. + +A widget may only draw in its own allocation. If this cannot be +achieved, a clipping view can be used, this is described in +\ref dw-layout-views. Generally, drawing should then look like: + +\code +void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) +{ + // 1. Create a clipping view. + dw::core::View clipView = + view->getClippingView (allocation.x, allocation.y, + allocation.width, getHeight ()); + + // 2. Draw into clip_view + clipView->doSomeDrawing (...); + + // 3. Draw the children, they receive the clipping view as argument. + dw::core::Rectangle *childArea + for () { + if (child->intersects (area, &childArea)) + child->draw (clipView, childArea); + } + + // 4. Merge + view->mergeClippingView (clipView); +} +\endcode + +Clipping views are expensive, so they should be avoided when possible. + +The second argument to dw::core::Widget::draw is the region, which has +to be drawn. This may (but needs not) be used for optimization. + +If a widget contains child widgets, it must explicitly draw these +children (see also code example above). For this, there is the useful +method dw::core::Widget::intersects, which returns, which area of the +child must be drawn. + +

Explicit Redrawing

+ +If a widget changes its contents, so that it must be redrawn, it must +call dw::core::Widget::queueDrawArea or +dw::core::Widget::queueDraw. The first variant expects a region within +the widget, the second will cause the whole widget to be redrawn. This +will cause an asynchronous call of dw::core::Widget::draw. + +If only the size changes, a call to dw::core::Widget::queueResize is +sufficient, this will also queue a complete redraw (see \ref +dw-widget-sizes.) + + +

Mouse Events

+ +A widget may process mouse events. The view (\ref dw-layout-views) +passes mouse events to the layout, which then passes them to the +widgets. There are two kinds of mouse events: + +
    +
  • events returning bool, and +
  • events returning nothing (void). +
+ +The first group consists of: + +
    +
  • dw::core::Widget::buttonPressImpl, +
  • dw::core::Widget::buttonReleaseImpl, and +
  • dw::core::Widget::motionNotifyImpl. +
+ +For these events, a widget returns a boolean value, which denotes, +whether the widget has processed this event (true) or not (false). In +the latter case, the event is delegated according to the following +rules: + +
    +
  1. First, this event is passed to the bottom-most widget, in which + allocation the mouse position is in. +
  2. If the widget does not process this event (returning false), it is + passed to the parent, and so on. +
  3. The final result (whether \em any widget has processed this event) is + returned to the view. +
+ +The view may return this to the UI toolkit, which then interprets this +in a similar way (whether the viewport, a UI widget, has processed +this event). + +These events return nothing: + +
    +
  • dw::core::Widget::enterNotifyImpl and +
  • dw::core::Widget::leaveNotifyImpl. +
+ +since they are bound to a widget. + +When processing mouse events, the layout always deals with two +widgets: the widget, the mouse pointer was in, when the previous mouse +event was processed, (below called the "old widget") and the widget, +in which the mouse pointer is now ("new widget"). + +The following paths are calculated: + +
    +
  1. the path from the old widget to the nearest common ancestor of the old + and the new widget, and +
  2. the path from this ancestor to the new widget. +
+ +For the widgets along these paths, dw::core::Widget::enterNotifyImpl +and dw::core::Widget::leaveNotifyImpl are called. + +

Signals

+ +If a caller outside of the widget is interested in these events, he +can connect a dw::core::Layout::LinkReceiver. For those events with a +boolean return value, the results of the signal emission is regarded, +i.e. the delegation of an event to the parent of the widget can be +stopped by a signal receiver returning true, even if the widget method +returns false. + +First, the widget method is called, then (in any case) the signal is +emitted. + +

Selection

+ +If your widget has selectable contents, it should delegate the events +to dw::core::SelectionState (dw::core::Layout::selectionState). + + +

Miscellaneous

+ +

Cursors

+ +Each widget has a cursor, which is set by +dw::core::Widget::setCursor. If a cursor is assigned to a part of a +widget, this widget must process mouse events, and call +dw::core::Widget::setCursor explicitly. + +(This will change, cursors should become part of +dw::core::style::Style.) + +

Background

+ +Backgrounds are part of styles +(dw::core::style::Style::backgroundColor). If a widget assigns +background colors to parts of a widget (as dw::Table does for rows), +it must call dw::core::Widget::setBgColor for the children inside this +part. + +*/ diff --git a/devdoc/dw-line-breaking.doc b/devdoc/dw-line-breaking.doc new file mode 100644 index 00000000..14ab97c4 --- /dev/null +++ b/devdoc/dw-line-breaking.doc @@ -0,0 +1,470 @@ +/** \page dw-line-breaking Changes in Line-Breaking and Hyphenation + +
Info: +Should be incorporated into dw::Textblock.
+ +Introduction +============ + +For the implementation of hyphenation in dillo, not only a +hyphenation algorithm was implemented, but also, the line breaking was +changed to a simple optimization per line. Aside from the improvement +by this change per se, an important aspect is the introduction of +"penalties". Before this change, dillo put all words into a line which +fitted into it; now, a "badness" is calculated for a possible +breakpoint, and the best breakpoint, i. e. the breakpoint with the +smallest value for "badness", is chosen. This can be simply refined +to define "good" and "bad" breakpoints by assigning a "penalty"; the +best breakpoint is then the one with the smallest value of "badness + +penalty". Details can be found below. + +Example: Normal spaces have a penalty of 0, while hyphenation points +get a penalty of, say, 1, since hyphenation is generally considered as +a bit "ugly" and should rather be avoided. Consider a situation where +the word "dillo" could be hyphenated, with the following badnesses: + +- before "dillo": 0.6; +- between "dil-" and "lo": 0.2; +- after "dillo": 0.5. + +Since the penalty is added, the last value is the best one, so "dillo" +is put at the end of the line, without hyphenation. + +Under other circumstances (e. g. narrower lines), the values +might be different: + +- before "dillo": infinite; +- between "dil-" and "lo": 0.3; +- after "dillo": 1.5. + +In this case, even the addition of the penalty makes hyphenation the +best choice. + + +Literature +========== + +Breaking Paragraphs Into Lines +------------------------------ + +Although dillo does not (yet?) implement the algorithm TEX +uses for line breaking, this document shares much of the notation used +by the article *Breaking Paragraphs Into Lines* by Donald E. Knuth and +Michael F. Plass; originally published in: Software -- Practice and +Experience **11** (1981), 1119-1184; reprinted in: *Digital +Typography* by Donalt E. Knuth, CSLI Publications 1999. Anyway an +interesting reading. + +Hyphenation +----------- + +Dillo uses the algorithm by Frank Liang, which is described in his +doctoral dissertation found at http://www.tug.org/docs/liang/. There +is also a description in chapter H ("Hyphenation") of *The +TEXbook* by Donald E. Knuth, Addison-Wesley 1984. + +Pattern files can be found at +http://www.ctan.org/tex-archive/language/hyphenation. + + +Overview of Changes +=================== + +Starting with this change, dw/textblock.cc has been split up; anything +related to line breaking has been moved into +dw/textblock_linebreaking.cc. This will also be done for other aspects +like floats. (Better, however, would be a clean logical split.) + +An important change relates to the way that lines are added: before, +dillo would add a line as soon as a new word for this line was +added. Now, a line is added not before the *last* word of this line is +known. This has two important implications: + +- Some values in dw::Textblock::Line, which represented values + accumulated within the line, could be removed, since now, these + values can be calculated simply in a loop. +- On the other hand, this means that some words may not belong to any + line. For this reason, in some cases (e. g. in + dw::Textblock::sizeRequestImpl) dw::Textblock::showMissingLines is + called, which creates temporary lines, which must, under other + circumstances, be removed again by + dw::Textblock::removeTemporaryLines, since they have been created + based on limited information, and so possibly in a wrong way. (See + below for details.) + +When a word can be hyphenated, an instance of dw::Textblock::Word is +used for each part. Notice that soft hyphens are evaluated +immediately, but automatic hyphenation is done in a lazy way (details +below), so the number of instances may change. There are some new +attributes: only when dw::Textblock::Word::canBeHyphenated is set to +*true*, automatic hyphenation is allowed; it is set to false when soft +hyphens are used for a word, and (of course) by the automatic +hyphenation itself. Furthermore, dw::Textblock::Word::hyphenWidth +(more details in the comment there) has to be included when +calculating line widths. + +Some values should be configurable: dw::Textblock::HYPHEN_BREAK, the +penalty for hyphens. Also dw::Textblock::Word::stretchability, +dw::Textblock::Word::shrinkability, which are both set in +dw::Textblock::addSpace. + + +Criteria for Line-Breaking +========================== + +Before these changes to line breaking, a word (represented by +dw::Textblock::Word) had the following attributes related to +line-breaking: + +- the width of the word itself, represented by + dw::Textblock::Word::size; +- the width of the space following the word, represented by + dw::Textblock::Word::origSpace. + +In a more mathematical notation, the \f$i\f$th word has a width +\f$w_i\f$ and a space \f$s_i\f$. + +A break was possible, when there was a space between the two words, +and the first possible break was chosen. + +With hyphenation, the criteria are refined. Hyphenation should only be +used when otherwise line breaking results in very large spaces. We +define: + +- the badness \f$\beta\f$ of a line, which is greater the more the + spaces between the words differ from the ideal space; +- a penalty \f$p\f$ for any possible break point. + +The goal is to find those break points, where \f$\beta + p\f$ is +minimal. + +Examples for the penalty \f$p\f$: + +- 0 for normal line breaks (between words); +- \f$\infty\f$ to prevent a line break at all costs; +- \f$-\infty\f$ to force a line +- a positive, but finite, value for hyphenation points. + +So we need the following values: + +- \f$w_i\f$ (the width of the word \f$i\f$ itself); +- \f$s_i\f$ (the width of the space following the word \f$i\f$); +- the stretchability \f$y_i\f$, a value denoting how much the space + after word\f$i\f$ can be stretched (typically \f${1\over 2} s_i\f$ + for justified text; otherwise 0, since the spaces are not + stretched); +- the shrinkability \f$y_i\f$, a value denoting how much the space + after word\f$i\f$ can be shrunken (typically \f${1\over 3} s_i\f$ + for justified text; otherwise 0, since the spaces are not shrinked); +- the penalty \f$p_i\f$, if the line is broken after word \f$i\f$; +- a width \f$h_i\f$, which is added, when the line is broken after + word \f$i\f$. + +\f$h_i\f$ is the width of the hyphen, if the word \f$i\f$ is a part of +the hyphenated word (except the last part); otherwise 0. + +Let \f$l\f$ be the (ideal) width (length) of the line, which is +e. at the top given by the browser window width. Furthermore, all words +from \f$a\f$ to \f$b\f$ are added to the line. \f$a\f$ is fixed: we do +not modify the previous lines anymore; but our task is to find a +suitable \f$b\f$. + +We define: + +\f[W_a^b = \sum_{i=a}^{b} w_i + \sum_{i=a}^{b-1} s_i + h_b\f] + +\f[Y_a^b = {Y_0}_a^b + \sum_{i=a}^{b-1} y_i\f] + +\f[Z_a^b = {Z_0}_a^b + \sum_{i=a}^{b-1} z_i\f] + + +\f$W_a^b\f$ is the total width, \f$Y_a^b\f$ the total stretchability, +and \f$Z_a^b\f$ the total shrinkability. \f${Y_0}_a^b\f$ and +\f${Z_0}_a^b\f$ are the stretchability and shrinkability defined per +line, and applied at the borders; they are 0 for justified text, but +\f${Y_0}_a^b\f$ has a positive value otherwise, see below for details. + +Furthermore the *adjustment ratio* \f$r_a^b\f$: + +- in the ideal case that \f$W_a^b = l\f$: \f$r_a^b = 0\f$; +- if \f$W_a^b < l\f$: \f$r_a^b = (l - W_a^b) / Y_a^b\f$ + (\f$r_a^b < 0\f$ in this case); +- if \f$W_a^b > l\f$: \f$r_a^b = (l - W_a^b) / Z_a^b\f$ + (\f$r_a^b < 0\f$ in this case). + +The badness \f$\beta_a^b\f$ is defined as follows: + +- if \f$r_a^b\f$ is undefined or \f$r_a^b < -1\f$: \f$\beta_a^b = \infty\f$; +- otherwise: \f$\beta_a^b = |r_a^b|^3\f$ + +The goal is to find the value of \f$b\f$ where \f$\beta_a^b + p_b\f$ +is minimal. (\f$a\f$ is given, since we do not modify the previous +lines.) + +After a couple of words, it is not predictable whether this minimum +has already been reached. There are two cases where this is possible +for a given \f$b'\f$: + +- \f$\beta_{b'}^a = \infty\f$ (line gets too tight): + \f$a \le b < b'\f$, the minimum has to be searched between these two + values; +- \f$p_{b'} = -\infty\f$ (forced line break): + \f$a \le b \le b'\f$ (there may be another minimum of + \f$\beta_a^b\f$ before; note the \f$\le\f$ instead of \f$<\f$). + +This leads to a problem that the last words of a text block are not +displayed this way, since they do not fulfill these rules for being +added to a line. For this reason, there are "temporary" lines already +described above. + +(Note that the actual calculation differs from this description, since +integer arithmetic is used for performance, which make the actual +code more complicated. See dw::Textblock::BadnessAndPenalty for +details.) + +Ragged Borders +-------------- + +For other than justified text (left-, right-aligned and centered), the +spaces between the words are not shrinked or stretched (so \f$y_i\f$ +and \f$z_i\f$ are 0), but additional space is added to the left or +right border or to both. For this reason, an additional stretchability +\f${Y_0}_a^b\f$ is added (see definition above). Since this space at +the border is 0 in an ideal case (\f$W_a^b = l\f$), it cannot be +shrunken, so \f${Z_0}_a^b\f$ is 0. + +This is not equivalent to the calculation of the total stretchability +as done for justified text, since in this case, the stretchability +depends on the number of words: consider the typical case that all +spaces and stretchabilities are equal (\f$y_a = y_{a + 1} = \ldots = +y_b\f$). With \f$n\f$ words, the total strechability would be \f$n +\cdot y_a\f$, so increase with an increasing number of words +(\f$y_a\f$ is constant). This is correct for justified text, but for +other alignments, where only one space (or two, for centered text) is +changed, this would mean that a line with many narrow words is more +stretchable than a line with few wide words. + +It is obvious that left-aligned text can be handled in the same way as +right-aligned text. [... Centered text? ...] + +The default value for the stretchability is the line height without +the space between the lines (more precisely: the maximum of all word +heights). The exact value not so important when comparing different +possible values for the badness \f$\beta_a^b\f$, when \f${Y_0}_a^b\f$ +is nearly constant for different \f$b\f$ (which is the case for the +actual value), but it is important for the comparison with penalties, +which are constant. To be considered is also that for non-justified +text, hyphenation is differently (less) desirable; this effect can be +achieved by enlarging the stretchability, which will lead to a smaller +badness, and so make hyphenation less likely. The user can configure +the stretchability by changing the preference value +*stretchability_factor* (default: 1.0). + +(Comparison to TEX: Knuth and Plass describe a method for +ragged borders, which is effectively the same as described here (Knuth +1999, pp. 93--94). The value for the stretchability of the line +is slightly less, 1 em (ibid., see also p. 72 for the +definition of the units). However, this article suggests a value for +the hyphenation penalty, which is ten times larger than the value for +justified text; this would suggest a larger value for +*stretchability_factor*.) + + +Hyphens +======= + +Words (instances of dw::Textblock::Word), which are actually part of a +hyphenated word, are always drawn as a whole, not seperately. This +way, the underlying platform is able to apply kerning, ligatures, etc. + +Calculating the width of such words causes some problems, since it is +not required that the width of text "AB" is identical to the width of +"A" plus the width of "B", just for the reasons mentioned above. It +gets even a bit more complicated, since it is required that a word +part (instance of dw::Textblock::Word) has always the same length, +independent of whether hyphenation is applied or not. Furthermore, the +hyphen length is fixed for a word; for practical reasons, it is always +the width of a hyphen, in the given font. + +For calculating the widths, consider a word of four syllables: +A-B-C-D. There are 3 hyphenation points, and so 23 = 8 +possible ways of hyphenation: ABCD, ABC-D, AB-CD, AB-C-D, A-BCD, +A-BC-D, A-B-CD, A-B-C-D. (Some of them, like the last one, are only +probable for very narrow lines.) + +Let w(A), w(B), w(C), w(D) be the word widths (part of +dw::Textblock::Word::size), which have to be calculated, and l be a +shorthand for dw::core::Platform::textWidth. Without considering +this problem, the calculation would be simple: w(A) = l(A) +etc. However, it gets a bit more complicated. Since all +non-hyphenations are drawn as a whole, the following conditions can be +concluded: + +- from drawing "ABCD" (not hyphenated at all): w(A) + w(B) + w(C) + + w(D) = l(ABCD); +- from drawing "BCD", when hyphenated as "A-BCD" ("A-" is not + considered here): w(B) + w(C) + w(D) = l(BCD); +- likewise, from drawing "CD" (cases "AB-CD" and "A-B-CD"): w(C) + + w(D) = l(CD); +- finally, for the cases "ABC-D", "AB-C-D", "A-BC-D", and "A-B-C-D": + w(D) = l(D). + +So, the calculation is simple: + +- w(D) = l(D) +- w(C) = l(CD) - w(D) +- w(B) = l(BCD) - (w(C) + w(D)) +- w(A) = l(ABCD) - (w(B) + w(C) + w(D)) + +For calculation the hyphen widths, the exact conditions would be +over-determined, even when the possibility for individual hyphen +widths (instead of simply the text width of a hyphen character) would +be used. However, a simple approach of fixed hyphen widths will have +near-perfect results, so this is kept simple. + + +Automatic Hyphenation +===================== + +When soft hyphens are used, words are immediately divided into +different parts, and so different instances of +dw::Textblock::Word. Automatic hyphenation (using Liang's algorithm) +is, however, not applied always, but only when possibly needed, after +calculating a line without hyphenation: + +- When the line is tight, the last word of the line is hyphenated; + possibly this will result in a line with less parts of this word, + and so a less tight line. +- When the line is loose, and there is another word (for the next + line) available, this word is hyphenated; possibly, some parts of + this word are taken into this line, making it less loose. + +After this, the line is re-calculated. + +A problem arrises when the textblock is rewrapped, e. g. when the +user changes the window width. In this case, some new instances of +dw::Textblock::Word must be inserted into the word list, +dw::Textblock::words. This word list is implemented as an array, which +is dynamically increased; a simple approach would involve moving all +of the n elements after position i, so +n - i steps are necessary. This would not be a +problem, since O(n) steps are necessary; however, this will be +necessary again for the next hyphenated word (at the end of a +following line), and so on, so that +(n - i1) + +(n - i2) + ..., with +i1 < i2 < ..., +which results in O(n2) steps. For this reason, the word +list is managed by the class lout::misc::NotSoSimpleVector, which uses +a trick (a second array) to deal with exactly this problem. See there +for more details. + + +Tests +===== + +There are test HTML files in the test directory. Also, there is +a program testing automatic hyphenation, test/liang, which can +be easily extended. + + +Bugs and Things Needing Improvement +=================================== + +High Priority +------------- + +None. + +Medium Priority +--------------- + +None. + +Low Priority +------------ + +**Mark the end of a paragraph:** Should dw::core::Content::BREAK still +be used? Currently, this is redundant to +dw::Textblock::BadnessAndPenalty. + +Solved (Must Be Documented) +--------------------------- + +These have been solved recently and should be documented above. + +*Bugs in hyphenation:* There seem to be problems when breaking words +containing hyphens already. Example: "Abtei-Stadt", which is divided +into "Abtei-" and "Stadt", resulting possibly in +"Abtei--[new line]Stadt". See also below under +"Medium Priority", on how to deal with hyphens and dashes. + +**Solution:** See next. + +*Break hyphens and dashes:* The following rules seem to be relevant: + +- In English, an em-dash is used with no spaces around. Breaking + before and after the dash should be possible, perhaps with a + penalty > 0. (In German, an en-dash (Halbgeviert) with spaces around + is used instead.) +- After a hyphen, which is part of a compound word, a break should be + possible. As described above ("Abtei-Stadt"), this collides with + hyphenation. + +Where to implement? In the same dynamic, lazy way like hyphenation? As +part of hyphenation? + +Notice that Liang's algorithm may behave different regarding hyphens: +"Abtei-Stadt" is (using the patterns from CTAN) divided into "Abtei-" +and "Stadt", but "Nordrhein-Westfalen" is divided into "Nord", +"rhein-West", "fa", "len": the part containing the hyphen +("rhein-West") is untouched. (Sorry for the German words; if you have +got English examples, send them me.) + +**Solution for both:** This has been implemented in +dw::Textblock::addText, in a similar way to soft hyphens. Liang's +algorithm now only operates on the parts: "Abtei" and "Stadt"; +"Nordrhein" and "Westfalen". + +*Hyphens in adjacent lines:* It should be simple to assign a larger +penalty for hyphens, when the line before is already hyphenated. This +way, hyphens in adjacent lines are penalized further. + +**Solved:** There are always two penalties. Must be documented in +detail. + +*Incorrect calculation of extremes:* The minimal width of a text block +(as part of the width extremes, which are mainly used for tables) is +defined by everything between two possible breaks. A possible break +may also be a hyphenation point; however, hyphenation points are +calculated in a lazy way, when the lines are broken, and not when +extremes are calculated. So, it is a matter of chance whether the +calculation of the minimal width will take the two parts "dil-" and +"lo" into account (when "dillo" has already been hyphenated), or only +one part, "dillo" (when "dillo" has not yet been hyphenated), +resulting possibly in a different value for the minimal width. + +Possible strategies to deal with this problem: + +- Ignore. The implications should be minimal. +- Any solution will make it neccessary to hyphenate at least some + words when calculating extremes. Since the minimal widths of all + words are used to calculate the minimal width of the text block, the + simplest approach will hyphenate all words. This would, of course, + eliminate the performance gains of the current lazy approach. +- The latter approach could be optimized in some ways. Examples: (i) + If a word is already narrower than the current accumulated value for + the minimal width, it makes no sense to hyphenate it. (ii) In other + cases, heuristics may be used to estimate the number of syllables, + the width of the widest of them etc. + +**Solved:** Hyphenated parts of a word are not considered anymore for +width extremes, but only whole words. This is also one reason for the +introduction of the paragraphs list. + +**Also:** + +- Configuration of penalties. + +*/ diff --git a/devdoc/dw-map.doc b/devdoc/dw-map.doc new file mode 100644 index 00000000..aebeb7da --- /dev/null +++ b/devdoc/dw-map.doc @@ -0,0 +1,59 @@ +/** \page dw-map Dillo Widget Documentation Map + +This maps includes special documentations as well as longer comments +in the sources. Arrows denote references between the documents. + +\dot +digraph G { + rankdir=LR; + node [shape=record, fontname=Helvetica, fontsize=8]; + fontname=Helvetica; fontsize=8; + + dw_overview [label="Dillo Widget Overview", URL="\ref dw-overview"]; + dw_usage [label="Dillo Widget Usage", URL="\ref dw-usage"]; + dw_layout_views [label="Layout and Views", URL="\ref dw-layout-views"]; + dw_layout_widgets [label="Layout and Widgets", + URL="\ref dw-layout-widgets"]; + dw_widget_sizes [label="Sizes of Dillo Widgets", + URL="\ref dw-widget-sizes"]; + dw_changes [label="Changes to the GTK+-based Release Version", + URL="\ref dw-changes"]; + dw_images_and_backgrounds [label="Images and Backgrounds in Dw", + URL="\ref dw-images-and-backgrounds"]; + dw_Image [label="dw::Image", URL="\ref dw::Image"]; + dw_core_Imgbuf [label="dw::core::Imgbuf", URL="\ref dw::core::Imgbuf"]; + dw_core_SelectionState [label="dw::core::SelectionState", + URL="\ref dw::core::SelectionState"]; + dw_core_style [label="dw::core::style", URL="\ref dw::core::style"]; + dw_Table [label="dw::Table", URL="\ref dw::Table"]; + dw_Textblock [label="dw::Textblock", URL="\ref dw::Textblock"]; + dw_core_ui [label="dw::core::ui", URL="\ref dw::core::ui"]; + + dw_overview -> dw_changes; + dw_overview -> dw_usage; + dw_overview -> dw_core_style; + dw_overview -> dw_core_ui; + dw_overview -> dw_images_and_backgrounds; + dw_overview -> dw_layout_widgets; + dw_overview -> dw_widget_sizes; + dw_overview -> dw_layout_views; + + dw_usage -> dw_Table; + dw_usage -> dw_Textblock; + dw_usage -> dw_core_style; + dw_usage -> dw_core_ui; + dw_usage -> dw_images_and_backgrounds; + + dw_layout_widgets -> dw_widget_sizes; + dw_layout_widgets -> dw_core_SelectionState; + + dw_widget_sizes -> dw_Table; + dw_widget_sizes -> dw_Textblock; + + dw_images_and_backgrounds -> dw_core_Imgbuf; + dw_images_and_backgrounds -> dw_Image; + + dw_core_style -> dw_Textblock; +} +\enddot +*/ \ No newline at end of file diff --git a/devdoc/dw-out-of-flow-2.doc b/devdoc/dw-out-of-flow-2.doc new file mode 100644 index 00000000..d9d70565 --- /dev/null +++ b/devdoc/dw-out-of-flow-2.doc @@ -0,0 +1,69 @@ +/** \page dw-out-of-flow-2 Handling Elements Out Of Flow (notes 2) + +This has to be integrated into \ref dw-out-of-flow. + +Constructing a page with floats +------------------------------- +When a page is constructed (dw::Textblock::addWord), the *generating* +block tells the positions of floats (or, generally, widgets out of +flow) via dw::OutOfFlowMgr::tellPosition. This method considers +already collisions with other floats (only previous floats; floats +following this float are not considered); after the call, +dw::OutOfFlowMgr::getBorder will return correct values. + +dw::OutOfFlowMgr::tellPosition also checks for overlaps of this float +with other textblocks, except this textblock (the *generator*, which +is just constructed, so nothing has to be done). The fact that the +position of the float is the top, and so the float has only an +allocation below this position, leads to the effect that only the +textblocks following the generator are affected. (**Check:** Can the +search be limited here?) When a page is constructed, no textblocks +should be following the generating block, so no textblocks are +affected. + +**Todo:** Clarify details of line breaking (\ref dw-line-breaking). + +Float changes its size +---------------------- +The float itself will call queueResize, which will result in a call of +markSizeChange for the *containing* block, which will then call +dw::OutOfFlowMgr::markSizeChange. Here, the vloat is only *marked* as +dirty; the size will be calculated later (in +dw::OutOfFlowMgr::ensureFloatSize). + +This will trigger the resize idle function, so sizeRequest and +sizeAllocate for all floats and textblocks. In this run, +dw::OutOfFlowMgr::hasRelationChanged will return *true*, and so result +in a call of dw::Textblock::borderChanged, and trigger a second run of +the resize idle function, dealing correctly with the new size. + +(This case is handles in a not perfectly optimal way, since two runs +of the resize idle function are neccessary; but size changes of floats +is not a very common case. + +When a page is constructed (see above), a changing size of a float +currently constructed typically only affects the most bottom +textblock; the other textblocks are not covered by this float.) + +**Error:** In this case, new collisions are not yet considered. + + +Changing the width of the page +------------------------------ + +When the page width is changed, this will result in a reconstruction +of the page; see *Constructing a page with floats*. Anyway, checking +for overlaps will play a more important role. This is handled in an +optimal way by dw::OutOfFlowMgr::hasRelationChanged. + +**Check:** Are "cascades" avoided, like this: + +1. All textblocks are constructed. A float in textblock 1 overlaps + with textblock 2, so dw::Textblock::borderChanged is called for + textblock 2. +2. In another resize idle run, textblock 2 is constructed again. A + float in textblock 2 overlaps with textblock 3, so that + dw::Textblock::borderChanged is called for textblock 3. +3. Etc. + +*/ \ No newline at end of file diff --git a/devdoc/dw-out-of-flow-floats.doc b/devdoc/dw-out-of-flow-floats.doc new file mode 100644 index 00000000..53c6b220 --- /dev/null +++ b/devdoc/dw-out-of-flow-floats.doc @@ -0,0 +1,121 @@ +/** \page dw-out-of-flow-floats Handling Elements Out Of Flow: Floats + +(Note: Bases on work at , I plan +to split the documentation on elements out of flow into different +parts: general part, floats, positioned elements. In this document, +informations about floats are collected.) + + +GB lists and CB lists +===================== + +Floats generated by a block which is not yet allocated are initially +put into a list related to the *generator*: + +- dw::OutOfFlowMgr::TBInfo::leftFloatsGB or +- dw::OutOfFlowMgr::TBInfo::rightFloatsGB. + +These lists are also called GB lists. + +Floats of allocated generators are put into lists related to the +*container* (called CB lists): + +- dw::OutOfFlowMgr::leftFloatsCB or +- dw::OutOfFlowMgr::rightFloatsCB. + +As soon as the container is allocated, all floats are moved from the +GB lists to the CB lists (dw::OutOfFlowMgr::sizeAllocateStart → +dw::OutOfFlowMgr::moveFromGBToCB). + +Here, it is important to preserve the *generation order* (for reasons, +see below: *Sorting floats*), i. e. the order in which floats have +been added (dw::OutOfFlowMgr::addWidgetOOF). This may become a bit +more complicated in a case like this: + + + + + +
+
float 1
+
+
float 2
+
+
float 3
+
+ + +The floats are generated in this order: + +- \#fl-1 (generated by \#bl-1), +- \#fl-2 (generated by \#bl-2), +- \#fl-3 (generated by \#bl-1). + +Since the floats must be moved into the CB list in this order, it +becomes clear that the floats from one GB list cannot be moved at +once. For this reason, each float is assigned a "mark", which is +different from the last one as soon as the generator is *before* the +generator of the float added before. In the example above, there are +three generators: body, \#bl-1, and \#bl-2 (in this order), and floats +are assigned these marks: + +- \#fl-1: 0, +- \#fl-2: also 0, +- \#fl-3 is assigned 1, since its generator (\#bl-1) lies before the + last generator (\#bl-2). + +dw::OutOfFlowMgr::moveFromGBToCB will then iterate over all marks, so +that the generation order is preserved. + + +Sorting floats +============== + +Floats are sorted, to make binary search possible, in these lists: + +- for each generator: dw::OutOfFlowMgr::TBInfo::leftFloatsGB and + dw::OutOfFlowMgr::TBInfo::rightFloatsGB; +- for the container: dw::OutOfFlowMgr::leftFloatsCB and + dw::OutOfFlowMgr::rightFloatsCB. + +The other two lists, dw::OutOfFlowMgr::leftFloatsAll and +dw::OutOfFlowMgr::rightFloatsAll are not sorted at all. + +New floats are always added to the end of either list; this order is +called *generation order*. See also above: *GB lists and CB lists*. + +On the other hand, there are different sorting criteria, implemented +by different comparators, so that different kinds of keys may be used +for searching. These sorting criteria are equivalent to the generation +order. + +dw::OutOfFlowMgr::Float::CompareSideSpanningIndex compares +*sideSpanningIndex* (used to compare floats to those on the respective +other side); if you look at the definition +(dw::OutOfFlowMgr::addWidgetOOF) it becomes clear that this order is +equivalent to the generation order. + +dw::OutOfFlowMgr::Float::CompareGBAndExtIndex compares *externalIndex* +for floats with same generators, otherwise: (i) if one generator (T1) +is a direct anchestor of the other generator (T2), the child of T1, +which is an anchestor of, or identical to, T2 is compared to the float +generated by T1, using *externalIndex*, as in this example: + + T1 -+-> child --> ... -> T2 -> Float + `-> Float + +Otherwise, the two blocks are compared, according to their position in +dw::OutOfFlowMgr::tbInfos: + + common anchestor -+-> ... --> T1 -> Float + `-> ... --> T2 -> Float + +This is equivalent to the generation order, as long it is ensured that +*externalIndex* reflects the generation order within a generating +block, for both floats and child blocks. + +dw::OutOfFlowMgr::Float::ComparePosition ... + +*/ diff --git a/devdoc/dw-out-of-flow.doc b/devdoc/dw-out-of-flow.doc new file mode 100644 index 00000000..ea4a52bc --- /dev/null +++ b/devdoc/dw-out-of-flow.doc @@ -0,0 +1,214 @@ +/** \page dw-out-of-flow Handling Elements Out Of Flow + + +
Info: +Should be incorporated into dw::Textblock.
+ +Introduction +============ + +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): + + +
    +
  • Some text.
  • +
  • +
    Some longer text, so + that the effect described in this passage can be + demonstrated. +
    + Some more and longer text.
  • +
  • Final text. Plus some more to demonstrate how text flows + around the float on the right side.
  • +
+ +which may be rendered like this + +\image html dw-floats-01.png + +The float (the DIV section, yellow in the image) is defined +("generated") within the list item (blue), 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. + +(Notice also that other text blocks must regard floats to calculate +their borders, and so their size. In this example, the following list +item (green) must consider the position of the float. This is +discussed in detail in the next section.) + +Both in this text and the code, generating and containing block are +abbreviated with **GB** and **CB**, respectively. + + +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 rules +which should be defined in this document). + +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 | + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + | left float index | 0 | 0 | 1 | + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + | right float index | 1 | 0 | 1 | + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + | absolutely positioned index | 1 | 1 | + +---+ - - - +---+---+- - - - - -+---+---+---+---+ + +Details are hidden by static inline methods of dw::OutOfFlowMgr. + + +The sizeRequest/sizeAllocate problem +======================================== + +*See also:* \ref dw-widget-sizes, especially the section *Rules for +Methods Related to Resizing*. + +The size/position model of ::dw consists mainly of the following two +steps: + +1. First, the size of the toplevel widget is calculated. Size + calculation typically depends on the sizes of the widgets, which + are calculated recursively, but not more. +2. After this, the toplevel widget is allocated at position (0, 0), + with the previosly calculated size. Each widget must allocate its + children; here, the condition for the toplevel widget (allocated + size equals requested size) is not necessary; instead, each widget + may be allocated at every size. + +Especially for floats, this model becomes a bit difficult, for reasons +described below. For the solutions, much is centralized at the level +of the containing block, which delegates most to an instance of +dw::OutOfFlowMgr (details below). + +**The size of a widget depends on the size not only of the children.** +In the example above, the last list item (green, following the +generating list item) must know the size of the the float (which is +not a child or, generally, descendant) to determine the borders, which +is done in dw::Textblock::sizeRequestImpl. + +For this, the size model has been extended (see \ref dw-widget-sizes, +section *Rules for Methods Related to Resizing*): *sizeRequest* can be +called within *sizeRequestImpl* for other widgets that children (with +some caution). Namely, dw::Textblock::sizeRequestImpl calls +dw::core::Widget::sizeRequest for the float, via +dw::OutOfFlowMgr::getBorder and dw::OutOfFlowMgr::ensureFloatSize. + +**The size of a widget depends on the allocation of another widget.** +In the example above, both list items (blue and green) must know the +position of the float widget, within dw::Textblock::sizeRequestImpl, +to calculate the borders. The position, however, is stored in the +allocation, which is typically calculated later. + +Here, two cases must be distinguished. The position of a float is +always **relative to its generating block**, so for calculating the +borders for the generating block, the allocation needs not to be +know. For other textblocks, it needs to be known, so the calculation +of the borders will ignore floats generated by other textblocks, until +all widgets are allocated. The latter will call (when neccessary) +dw::core::Widget::queueResize, so that all border calculations are +repeated. See below (*hasRelationChanged*) for details. + +Generally, this pattern (distinguishing between GB and CB) can be +found everywhere in dw::OutOfFlowMgr. + +For details see: + +- dw::OutOfFlowMgr::getLeftBorder, dw::OutOfFlowMgr::getRightBorder, + dw::OutOfFlowMgr::getBorder (called by the first two), and + especially, dw::OutOfFlowMgr::getFloatsListForTextblock (called by + the latter), where these three cases are distinguished; +- dw::OutOfFlowMgr::sizeAllocateStart, + dw::OutOfFlowMgr::sizeAllocateEnd which are called by the containing + block. + +(This could be solved in a more simple, elegant way, when +*sizeRequest* would depend on the position. This is, however, only a +vague idea, perhaps not even feasible, and for which there are no +concrete plans, certainly not in \ref dw-grows.) + + +Implementation details +====================== + +- CB and GB lists (general pattern) (see previous section) +- binary search; different search criteria, how they accord +- lastLeftTBIndex, lastRightTBIndex etc. +- limitiation of search; extIndex etc. + + +How *hasRelationChanged* works +============================== + +... + + +Integration of line breaking and floats +======================================= + +(Positioning of floats, loop, recent works.) + + +Absolute and fixed positiones +============================= + +See . + +*/ \ No newline at end of file diff --git a/devdoc/dw-overview.doc b/devdoc/dw-overview.doc new file mode 100644 index 00000000..0c4ffb53 --- /dev/null +++ b/devdoc/dw-overview.doc @@ -0,0 +1,158 @@ +/** \page dw-overview Dillo Widget Overview + +Note: If you are already familiar with the Gtk+-based version of Dw, +read \ref dw-changes. + + +The module Dw (Dillo Widget) is responsible for the low-level rendering of +all resources, e.g. images, plain text, and HTML pages (this is the +most complex type). Dw is \em not responsible for parsing HTML, or +decoding image data. Furthermore, the document tree, which is planned +for CSS, is neither a part of Dw, instead, it is a new module on top +of Dw. + +The rendering, as done by Dw, is split into two phases: + +
    +
  • the \em layouting, this means calculating the exact positions of + words, lines, etc. (in pixel position), and +
  • the \em drawing, i.e. making the result of the layouting visible + on the screen. +
+ +The result of the layouting allocates an area, which is called +\em canvas. + +

Structure

+ +The whole Dw module can be split into the following parts: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", fontname=Helvetica, fontsize=10, + labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + + subgraph cluster_core { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent core"; + + Layout [URL="\ref dw::core::Layout"]; + Platform [URL="\ref dw::core::Platform", color="#ff8080"]; + View [URL="\ref dw::core::View", color="#ff8080"]; + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + } + + subgraph cluster_fltk { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK specific part (as an\nexample for the platform specific\n\ +implementations)"; + + subgraph cluster_fltkcore { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK core"; + + FltkPlatform [URL="\ref dw::fltk::FltkPlatform"]; + FltkView [URL="\ref dw::fltk::FltkView", color="#ff8080"]; + } + + FltkViewport [URL="\ref dw::fltk::FltkViewport"]; + FltkPreview [URL="\ref dw::fltk::FltkPreview"]; + } + + subgraph cluster_widgets { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent widgets"; + + Textblock [URL="\ref dw::Textblock"]; + AlignedTextblock [URL="\ref dw::AlignedTextblock", color="#a0a0a0"]; + Table [URL="\ref dw::Table"]; + Image [URL="\ref dw::Image"]; + etc1 [label="..."]; + etc2 [label="..."]; + } + + Layout -> Platform [headlabel="1", taillabel="1"]; + Layout -> View [headlabel="*", taillabel="1"]; + + Layout -> Widget [headlabel="1", taillabel="1", label="topLevel"]; + Widget -> Widget [headlabel="*", taillabel="1", label="children"]; + + Widget -> Textblock [arrowhead="none", arrowtail="empty", dir="both"]; + Widget -> Table [arrowhead="none", arrowtail="empty", dir="both"]; + Widget -> Image [arrowhead="none", arrowtail="empty", dir="both"]; + Widget -> etc1 [arrowhead="none", arrowtail="empty", dir="both"]; + Textblock -> AlignedTextblock [arrowhead="none", arrowtail="empty", + dir="both"]; + AlignedTextblock -> etc2 [arrowhead="none", arrowtail="empty", dir="both"]; + + Platform -> FltkPlatform [arrowhead="none", arrowtail="empty", dir="both", + style="dashed"]; + FltkPlatform -> FltkView [headlabel="*", taillabel="1"]; + + View -> FltkView [arrowhead="none", arrowtail="empty", dir="both"]; + FltkView -> FltkViewport [arrowhead="none", arrowtail="empty", dir="both", + style="dashed"]; + FltkView -> FltkPreview [arrowhead="none", arrowtail="empty", dir="both", + style="dashed"]; +} +\enddot + +
[\ref uml-legend "legend"]
+ +\em Platform means in most cases the underlying UI toolkit +(e.g. FLTK). A layout is bound to a specific platform, but multiple +platforms may be handled in one program. + +A short overview: + +
    +
  • dw::core::Layout is the central class, it manages the widgets and the + view, and provides delegation methods for the platform. + +
  • The layouting is done by a tree of widgets (details are described in + \ref dw-layout-widgets), also the drawing, which is finally delegated + to the view. + +
  • The view (implementation of dw::core::View) provides primitive methods + for drawing, but also have an influence on + the canvas size (via size hints). See \ref dw-layout-views for details. + +
  • Some platform dependencies are handled by implementations + of dw::core::Platform. +
+ + +

Header Files

+ +The structures mentioned above can be found in the following header +files: + +
    +
  • Anything from the Dw core in core.hh. Do not include the single files. + +
  • The single widgets can be found in the respective header files, e.g. + image.hh for dw::Image. + +
  • The core of the FLTK implementation is defined in fltkcore.hh. This + includes dw::fltk::FltkPlatform, dw::fltk::FltkView, but not the concrete + view implementations. + +
  • The views can be found in single header files, e.g fltkviewport.hh for + dw::fltk::FltkViewport. +
+ + +

Further Documentations

+ +A complete map can be found at \ref dw-map. + +
    +
  • For learning, how to use Dw, read \ref dw-usage and related documents, + dw::core::style, dw::core::ui and \ref dw-images-and-backgrounds. +
  • Advanced topics are described in \ref dw-layout-widgets, + \ref dw-widget-sizes and \ref dw-layout-views. +
+ +*/ diff --git a/devdoc/dw-size-of-widget.png b/devdoc/dw-size-of-widget.png new file mode 100644 index 00000000..dbdbe0c4 Binary files /dev/null and b/devdoc/dw-size-of-widget.png differ diff --git a/devdoc/dw-style-box-model.png b/devdoc/dw-style-box-model.png new file mode 100644 index 00000000..bf2fb1f1 Binary files /dev/null and b/devdoc/dw-style-box-model.png differ diff --git a/devdoc/dw-style-length-absolute.png b/devdoc/dw-style-length-absolute.png new file mode 100644 index 00000000..9ea28cad Binary files /dev/null and b/devdoc/dw-style-length-absolute.png differ diff --git a/devdoc/dw-style-length-percentage.png b/devdoc/dw-style-length-percentage.png new file mode 100644 index 00000000..b1ad79c9 Binary files /dev/null and b/devdoc/dw-style-length-percentage.png differ diff --git a/devdoc/dw-style-length-relative.png b/devdoc/dw-style-length-relative.png new file mode 100644 index 00000000..ee79b1a9 Binary files /dev/null and b/devdoc/dw-style-length-relative.png differ diff --git a/devdoc/dw-textblock-collapsing-spaces-1-1.png b/devdoc/dw-textblock-collapsing-spaces-1-1.png new file mode 100644 index 00000000..d528dfb2 Binary files /dev/null and b/devdoc/dw-textblock-collapsing-spaces-1-1.png differ diff --git a/devdoc/dw-textblock-collapsing-spaces-1-2.png b/devdoc/dw-textblock-collapsing-spaces-1-2.png new file mode 100644 index 00000000..483e79d1 Binary files /dev/null and b/devdoc/dw-textblock-collapsing-spaces-1-2.png differ diff --git a/devdoc/dw-textblock-collapsing-spaces-2-1.png b/devdoc/dw-textblock-collapsing-spaces-2-1.png new file mode 100644 index 00000000..0a03ea80 Binary files /dev/null and b/devdoc/dw-textblock-collapsing-spaces-2-1.png differ diff --git a/devdoc/dw-textblock-collapsing-spaces-2-2.png b/devdoc/dw-textblock-collapsing-spaces-2-2.png new file mode 100644 index 00000000..b89c6254 Binary files /dev/null and b/devdoc/dw-textblock-collapsing-spaces-2-2.png differ diff --git a/devdoc/dw-usage.doc b/devdoc/dw-usage.doc new file mode 100644 index 00000000..a23920b8 --- /dev/null +++ b/devdoc/dw-usage.doc @@ -0,0 +1,375 @@ +/** \page dw-usage Dillo Widget Usage + +This document describes the usage of Dw, without going too much into +detail. + + +

Getting Started

+ +In this section, a small runnable example is described, based on the +FLTK implementation. + +As described in \ref dw-overview, the following objects are needed: + +
    +
  • dw::core::Layout, +
  • an implementation of dw::core::Platform (we will use + dw::fltk::FltkPlatform), +
  • at least one implementation of dw::core::View (dw::fltk::FltkViewport), + and +
  • some widgets (for this example, only a simple dw::Textblock). +
+ +First of all, the necessary \#include's: + +\code +#include +#include + +#include "dw/core.hh" +#include "dw/fltkcore.hh" +#include "dw/fltkviewport.hh" +#include "dw/textblock.hh" +\endcode + +Everything is put into one function: + +\code +int main(int argc, char **argv) +{ +\endcode + +As the first object, the platform is instantiated: + +\code + dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform (); +\endcode + +Then, the layout is created, with the platform attached: + +\code + dw::core::Layout *layout = new dw::core::Layout (platform); +\endcode + +For the view, we first need a FLTK window: + +\code + Fl_Window *window = new Fl_Window(200, 300, "Dw Example"); + window->begin(); +\endcode + +After this, we can create a viewport, and attach it to the layout: + +\code + dw::fltk::FltkViewport *viewport = + new dw::fltk::FltkViewport (0, 0, 200, 300); + layout->attachView (viewport); +\endcode + +Each widget needs a style (dw::core::style::Style, see dw::core::style), +so we construct it here. For this, we need to fill a +dw::core::style::StyleAttrs structure with values, and call +dw::core::style::Style::create (latter is done further below): + +\code + dw::core::style::StyleAttrs styleAttrs; + styleAttrs.initValues (); + styleAttrs.margin.setVal (5); +\endcode + +dw::core::style::StyleAttrs::initValues sets several default +values. The last line sets a margin of 5 pixels. Next, we need a +font. Fonts are created in a similar way, first, the attributes are +defined: + +\code + dw::core::style::FontAttrs fontAttrs; + fontAttrs.name = "Bitstream Charter"; + fontAttrs.size = 14; + fontAttrs.weight = 400; + fontAttrs.style = dw::core::style::FONT_STYLE_NORMAL; + fontAttrs.letterSpacing = 0; + fontAttrs.fontVariant = dw::core::style::FONT_VARIANT_NORMAL; +\endcode + +Now, the font can be created: + +\code + styleAttrs.font = dw::core::style::Font::create (layout, &fontAttrs); +\endcode + +As the last attributes, the background and forground colors are +defined, here dw::core::style::Color::createSimple must be called: + +\code + styleAttrs.color = + dw::core::style::Color::create (layout, 0x000000); + styleAttrs.backgroundColor = + dw::core::style::Color::create (layout, 0xffffff); +\endcode + +Finally, the style for the widget is created: + +\code + dw::core::style::Style *widgetStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +Now, we create a widget, assign a style to it, and set it as the +toplevel widget of the layout: + +\code + dw::Textblock *textblock = new dw::Textblock (false); + textblock->setStyle (widgetStyle); + layout->setWidget (textblock); +\endcode + +The style is not needed anymore (a reference is added in +dw::core::Widget::setStyle), so it should be unreferred: + +\code + widgetStyle->unref(); +\endcode + +Now, some text should be added to the textblock. For this, we first +need another style. \em styleAttrs can still be used for this. We set +the margin to 0, and the background color to "transparent": + +\code + styleAttrs.margin.setVal (0); + styleAttrs.backgroundColor = NULL; + + dw::core::style::Style *wordStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +This loop adds some paragraphs: + +\code + for(int i = 1; i <= 10; i++) { + char buf[4]; + sprintf(buf, "%d.", i); + + char *words[] = { "This", "is", "the", buf, "paragraph.", + "Here", "comes", "some", "more", "text", + "to", "demonstrate", "word", "wrapping.", + NULL }; + + for(int j = 0; words[j]; j++) { + textblock->addText(strdup(words[j]), wordStyle); +\endcode + +Notice the \em strdup, dw::Textblock::addText will feel responsible +for the string, and free the text at the end. (This has been done to +avoid some overhead in the HTML parser.) + +The rest is simple, it also includes spaces (which also have styles): + +\code + textblock->addSpace(wordStyle); + } +\endcode + +Finally, a paragraph break is added, which is 10 pixels high: + +\code + textblock->addParbreak(10, wordStyle); + } +\endcode + +Again, this style should be unreferred: + +\code + wordStyle->unref(); +\endcode + +After adding text, this method should always be called (for faster +adding large text blocks): + +\code + textblock->flush (); +\endcode + +Some FLTK stuff to finally show the window: + +\code + window->resizable(viewport); + window->show(); + int errorCode = Fl::run(); +\endcode + +For cleaning up, it is sufficient to destroy the layout: + +\code + delete layout; +\endcode + +And the rest + +\code + return errorCode; +} +\endcode + +If you compile and start the program, you should see the following: + +\image html dw-example-screenshot.png + +Try to scroll, or to resize the window, you will see, that everything +is done automatically. + +Of course, creating new widgets, adding text to widgets etc. can also +be done while the program is running, i.e. after fltk::run has been +called, within timeouts, idles, I/O functions etc. Notice that Dw is +not thread safe, so that everything should be done within one thread. + +With the exception, that you have to call dw::Textblock::flush, +everything gets immediately visible, within reasonable times; Dw has +been optimized for frequent updates. + + +

List of all Widgets

+ +These widgets are used within dillo: + +
    +
  • dw::core::ui::Embed +
  • dw::AlignedTextblock +
  • dw::Bullet +
  • dw::Ruler +
  • dw::Image +
  • dw::ListItem +
  • dw::Table +
  • dw::TableCell +
  • dw::Textblock +
+ +If you want to create a new widget, refer to \ref dw-layout-widgets. + + +

List of Views

+ +There are three dw::core::View implementations for FLTK: + +
    +
  • dw::fltk::FltkViewport implements a viewport, which is used in the + example above. + +
  • dw::fltk::FltkPreview implements a preview window, together with + dw::fltk::FltkPreviewButton, it is possible to have a scaled down + overview of the whole canvas. + +
  • dw::fltk::FltkFlatView is a "flat" view, i.e. it does not support + scrolling. It is used for HTML buttons, see + dw::fltk::ui::FltkComplexButtonResource and especially + dw::fltk::ui::FltkComplexButtonResource::createNewWidget for details. +
+ +More informations about views in general can be found in \ref +dw-layout-views. + + +

Iterators

+ +For examining generally the contents of widgets, there are iterators +(dw::core::Iterator), created by the method +dw::core::Widget::iterator (see there for more details). + +These simple iterators only iterate through one widget, and return +child widgets as dw::core::Content::WIDGET. The next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +If you want to iterate through the whole widget trees, there are two +possibilities: + +
    +
  1. Use a recursive function. Of course, with this approach, you are + limited by the program flow. + +
  2. Maintain a stack of iterators, so you can freely pass this stack + around. This is already implemented, as dw::core::DeepIterator. +
+ +As an example, dw::core::SelectionState represents the selected region +as two instances of dw::core::DeepIterator. + + +

Finding Text

+ +See dw::core::Layout::findtextState and dw::core::FindtextState +(details in the latter). There are delegation methods: + +
    +
  • dw::core::Layout::search and +
  • dw::core::Layout::resetSearch. +
+ + +

Anchors and Scrolling

+ +In some cases, it is necessary to scroll to a given position, or to +an anchor, programmatically. + +

Anchors

+ +Anchors are defined by widgets, e.g. dw::Textblock defines them, when +dw::Textblock::addAnchor is called. To jump to a specific anchor +within the current widget tree, use dw::core::Layout::setAnchor. + +This can be done immediately after assignig a toplevel widget, even +when the anchor has not yet been defined. The layout will remember the +anchor, and jump to the respective position, as soon as possible. Even +if the anchor position changes (e.g., when an anchor is moved +downwards, since some space is needed for an image in the text above), +the position is corrected. + +As soon as the user scrolls the viewport, this correction is not done +anymore. If in dillo, the user request a page with an anchor, which is +quite at the bottom of the page, he may be get interested in the text +at the beginning of the page, and so scrolling down. If then, after +the anchor has been read and added to the dw::Textblock, this anchor +would be jumped at, the user would become confused. + +The anchor is dismissed, too, when the toplevel widget is removed +again. + +\todo Currently, anchors only define vertical positions. + +

Scrolling

+ +To scroll to a given position, use the method +dw::core::Layout::scrollTo. It expects several parameters: + +
    +
  • a horizontal adjustment parameter, defined by dw::core::HPosition, +
  • a vertical adjustment parameter, defined by dw::core::VPosition, and +
  • a rectangle (\em x, \em y, \em width and \em heigh) of the region + to be adjusted. +
+ +If you just want to move the canvas coordinate (\em x, \em y) into the +upper left corner of the viewport, you can call: + +\code +dw::core::Layout *layout; +// ... +layout->scrollTo(dw::core::HPOS_LEFT, dw::core::VPOS_TOP, 0, 0, 0, 0); +\endcode + +By using dw::core::HPOS_NO_CHANGE or dw::core::VPOS_NO_CHANGE, you can +change only one dimension. dw::core::HPOS_INTO_VIEW and +dw::core::VPOS_INTO_VIEW will cause the viewport to move as much as +necessary, that the region is visible in the viewport (this is +e.g. used for finding text). + + +

Further Documentations

+ +
    +
  • dw::core::style +
  • dw::core::ui +
  • \ref dw-images-and-backgrounds +
+ +*/ diff --git a/devdoc/dw-viewport-with-scrollbar.png b/devdoc/dw-viewport-with-scrollbar.png new file mode 100644 index 00000000..7ac62de3 Binary files /dev/null and b/devdoc/dw-viewport-with-scrollbar.png differ diff --git a/devdoc/dw-viewport-without-scrollbar.png b/devdoc/dw-viewport-without-scrollbar.png new file mode 100644 index 00000000..8aa20fec Binary files /dev/null and b/devdoc/dw-viewport-without-scrollbar.png differ diff --git a/devdoc/dw-widget-sizes.doc b/devdoc/dw-widget-sizes.doc new file mode 100644 index 00000000..a82d3b99 --- /dev/null +++ b/devdoc/dw-widget-sizes.doc @@ -0,0 +1,277 @@ +/** \page dw-widget-sizes Sizes of Dillo Widgets + +
Info: +Not up to date, see \ref dw-grows.
+ +Allocation +========== + +Each widget has an \em allocation at a given time, this includes + +- 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. + +- 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 +divided into an ascender (which height is called \em ascent), and a +descender (which height is called \em descent). The total height is so +the sum of \em ascent and \em descent. + +Sizes of zero are allowed. The upper limit for the size of a widget is +defined by the limits of the C++ type \em int. + +\image html dw-size-of-widget.png Allocation of a Widget + +In the example in the image, the widget has the following allocation: + +- \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 +calling dw::core::Widget::sizeAllocate. This is a concrete method, +which will call dw::core::Widget::sizeAllocateImpl (see code of +dw::core::Widget::sizeAllocate for details). + +For trivial widgets (like dw::Bullet), +dw::core::Widget::sizeAllocateImpl does not need to be +implemented. For more complex widgets, the implementation should call +dw::core::Widget::sizeAllocate (not +dw::core::Widget::sizeAllocateImpl) on all child widgets, with +appropriate child allocations. dw::core::Widget::allocation should not +be changed here, this is already done in +dw::core::Widget::sizeAllocate. + + +Requisitions +============ + +A widget may prefer a given size for the allocation. This size, the +\em requisition, should be returned by the method +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: + +- 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 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. + +From the outside, dw::Image::sizeRequest should be called, which does +a bit of optimization. Notice that in dw::Image::sizeRequestImpl, no +optimization like lazy evaluation is necessary, this is already done +in dw::Image::sizeRequest. + +A widget, which has children, will likely call dw::Image::sizeRequest +on its children, to calculate the total requisition. + +The caller (this is either the dw::core::Layout, or the parent +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.) + + +Size Hints +========== + +
Info: +Size hints have been removed, see \ref dw-grows.
+ + +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: + +- 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: + +- 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 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. + +- 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. + + +Resizing +======== + +When the widget changes its size (requisition), it should call +dw::core::Widget::queueResize. The next call of +dw::core::Widget::sizeRequestImpl should then return the new +size. See dw::Image::setBuffer as an example. + +Interna are described in the code of dw::core::Widget::queueResize. + +

Incremental Resizing

+ +A widget may calculate its size based on size calculations already +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: + +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: + 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 +===================================== + +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 + *sizeRequestImpl* (called by *sizeRequest*), *markSizeChange*, and + *markExtremesChange* (the latter two are called by *queueResize*). +2. On the other hand, to make sure that the calls, which are allowed, + are handled correctly, especially in implementations of + *sizeRequestImpl*, *markSizeChange*, *markExtremesChange* + +Generally, the rules defined below are, in case of doubt, rather +strict; when changing the rules, loosening is simpler than to tighten +them, since this will make it neccessary to review old code for calls +previously allowed but now forbidden. + +Short recap: + +- *QueueResize* directly calls *markSizeChange* and + *markExtremesChanges*, and queues an idle function for the actual + resizing (dw::core::Layout::resizeIdle). (The idle function is + called some time after *queueResize* is finished.) +- The resize idle function first calls *sizeRequest*, then + *sizeAllocate*, for the toplevel widget. + +In the following table, the rules are defined in detail. "Within call +of ..." includes all methods called from the original method: the +first row (*queueResize*) defines also the rules for +*markExtremesChanges* and *markExtremesChanges*, and in the second row +(*sizeAllocate*), even *sizeRequest* has to be considered. + +
Info: +Not up to date: *queueResize* can now be called recursively (so to +speak). See code there.
+ + + + + + + + +
Within call of ... ↓ + ... is call allowed of ... ? → + queueResize + sizeAllocate + sizeRequest + getExtremes +
queueResize + No + No1 + No1 + No1 +
sizeAllocate + Yes + Only for children2 + Yes(?) + Yes(?) +
sizeRequest + Yes3 + No + Limited4 + Limited4 +
getExtremes + Yes3 + No + Limited4 + Limited4 +
1) Otherwise, since these other methods +may be call *queueResize*, the limitation that *queueResize* must not +call *queueResize* can be violated. + +2) Could perhaps be loosened as for *sizeRequest* and +*getExtremes*, but there is probably no need. + +3) Therefore the distinction between *RESIZE_QUEUED* and +*NEEDS_RESIZE*, and *EXTREMES_QUEUED* and *EXTREMES_CHANGED*, +respectively. + +4) Calls only for children are safe. In other cases, you +take a large responsibility to prevent endless recursions by +(typically indirectly) calling *sizeRequest* / *getExtremes* for +direct ancestors. +
+ +Furthermore, *sizeAllocate* can only be called within a call of +dw::core::Layout::resizeIdleId, so (if you do not touch dw::core) do +not call it outside of *sizeAllocateImpl*. The other methods can be +called outsize; e. g. *sizeRequest* is called in +dw::Textblock::addWidget. + +To avoid painful debugging, there are some tests for the cases that +one method call is strictly forbidden while another method is called. + +This could be done furthermore: + +- The tests could be refined. +- Is it possible to define exacter rules, along with a proof that no + problems (like endless recursion) can occur? + + +See also +======== + +- \ref dw-grows + +*/ diff --git a/devdoc/fltk-problems.doc b/devdoc/fltk-problems.doc new file mode 100644 index 00000000..df4f1f14 --- /dev/null +++ b/devdoc/fltk-problems.doc @@ -0,0 +1,180 @@ +/** \page fltk-problems Problems with FLTK + +

dw::fltk::FltkViewport

+ +Current problems: + +
    +
  • How should dw::fltk::FltkViewport::cancelQueueDraw be implemented? + +
  • If the value of a scrollbar is changed by the program, not the user, + the callback seems not to be called. Can this be assured? + +
  • The same for dw::fltk::FltkViewport::layout? + +
  • Also, the problems with the widgets seems to work. Also sure? + +
  • When drawing, clipping of 32 bit values is not working properly. + +
  • The item group within a selection widget (menu) should not be selectable. +
+ + +

dw::fltk::FltkPlatform

+ +
    +
  • There is the problem, that fltk::font always returns a font, the + required one, or a replacements. The latter is not wanted in all + cases, e.g. when several fonts are tested. Perhaps, this could be + solved by searching in the font list. [This was true of fltk2. + What is the state of font handling now with fltk-1.3?] + +
  • Distinction between italics and oblique would be nice + (dw::fltk::FltkFont::FltkFont). +
+ + +

dw::fltk::ui::FltkCheckButtonResource

+ +Groups of Fl_Radio_Button must be added to one Fl_Group, which is +not possible in this context. There are two alternatives: + +
    +
  1. there is a more flexible way to group radio buttons, or +
  2. radio buttons are not grouped, instead, grouping (especially + unchecking other buttons) is done by the application. +
+ +(This is mostly solved.) + +

dw::fltk::FltkImgbuf

+ +Alpha transparency should be best abstracted by FLTK itself. If not, +perhaps different implementations for different window systems could +be used. Then, it is for X necessary to use GCs with clipping masks. + + +

dw::fltk::ui::ComplexButton

+ +Unfortunately, FLTK does not provide a button with Fl_Group as parent, so +that children may be added to the button. dw::fltk::ui::ComplexButton does +exactly this, and is, in an ugly way, a modified copy of the FLTK +button. + +It would be nice, if this is merged with the standard FLTK +button. Furthermore, setting the type is strange. + +If the files do not compile, it may be useful to create a new one from +the FLTK source: + +
    +
  1. Copy Fl_Button.H from FLTK to dw/fltkcomplexbutton.hh and + src/Button.cxx to dw/fltkcomplexbutton.cc. + +
  2. In both files, rename "Button" to "ComplexButton". Automatic replacing + should work. + +
  3. Apply the changes below. +
+ +The following changes should be applied manually. + +

Changes in fltkcomplexbutton.hh

+ +First of all, the \#define's for avoiding multiple includes: + +\code +-#ifndef fltk_ComplexButton_h // fltk_Button_h formerly +-#define fltk_ComplexButton_h ++#ifndef __FLTK_COMPLEX_BUTTON_HH__ ++#define __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the beginning and + +\code +-#endif ++#endif // __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the end. Then, the namespace is changed: + +\code +-namespace fltk { ++namespace dw { ++namespace fltk { ++namespace ui { +\endcode + +at the beginning and + +\code +-} ++} // namespace ui ++} // namespace fltk ++} // namespace dw +\endcode + +at the end. Most important, the base class is changed: + +\code +-#include "FL/Fl_Widget.H" ++#include +\endcode + +and + +\code +-class FL_API ComplexButton : public Fl_Widget { ++class ComplexButton: public Fl_Group ++{ +\endcode + +Finally, for dw::fltk::ui::ComplexButton::default_style, there is a +namespace conflict: + +\code +- static NamedStyle* default_style; ++ static ::fltk::NamedStyle* default_style; +\endcode + +

Changes in fltkcomplexbutton.cc

+ +First, \#include's: + +\code + + #include +-#include // formerly + #include + #include ++ ++#include "fltkcomplexbutton.hh" +\endcode + +Second, namespaces: + +\code ++using namespace dw::fltk::ui; +\endcode + +Since the base class is now Fl_Group, the constructor must be changed: + +\code +-ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : Fl_Widget(x,y,w,h,l) { ++ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : ++ Fl_Group(x,y,w,h,l) ++{ +\endcode + +Finally, the button must draw its children (end of +dw::fltk::ui::ComplexButton::draw()): + +\code ++ ++ for (int i = children () - 1; i >= 0; i--) ++ draw_child (*child (i)); + } +\endcode + +*/ diff --git a/devdoc/index.doc b/devdoc/index.doc new file mode 100644 index 00000000..59de8cd8 --- /dev/null +++ b/devdoc/index.doc @@ -0,0 +1,48 @@ +/** \mainpage + +

Overview

+ +This is a list of documents to start with: + +
    +
  • \ref lout +
  • \ref dw-overview (map at \ref dw-map) +
+ +Currently, a document \ref fltk-problems is maintained, ideally, it +will be removed soon. + +

Historical

+ +

Replacements for GTK+ and GLib

+ +There are several classes etc., which are used for tasks formerly (in the GTK+ +version of dillo) achieved by GtkObject (in 1.2.x, this is part of Gtk+) and +GLib. For an overview on all this, take a look at \ref lout. + +GtkObject is replaced by the following: + +
    +
  • lout::object::Object is a common base class for many classes used + dillo. In the namespace lout::object, there are also some more common + classes and interfaces. + +
  • A sub class of lout::object::Object is + lout::identity::IdentifiableObject, which allows to determine the + class at run-time (equivalent to GTK_CHECK_CAST in GtkObject). + +
  • For signals, there is the namespace lout::signal. +
+ +Hash tables, linked lists etc. can be found in the lout::container namespace, +several useful macros from GLib have been implemented as inline functions +in the lout::misc namespace. + +As an alternative to the macros defined in list.h, there is also a template +class, lout::misc::SimpleVector, which does the same. + +

Changes in Dw

+ +If you have been familiar with Dw before, take a look at \ref dw-changes. + +*/ diff --git a/devdoc/lout.doc b/devdoc/lout.doc new file mode 100644 index 00000000..4e1503c6 --- /dev/null +++ b/devdoc/lout.doc @@ -0,0 +1,95 @@ +/** \page lout Lots of Useful Tools + +In the "lout" directory, there are some common base functionality for +C++. Most is described as doxygen comments, this text gives an +overview. + +

Common Base Class

+ +Many classes are derived from lout::object::Object, which defines some +general methods. See there for more information. + +For the case, that you need primitive C++ types, there are some +wrappers: + + +
C++ Type Wrapper Class +
void* lout::object::Pointer +
specific pointer lout::object::TypedPointer (template class) +
int lout::object::Integer +
const char* lout::object::ConstString +
char* lout::object::String +
+ + +

Containers

+ +In the namespace lout::container, several container classes are defined, +which all deal with instances of lout::object::Object. + +

Untyped Containers

+ +In lout::container::untyped, there are the following containers: + +
    +
  • lout::container::untyped::Vector, a dynamically increases array, +
  • lout::container::untyped::List, a linked list, +
  • lout::container::untyped::HashTable, a hash table, and +
  • lout::container::untyped::Stack, a stack. +
+ +All provide specific methods, but since they have a common base class, +lout::container::untyped::Collection, they all provide iterators, by the +method lout::container::untyped::Collection::iterator. + +

Typed Containers

+ +lout::container::typed provides wrappers for the container classes defined +in lout::container::untyped, which are more type safe, by using C++ +templates. + + +

Signals

+ +For how to connect objects at run-time (to reduce dependencies), take a +look at the lout::signal namespace. + +There is also a base class lout::signal::ObservedObject, which implements +signals for deletion. + + +

Debugging

+ +In debug.hh, there are some some useful macros for debugging messages, +see the file for mor informations. + + +

Identifying Classes at Runtime

+ +If the class of an object must be identified at runtime, +lout::identity::IdentifiableObject should be used as the base class, +see there for more details. + + +

Miscellaneous

+ +The lout::misc namespace provides several miscellaneous stuff: + +
    +
  • In some contexts, it is necessary to compare objects + (less/greater), for this, also lout::misc::Comparable must be + implemented. For example., lout::container::untyped::Vector::sort and + lout::container::typed::Vector::sort cast the elements to + lout::misc::Comparable. This can be mixed with lout::object::Object. +
  • lout::misc::SimpleVector, a simple, template based vector class + (not depending on lout::object::Object) (a variant for handling a + special case in an efficient way is lout::misc::NotSoSimpleVector), +
  • lout::misc::StringBuffer, class for fast concatenation of a large number + of strings, +
  • lout::misc::BitSet implements a bitset. +
  • useful (template) functions (lout::misc::min, lout::misc::max), and +
  • some functions useful for runtime checks (lout::misc::assert, + lout::misc::assertNotReached). +
+ +*/ diff --git a/devdoc/not-so-simple-container.png b/devdoc/not-so-simple-container.png new file mode 100644 index 00000000..0af067b5 Binary files /dev/null and b/devdoc/not-so-simple-container.png differ diff --git a/devdoc/rounding-errors.doc b/devdoc/rounding-errors.doc new file mode 100644 index 00000000..a442033e --- /dev/null +++ b/devdoc/rounding-errors.doc @@ -0,0 +1,35 @@ +/** \page rounding-errors How to Avoid Rounding Errors + +(Probably, this is a standard algorithm, so if someone knows the name, +drop me a note.) + +If something like + +\f[y_i = {x_i a \over b}\f] + +is to be calculated, and all numbers are integers, a naive +implementation would result in something, for which + +\f[\sum y_i \ne {(\sum x_i) a \over b}\f] + +because of rounding errors, due to the integer division. This can be +avoided by transforming the formula into + +\f[y_i = {(\sum_{j=0}^{j=i} x_j) a \over b} - \sum_{j=0}^{j=i-1} y_j\f] + +Of corse, when all \f$y_i\f$ are calculated in a sequence, +\f$\sum_{j=0}^{j=i} x_j\f$ and \f$\sum_{j=0}^{j=i-1} y_j\f$ can be +accumulated in the same loop. Regard this as sample: + +\code +int n, x[n], a, b; // Should all be initialized. +int y[n], cumX = 0, cumY = 0; + +for (int i = 0; i < n; i++) { + cumX += x[i] + y[i] = (cumX * a) / b - cumY; + cumY += y[i]; +} +\endcode + +*/ diff --git a/devdoc/uml-legend.doc b/devdoc/uml-legend.doc new file mode 100644 index 00000000..54004ccd --- /dev/null +++ b/devdoc/uml-legend.doc @@ -0,0 +1,195 @@ +/** \page uml-legend UML Legend + +This page describes the notation for several diagrams used in the +documentation, which is a slight variation of UML. + + +

Classes

+ +Classes are represented by boxes, containing there names: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + fontname=Helvetica; fontsize=8; + "Concrete Class"; + "Abstract Class" [color="#a0a0a0"]; + Interface [color="#ff8080"]; +} +\enddot + +(In most cases, the attributes and operations are left away, for +better readibility. Just click on it, to get to the detailed +description.) + +Of course, in C++, there are no interfaces, but here, we call a class, +which has only virtual abstract methods, and so does not provide any +functionality, an interface. + +Templates get a yellow background color: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10, + fillcolor="#ffffc0", style="filled"]; + fontname=Helvetica; fontsize=8; + "Concrete Class Template"; + "Abstract Class Template" [color="#a0a0a0"]; + "Interface Template" [color="#ff8080"]; +} +\enddot + + +

Objects

+ +In some cases, an examle for a concrete constellation of objects is +shown. An object is represented by a box containing a name and the +class, separated by a colon. + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "x: A" -> "y1: B"; + "x: A" -> "y2: B"; +} +\enddot + +The names (\em x, \em y, and \em z) are only meant within the context +of the diagram, there needs not to be a relation to the actual names +in the program. They should be unique within the diagram. + +Classes and objects may be mixed in one diagram. + + +

Associations

+ +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080", + fontname=Helvetica, fontsize=10, fontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A -> B [headlabel="*", taillabel="1", label="x"]; +} +\enddot + +In this example, one instance of A refers to an arbitrary number of B +instances (denoted by the "*"), and each instance of B is referred by +exactly one ("1") A. The label \em x is the name of the association, +in most cases the name of the field, e.g. A::x. + +Possible other values for the \em multiplicity: + +
    +
  • a concrete number, in most cases "1", +
  • a range, e.g. "0..1", +
  • "*", denoting an arbitrary number. +
+ + +

Implementations and Inheritance

+ +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", dir="both", arrowtail="empty", + labelfontname=Helvetica, labelfontsize=10, color="#404040", + labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A[color="#ff8080"]; + B[color="#ff8080"]; + C; + D; + A -> B; + A -> C [style="dashed"]; + C -> D; +} +\enddot + +In this example, + +
    +
  • the interface B extends the interface A, +
  • the class C implements the interface A, and +
  • the class D extends the class C. +
+ + +

Template Instantiations

+ +Template instantiations are shown as own classes/interfaces, the +instantiation by the template is shown by a yellow dashed arrow: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", dir="both", + labelfontname=Helvetica, labelfontsize=10, color="#404040", + labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + A[color="#ff8080"]; + B[color="#ff8080"]; + C[color="#ff8080", fillcolor="#ffffc0", style="filled"]; + C_A[color="#ff8080", label="C \"]; + C_B[color="#ff8080", label="C \"]; + D; + + C -> C_A [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + C -> C_B [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + A -> C_A; + B -> C_B; + C_A -> D [style="dashed"]; +} +\enddot + +In this example, the interface template C uses the template argument +as super interface. + + +

Packages

+ +Packages are presented by dashed rectangles: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", dir="both", + labelfontname=Helvetica, labelfontsize=10, color="#404040", + labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + subgraph cluster_1 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 1"; + + A; + B [color="#a0a0a0"]; + } + + subgraph cluster_2 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 2"; + + C; + D [color="#a0a0a0"]; + E + } + + A -> C; + B -> D; + D -> E; + E -> A [arrowhead="open", arrowtail="none"]; +} +\enddot + +Packages may be nested. + +*/ \ No newline at end of file diff --git a/doc/CCCwork.txt b/doc/CCCwork.txt deleted file mode 100644 index 1ea5d20e..00000000 --- a/doc/CCCwork.txt +++ /dev/null @@ -1,153 +0,0 @@ -Last review: August 04, 2009 --jcid - - ----------------------------- -Internal working for the CCC ----------------------------- - - -HTTP protocol -------------- - - - Query: | - . - 1B --> 1B 1B --> 1B --> | -------------. - .----. .----. .----. . | -I |Capi| |http| | IO | | | - '----' '----' '----' . | - 1F <-- 1F 1F <-- 1F | V - . - | [Server] - Answer: . - - 2B --> 2B 2B --> 2B | | - .----. .----. .----. . | -II |Capi| |Dpi | | IO | | | - '----' '----' '----' . | - 2F <-- 2F 2F <-- 2F <-- | <------------' - . - | - -* a_Capi_open_url() builds both the Answer and Query chains at -once (Answer first then Query), to ensure a uniform structure -that avoids complexity (e.g. race conditions). - -* Http_get() sets a callback for the DNS hostname resolve. -Normally it comes later, but may also by issued immediately if -the hostname is cached. - -* The socket FD is passed by means of OpSend by the http module -once the remote IP is known and the socket is connected. - - - -Function calls for HTTP CCC ---------------------------- - - a_Capi_open_url - if (reload) - Capi OpStart 2B (answer) [Capi] --> [dpi] --> [IO] - Capi OpStart 1B (query) [Capi] --> [http] --> [IO] - Http_get - a_Cache_open_url - if URL_E2EReload -> prepare reload - if cached - client enqueue - delayed process queue - else - Cache_entry_add - client enqueue - - -//-> - a_Http_dns_cb - Http_connect_socket - OpSend FD, BCK - OpSend FD, FWD - Http_send_query - a_Http_make_query_str - OpSend, BCK - IO_submit - a_IOwatch_add_fd (DIO_WRITE, ...) - - - Note about 'web' structures. They're created using a_Web_new(). -The web.c module keeps a list of valid webs, so anytime you're -unsure of a weak reference to 'web', it can be checked with -a_Web_valid(web). - - - ------------- -Dpi protocol ------------- - - - Query: | - . - 1B --> 1B 1B --> 1B --> | -------------. - .----. .----. .----. . | -I |Capi| |Dpi | | IO | | | - '----' '----' '----' . | - 1F <-- 1F 1F <-- 1F | V - . - | [Server] - . - Answer (same as HTTP): | | - . | - 2B --> 2B 2B --> 2B | | - .----. .----. .----. . | -II |Capi| |Dpi | | IO | | | - '----' '----' '----' . | - 2F <-- 2F 2F <-- 2F <-- | <------------' - . - | - - -CCC Construction: - - a_Capi_open_url() calls a_Capi_dpi_send_cmd() when the URL -belongs to a dpi and it is not cached. - - a_Capi_dpi_send_cmd() builds both the Answer and Query chains -at once (Answer first then Query), in the same way as HTTP does. -Note that the answer chain is the same for both, and the query -chain only differs in the module in the middle ([http] or [dpi]). - - -Function calls for DPI CCC --------------------------- - - a_Capi_open_url - a_Capi_dpi_send_cmd - Capi OpStart 2B (answer) [Capi] --> [dpi] --> [IO] - Capi OpStart 1B (query) [Capi] --> [http] --> [IO] - a_Cache_open_url - [...] - - -Normal termination: - - When the dpi server is done, it closes the FD, and OpEnd flows -from IO to Capi (answer branch). When in Capi, capi propagates -OpEnd to the query branch. - -Abnormal termination: - - The transfer may be aborted by a_Capi_conn_abort_by_url(). The -OpAbort is not yet standardized and has an ad-hoc implementation. -One idea is to have OpAbort always propagate BCK and then FWD and -to jump into the other chain when it gets to [Capi]. - - -Debugging CCC -------------- - - A simple way to "look" inside it, is to "#define VERBOSE 1" in -chain.c, and then to follow its work with a printed copy of the -diagrams in this document. - - Each new data request generates a CCC, so if you want to debug, -it's good to refine the testcase to the minimum possible number -of connections. - diff --git a/doc/Cache.txt b/doc/Cache.txt deleted file mode 100644 index 4e885df2..00000000 --- a/doc/Cache.txt +++ /dev/null @@ -1,166 +0,0 @@ - June 2000, --Jcid - Last update: Jul 09 - - ------- - CACHE - ------- - - The cache module is the main abstraction layer between -rendering and networking. - - The capi module acts as a discriminating wrapper which either -calls the cache or the dpi routines depending on the type of -request. - - Every URL must be requested using a_Capi_open_url, which -sends the request to the cache if the data is cached, to dillo's -http module for http: URLs, and through dillo's DPI system for -other URLs. - - Here we'll document non dpi requests. - - - ---------------- - CACHE PHILOSOPHY - ---------------- - - Dillo's cache is very simple; every single resource that's -retrieved (URL) is kept in memory. NOTHING is saved to disk. -This is mainly for three reasons: - - - Dillo encourages personal privacy and it assures there'll be -no recorded tracks of the sites you visited. - - - The Network is full of intermediate transparent proxys that -serve as caches. - - - If you still want to have cached stuff, you can install an -external cache server (such as WWWOFFLE), and benefit from it. - - - --------------- - CACHE STRUCTURE - --------------- - - Currently, dillo's cache code is spread in different sources: -mainly in cache.[ch], dicache.[ch] and it uses some other -functions from mime.c and web.cc. - - Cache.c is the principal source, and it also is the one -responsible for processing cache-clients (held in a queue). -Dicache.c is the interface to the decompressed RGB representations -of currently-displayed images held in DW's imgbuf. - - mime.c and web.cc are used for secondary tasks such as -assigning the right "viewer" or "decoder" for a given URL. - - ----------------- -A bit of history ----------------- - - Some time ago, the cache functions, URL retrieval and -external protocols were a whole mess of mixed code, and it was -getting REALLY hard to fix, improve or extend the functionality. -The main idea of this "layering" is to make code-portions as -independent as possible so they can be understood, fixed, -improved or replaced without affecting the rest of the browser. - - An interesting part of the process is that, as resources are -retrieved, the client (dillo in this case) doesn't know the -Content-Type of the resource at request-time. It only becomes known -when the resource header is retrieved (think of http). This -happens when the cache has control, so the cache sets the -proper viewer for it (unless the Callback function was already -specified with the URL request). - - You'll find a good example in http.c. - - Note: All resources received by the cache have HTTP-style headers. - The file/data/ftp DPIs generate these headers when sending their - non-HTTP resources. Most importantly, a Content-Type header is - generated based on file extension or file contents. - - -------------- -Cache clients -------------- - - Cache clients MUST use a_Capi_open_url to request an URL. The -client structure and the callback-function prototype are defined, -in cache.h, as follows: - -struct _CacheClient { - int Key; /* Primary Key for this client */ - const DilloUrl *Url; /* Pointer to a cache entry Url */ - int Version; /* Dicache version of this Url (0 if not used) */ - void *Buf; /* Pointer to cache-data */ - uint_t BufSize; /* Valid size of cache-data */ - CA_Callback_t Callback; /* Client function */ - void *CbData; /* Client function data */ - void *Web; /* Pointer to the Web structure of our client */ -}; - -typedef void (*CA_Callback_t)(int Op, CacheClient_t *Client); - - - Notes: - - * Op is the operation that the callback is asked to perform - by the cache. { CA_Send | CA_Close | CA_Abort }. - - * Client: The Client structure that originated the request. - - - --------------------------- -Key-functions descriptions --------------------------- - -································································ -int a_Cache_open_url(void *Web, CA_Callback_t Call, void *CbData) - - if Web->url is not cached - Create a cache-entry for that URL - Send client to cache queue - else - Feed our client with cached data - -································································ - ----------------------- -Redirections mechanism - (HTTP 30x answers) ----------------------- - - This is by no means complete. It's a work in progress. - - Whenever an URL is served under an HTTP 30x header, its cache -entry is flagged with 'CA_Redirect'. If it's a 301 answer, the -additional 'CA_ForceRedirect' flag is also set, if it's a 302 -answer, 'CA_TempRedirect' is also set (this happens inside the -Cache_parse_header() function). - - Later on, in Cache_process_queue(), when the entry is flagged -with 'CA_Redirect' Cache_redirect() is called. - - - - - - - ------------ -Notes ------------ - - The whole process is asynchronous and very complex. I'll try -to document it in more detail later (source is commented). - Currently I have a drawing to understand it; hope the ASCII -translation serves the same as the original. - If you're planning to understand the cache process thoroughly, -write me a note and I will assign higher priority to further -improvement of this doc. - Hope this helps! - - diff --git a/doc/Dillo.txt b/doc/Dillo.txt deleted file mode 100644 index a63c9588..00000000 --- a/doc/Dillo.txt +++ /dev/null @@ -1,96 +0,0 @@ -"Eliminate the guesswork and quality goes up." - - - ------- - DILLO - ------- - - These notes are written with a view to make it less hard, not -easier yet ;), to get into Dillo development. - When I first got into it, I was totally unaware of the browser -internals. Now that I've made my way deep into the core of it, -(we rewrote it 90% and modified the rest), is time to write some -documentation, just to make a less steep learning curve for new -developers. - - --Jcid - - - - -------- - OVERVIEW - -------- - - Dillo can be viewed as the sum of five main parts: - - 1.- Dillo Widget: A custom widget, FLTK-based, that holds the -necessary data structures and mechanisms for graphical rendering. -(Described in Dw*.txt, dw*.c files among the sources.) - - 2.- Dillo Cache: Integrated with a signal driven Input/Output -engine that handles file descriptor activity, the cache acts as -the main abstraction layer between rendering and networking. - Every URL, whether cached or not, must be retrieved using -a_Capi_open_url (Described briefly in Cache.txt, source -contained in capi.c). - IO is described in IO.txt (recommended), source in src/IO/. - - 3.- The HTML parser: A streamed parser that joins the Dillo -Widget and the Cache functionality to make browsing possible -(Described in HtmlParser.txt, source mainly inside html.cc). - - 4.- Image processing code: The part that handles image -retrieval, decoding, caching and displaying. (Described in -Images.txt. Sources: image.c, dw/image.cc, dicache.c, gif.c, -jpeg.c and png.c) - - 5.- The dpi framework: a gateway to interface the browser with -external programs (Example: the bookmarks server plugin). -Dpi spec: http://www.dillo.org/dpi1.html - - - ------------------------- - HOW IS THE PAGE RENDERED? - ------------------------- - -(A short description of the internal function calling process) - - When the user requests a new URL, a_UIcmd_open_url -is queried to do the job; it calls a_Nav_push (The highest level -URL dispatcher); a_Nav_push updates current browsing history and -calls Nav_open_url. Nav_open_url closes all open connections by -calling a_Bw_stop_clients, and then calls -a_Capi_open_url which calls a_Cache_open_url (or the dpi module if -this gateway is used). - - If Cache_entry_search hits (due to a cached url :), the client is -fed with cached data, but if the URL isn't cached yet, a new CCC -(Concomitant Control Chain) is created and committed to fetch the -URL. - - The next CCC link is dynamically assigned by examining the -URL's protocol. It can be a_Http_ccc or a_Dpi_ccc. - - If we have an HTTP URL, a_Http_ccc will succeed, and the http -module will be linked; it will create the proper HTTP query and -link the IO module to submit and deliver the answer. - - Note that as the Content-Type of the URL is not always known -in advance, the answering branch decides where to dispatch it to -upon HTTP header arrival. - - - What happens then? - - Well, the html parser gets fed, and proper functions are -called for each tag (to parse and call the appropriate methods) -and the whole page is contructed in a streamed way. - Somewhere in the middle of it, resize and repaint functions -are activated and idle functions draw to screen what has been -processed. - - (The process for images is described in Images.txt) - - - - diff --git a/doc/Dpid.txt b/doc/Dpid.txt deleted file mode 100644 index 6c418f57..00000000 --- a/doc/Dpid.txt +++ /dev/null @@ -1,331 +0,0 @@ -Aug 2003, Jorge Arellano Cid, - Ferdi Franceschini -- -Last update: Nov 2009 - - - ------ - dpid - ------ - -------------- -Nomenclature: -------------- - - dpi: - generic term referring to dillo's plugin system (version1). - - dpi1: - specific term for dillo's plugin spec version 1. - at: http://www.dillo.org/dpi1.html - - dpi program: - any plugin program itself. - - dpi framework: - the code base inside and outside dillo that makes dpi1 - working possible (it doesn't include dpi programs). - - dpip: - dillo plugin protocol. The HTML/XML like set of command tags - and information that goes inside the communication sockets. - Note: not yet fully defined, but functional. - Note2: it was designed to be extensible. - - dpid: - dillo plugin daemon. - - server plugin: - A plugin that is capable of accepting connections on a socket. Dpid will - never run more than one instance of a server plugin at a time. - - filter plugin: - A dpi program that reads from stdin and writes to stdout, and that - exits after its task is done (they don't remain as server plugins). - Warning, dpid will run multiple instances of filter plugins if requested. - ------------ -About dpid: ------------ - - * dpid is a program which manages dpi connections. - * dpid is a daemon that serves dillo using IDS sockets. - * dpid launches dpi programs and arranges socket communication - between the dpi program and dillo. - - The concept and motivation is similar to that of inetd. The -plugin manager (dpid) listens for a service request on a socket -and returns the socket/port pair of a plugin that handles the -service. It also watches sockets of inactive plugins and starts -them when a connection is requested. - - ------------------------------------------------------------ -What's the problem with managing dpi programs inside dillo? ------------------------------------------------------------ - - That's the other way to handle it, but it started to show some -problems (briefly outlined here): - - * When having two or more running instances of Dillo, one - should prevail, and take control of dpi managing (but all - dillos carry the managing code). - * If the managing-dillo exits, it must pass control to another - instance, or leave it void if there's no other dillo running! - * The need to synchronize all the running instances of - dillo arises. - * If the controlling instance finishes and quits, all the - dpi-program PIDs are lost. - * Terminating hanged dpis is hard if it's not done with signals - (PIDs) - * Forks can be expensive (Dillo had to fork its dpis). - * When a managing dillo exits, the new one is no longer the - parent of the forked dpis. - * If Unix domain sockets for the dpis were to be named - randomly, it gets very hard to recover their names if the - controlling instance of dillo exits and another must "take - over" the managing. - * It increments dillo's core size. - * If dillo hangs/crashes, dpi activity is lost (e.g. downloads) - * ... - - That's why the managing daemon scheme was chosen. - - ----------------------- -What does dpid handle? ----------------------- - - It solves all the above mentioned shortcomings and also can do: - - * Multiple dillos: - dpid can communicate and serve more than one instance - of dillo. - - * Multiple dillo windows: - two or more windows of the same dillo instance accessing dpis - at the same time. - - * Different implementations of the same service - dpi programs ("dpis") are just an implementation of a - service. There's no problem in implementing a different one - for the same service (e.g. downloads). - - * Upgrading a service: - to a new version or implementation without requiring - patching dillo's core or even bringing down the dpid. - - - And finally, being aware that this design can support the -following functions is very helpful: - - SCHEME Example - ------------------------------------------------------------ - * "one demand/one response" man, preferences, ... - * "resident while working" downloads, mp3, ... - * "resident until exit request" bookmarks, ... - - * "one client only" cd burner, ... - * "one client per instance" man, ... - * "multiple clients/one instance" downloads, cookies ... - - --------- -Features --------- - * Dpi programs go in: "EPREFIX/dillo/dpi" or "~/.dillo/dpi". The binaries - are named .dpi as "bookmarks.dpi" and .filter.dpi as in - "hello.filter.dpi". The ".filter" plugins simply read from stdin - and write to stdout. - * Register/update/remove dpis from list of available dpis when a - 'register_all' command is received. - * dpid terminates when it receives a 'DpiBye' command. - * dpis can be terminated with a 'DpiBye' command. - * dpidc control program for dpid, currently allows register and stop. - - ------ -todo: ------ - - These features are already designed, waiting for implementation: - - * dpidc remove // May be not necessary after all... - - ------------------ -How does it work? ------------------ - -o on startup dpid reads dpidrc for the path to the dpi directory - (usually EPREFIX/lib/dillo/dpi). ~/.dillo/dpi is scanned first. - -o both directories are scanned for the list of available plugins. - ~/.dillo/dpi overrides system-wide dpis. - -o next it creates internet domain sockets for the available plugins and - then listens for service requests on its own socket, - and for connections to the sockets of inactive plugins. - -o dpid returns the port of a plugin's socket when a client (dillo) - requests a service. - -o if the requested plugin is a 'server' then - 1) dpid stops watching the socket for activity - 2) forks and starts the plugin - 3) resumes watching the socket when the plugin exits - -o if the requested plugin is a 'filter' then - 1) dpid accepts the connection - 2) maps the socket fd to stdin/stdout (with dup2) - 3) forks and starts the plugin - 4) continues to watch the socket for new connections - - - - ---------------------------- -dpi service process diagram ---------------------------- - - These drawings should be worth a thousand words! :) - - -(I) - .--- s1 s2 s3 ... sn - | - [dpid] [dillo] - | - '--- srs - - The dpid is running listening on several sockets. - - -(II) - .--- s1 s2 s3 ... sn - | - [dpid] [dillo] - | | - '--- srs ------------------' - - dillo needs a service so it connects to the service request - socket of the dpid (srs) and asks for the socket name of the - required plugin (using dpip). - - -(III) - .--- s1 s2 s3 ... sn - | | - [dpid] | [dillo] - | | | - '--- srs '---------------' - - then it connects to that socket (s3, still serviced by dpid!) - - -(IV) - .--- s1 s2 s3 ... sn - | | - .[dpid] | [dillo] - . | | | - . '--- srs '---------------' - . - .............[dpi program] - - when s3 has activity (incoming data), dpid forks the dpi - program for it... - - -(V) - .--- s1 s2 (s3) ... sn - | - [dpid] [dillo] - | | - '--- srs .---------------' - | - [dpi program] - - ... and lets it "to take over" the socket. - - Once there's a socket channel for dpi and dillo, the whole -communication process takes place until the task is done. When -the dpi program exits, dpid resumes listening on the socket (s3). - - --------------------------------- -So, how do I make my own plugin? --------------------------------- - - Maybe the simplest way to get started is to understand a few -concepts and then to use the hands-on method by using/modifying -the hello dpi. It's designed as an example to get developers -started. - - --------- - Concepts: - --------- - - * Dillo plugins work by communicating two processes: dillo - and the dpi. - * The underlying protocol (DPIP) has a uniform API which is - powerful enough for both blocking and nonblocking IO, and - filter or server dpis. - * The simplest example is one-request one-answer (for example - dillo asks for a URL and the dpi sends it). You'll find - this and more complex examples in hello.c - - First, you should get familiar with the hello dpi as a user: - - $dillo dpi:/hello/ - - Once you've played enough with it, start reading the well -commented code in hello.c and start making changes! - - - --------------- - Debugging a dpi - --------------- - - The simplest way is to add printf-like feedback using the MSG* -macros. You can start the dpid by hand on a terminal to force -messages to go there. Filter dpis use sdterr and server dpis -stdout. - - Sometimes more complex dpis need more than MSG*. In this case -you can use gdb like this. - - 1.- Add an sleep(20) statement just after the dpi starts. - 2.- Start dillo and issue a request for your dpi. This will - get your dpi started. - 3.- Standing in the dpi source directory: - ps aux|grep dpi - 4.- Take note of the dpi's PID and start gdb, then: - (gdb) attach - 5.- Continue from there... - - - ------------ - Final Notes: - ------------ - - 1.- If you already understand the hello dpi and want to try -something more advanced: - - * bookmarks.c is a good example of a blocking server - * file.c is an advanced example of a server handling multiple - non-blocking connections with select(). - - 2.- Multiple instances of a filter plugin may be run -concurrently, this could be a problem if your plugin records data -in a file, however it is safe if you simply write to stdout. -Alternatively you could write a 'server' plugin instead as they -are guaranteed not to run concurrently. - - 3.- The hardest part is to try to modify the dpi framework code -inside dillo; you have been warned! It already supports a lot of -functionality, but if you need to do some very custom stuff, try -extending the "chat" command, or asking in dillo-dev. - - - - >>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< - diff --git a/doc/Dw.txt b/doc/Dw.txt deleted file mode 100644 index f6909380..00000000 --- a/doc/Dw.txt +++ /dev/null @@ -1,11 +0,0 @@ -Last update: Oct 2008 - -================ -Dw: Dillo Widget -================ - -Dw is the internal widget library for rendering HTML. It has excellent -documentation. - - Just run "doxygen" and browse the html/ directory! - diff --git a/doc/HtmlParser.txt b/doc/HtmlParser.txt deleted file mode 100644 index 2eb8be63..00000000 --- a/doc/HtmlParser.txt +++ /dev/null @@ -1,124 +0,0 @@ - October 2001, --Jcid - Last update: Jul 2009 - - --------------- - THE HTML PARSER - --------------- - - - Dillo's parser is more than just a HTML parser, it does XHTML -and plain text also. It has parsing 'modes' that define its -behaviour while working: - - typedef enum { - DILLO_HTML_PARSE_MODE_INIT = 0, - DILLO_HTML_PARSE_MODE_STASH, - DILLO_HTML_PARSE_MODE_STASH_AND_BODY, - DILLO_HTML_PARSE_MODE_BODY, - DILLO_HTML_PARSE_MODE_VERBATIM, - DILLO_HTML_PARSE_MODE_PRE - } DilloHtmlParseMode; - - - The parser works upon a token-grained basis, i.e., the data -stream is parsed into tokens and the parser is fed with them. The -process is simple: whenever the cache has new data, it is -passed to Html_write, which groups data into tokens and calls the -appropriate functions for the token type (tag, space, or word). - - Note: when in DILLO_HTML_PARSE_MODE_VERBATIM, the parser -doesn't try to split the data stream into tokens anymore; it -simply collects until the closing tag. - ------- -TOKENS ------- - - * A chunk of WHITE SPACE --> Html_process_space - - - * TAG --> Html_process_tag - - The tag-start is defined by two adjacent characters: - - first : '<' - second: ALPHA | '/' | '!' | '?' - - Note: comments are discarded ( ) - - - The tag's end is not as easy to find, nor to deal with!: - - 1) The HTML 4.01 sec. 3.2.2 states that "Attribute/value - pairs appear before the final '>' of an element's start tag", - but it doesn't define how to discriminate the "final" '>'. - - 2) '<' and '>' should be escaped as '<' and '>' inside - attribute values. - - 3) The XML SPEC for XHTML states: - AttrValue ::== '"' ([^<&"] | Reference)* '"' | - "'" ([^<&'] | Reference)* "'" - - Current parser honors the XML SPEC. - - As it's a common mistake for human authors to mistype or - forget one of the quote marks of an attribute value; the - parser solves the problem with a look-ahead technique - (otherwise the parser could skip significant amounts of - properly-written HTML). - - - - * WORD --> Html_process_word - - A word is anything that doesn't start with SPACE, that's - outside of a tag, up to the first SPACE or tag start. - - SPACE = ' ' | \n | \r | \t | \f | \v - - ------------------ -THE PARSING STACK ------------------ - - The parsing state of the document is kept in a stack: - - class DilloHtml { - [...] - lout::misc::SimpleVector *stack; - [...] - }; - - struct _DilloHtmlState { - CssPropertyList *table_cell_props; - DilloHtmlParseMode parse_mode; - DilloHtmlTableMode table_mode; - bool cell_text_align_set; - DilloHtmlListMode list_type; - int list_number; - - /* TagInfo index for the tag that's being processed */ - int tag_idx; - - dw::core::Widget *textblock, *table; - - /* This is used to align list items (especially in enumerated lists) */ - dw::core::Widget *ref_list_item; - - /* This is used for list items etc; if it is set to TRUE, breaks - have to be "handed over" (see Html_add_indented and - Html_eventually_pop_dw). */ - bool hand_over_break; - }; - - Basically, when a TAG is processed, a new state is pushed into -the 'stack' and its 'style' is set to reflect the desired -appearance (details in DwStyle.txt). - - That way, when a word is processed later (added to the Dw), all -the information is within the top state. - - Closing TAGs just pop the stack. - - diff --git a/doc/IO.txt b/doc/IO.txt deleted file mode 100644 index cd62a4f5..00000000 --- a/doc/IO.txt +++ /dev/null @@ -1,468 +0,0 @@ - -This is the updated base of a paper I wrote with Horst. -It provides a good introduction to Dillo's internals. -(Highly recommended if you plan to patch or develop in Dillo) - -It may not be exactly accurate (it's quite old), but it explains -the theory behind in some detail, so it's more than recommended -reading material. ---Jcid - - ------------------------------------------------------ -Parallel network programming of the Dillo web browser ------------------------------------------------------ - - Jorge Arellano-Cid - Horst H. von Brand - - --------- -Abstract --------- - - Network programs face several delay sources when sending or -retrieving data. This is particularly problematic in programs -which interact directly with the user, most notably web browsers. -We present a hybrid approach using threads communicated through -pipes and signal driven I/O, which allows a non-blocking main -thread and overlapping waiting times. - - ------------- -Introduction ------------- - - The Dillo project didn't start from scratch but mainly working -on the code base of gzilla (a light web browser written by Raph -Levien). As the project went by, the code of the whole source was -standardized, and the networking engine was replaced with a new, -faster design. Later, the parser was changed, the streamed -handling of data and its error control was put under the control -of the CCC (Concomitant Control Chain), and the old widget system -was replaced with a new one (Dw). The source code is currently -regarded as "very stable beta", and is available at -. Dillo is a project licensed under the GNU -General Public License. - - This paper covers basic design aspects of the hybrid approach -that the Dillo web browser uses to solve several latency -problems. After introducing the main delay-sources, the main -points of the hybrid design will be addressed. - - -------------- -Delay sources -------------- - - Network programs face several delay-sources while sending or -retrieving data. In the particular case of a web browser, they -are found in: - - DNS querying: - The time required to solve a name. - - Initiating the TCP connection: - The three way handshake of the TCP protocol. - - Sending the query: - The time spent uploading queries to the remote server. - - Retrieving data: - The time spent expecting and receiving the query answer. - - Closing the TCP connection: - The four packet-sending closing sequence of the TCP protocol. - - In a WAN context, every single item of this list has an -associated delay that is non deterministic and often measured in -seconds. If we add several connections per browsed page (each one -requiring at least the 4 last steps), the total latency can be -considerable. - - ------------------------------------ -The traditional (blocking) approach ------------------------------------ - - The main problems with the blocking approach are: - - When issuing an operation that can't be completed - immediately, the process is put to sleep waiting for - completion, and the program doesn't do any other - processing in the meantime. - - When waiting for a specific socket operation to complete, - packets that belong to other connections may be arriving, - and have to wait for service. - - Web browsers handle many small transactions, - if waiting times are not overlapped - the latency perceived by the user can be very annoying. - - If the user interface is just put to sleep during network - operations, the program becomes unresponsive, confusing - and perhaps alarming the user. - - Not overlapping waiting times and processing makes - graphical rendering (which is arguably the central function - of a browser) unnecessarily slow. - - ---------------------- -Dillo's hybrid design ---------------------- - - Dillo uses threads and signal driven I/O extensively to -overlap waiting times and computation. Handling the user -interface in a thread that never blocks gives a good interactive -``feel.'' The use of GTK+, a sophisticated widget framework for -graphical user interfaces, helped very much to accomplish this -goal. All the interface, rendering and I/O engine was built upon -its facilities. - - The design is said to be ``hybrid'' because it uses threads -for DNS querying and reading local files, and signal driven I/O -for TCP connections. The threaded DNS scheme is potentially -concurrent (this depends on underlying hardware), while the I/O -handling (both local files and remote connections) is -definitively parallel. - - To simplify the structure of the browser, local files are -encapsulated into HTTP streams and presented to the rest of the -browser as such, in exactly the same way a remote connection is -handled. To create this illusion, a thread is launched. This -thread opens a pipe to the browser, it then synthesizes an -appropriate HTTP header, sends it together with the file to the -browser proper. In this way, all the browser sees is a handle, -the data on it can come from a remote connection or from a local -file. - - To handle a remote connection is more complex. In this case, -the browser asks the cache manager for the URL. The name in the -URL has to be resolved through the DNS engine, a socket TCP -connection must be established, the HTTP request has to be sent, -and finally the result retrieved. Each of the steps mentioned -could give rise to errors, which have to be handled and somehow -communicated to the rest of the program. For performance reasons, -it is critical that responses are cached locally, so the remote -connection doesn't directly hand over the data to the browser; -the response is passed to the cache manager which then relays it -to the rest of the browser. The DNS engine caches DNS responses, -and either answers them from the cache or by querying the DNS. -Querying is done in a separate thread, so that the rest of the -browser isn't blocked by long waits here. - - The activities mentioned do not happen strictly in the order -stated above. It is even possible that several URLs are being -handled at the same time, in order to overlap waiting and -downloading. The functions called directly from the user -interface have to return quickly to maintain interactive -response. Sometimes they return connection handlers that haven't -been completely set up yet. As stated, I/O is signal-driven, when -one of the descriptors is ready for data transfer (reading or -writing), it wakes up the I/O engine. - - Data transfer between threads inside the browser is handled by -pipes, shared memory is little used. This almost obviates the -need for explicit synchronization, which is one of the main areas -of complexity and bugs in concurrent programs. Dillo handles its -threads in a way that its developers can think of it as running -on a single thread of control. This is accomplished by making the -DNS engine call-backs happen within the main thread, and by -isolating file loading with pipes. - - Using threads in this way has three big advantages: - - The browser doesn't block when one of its child threads - blocks. In particular, the user interface is responsive - even while resolving a name or downloading a file. - - Developers don't need to deal with complex concurrent - concerns. Concurrency is hard to handle, and few developers - are adept at this. This gives access a much larger pool of - potential developers, something which can be critical - in an open-source development project. - - By making the code mostly sequential, debugging the code - with traditional tools like gdb is possible. Debugging - parallel programs is very hard, and appropriate tools are - hard to come by. - - Because of simplicity and portability concerns, DNS querying -is done in a separate thread. The standard C library doesn't -provide a function for making DNS queries that don't block. The -alternative is to implement a new, custom DNS querying function -that doesn't block. This is certainly a complex task, integrating -this mechanism into the thread structure of the program is much -simpler. - - Using a thread and a pipe to read a local file adds a -buffering step to the process (and a certain latency), but it has -a couple of significative advantages: - - By handling local files in the same way as remote - connections, a significant amount of code is reused. - - A preprocessing step of the file data can be added easily, - if needed. In fact, the file is encapsulated into an HTTP - data stream. - - ------------ -DNS queries ------------ - - Dillo handles DNS queries with threads, letting a child thread -wait until the DNS server answers the request. When the answer -arrives, a call-back function is called, and the program resumes -what it was doing at DNS-request time. The interesting thing is -that the call-back happens in the main thread, while the child -thread simply exits when done. This is implemented through a -server-channel design. - - -The server channel ------------------- - - There is one thread for each channel, and each channel can -have multiple clients. When the program requests an IP address, -the server first looks for a cached match; if it hits, the client -call-back is invoked immediately, but if not, the client is put -into a queue, a thread is spawned to query the DNS, and a GTK+ -idle client is set to poll the channel 5~times per second for -completion, and when it finally succeeds, every client of that -channel is serviced. - - This scheme allows all the further processing to continue on -the same thread it began: the main thread. - - ------------------------- -Handling TCP connections ------------------------- - - Establishing a TCP connection requires the well known -three-way handshake packet-sending sequence. Depending on network -traffic and several other issues, significant delay can occur at -this phase. - - Dillo handles the connection by a non blocking socket scheme. -Basically, a socket file descriptor of AF_INET type is requested -and set to non-blocking I/O. When the DNS server has resolved the -name, the socket connection process begins by calling connect(2); - {We use the Unix convention of identifying the manual section - where the concept is described, in this case - section 2 (system calls).} -which returns immediately with an EINPROGRESS error. - - After the connection reaches the EINPROGRESS ``state,'' the -socket waits in background until connection succeeds (or fails), -when that happens, a callback function is awaked to perform the -following steps: set the I/O engine to send the query and expect -its answer (both in background). - - The advantage of this scheme is that every required step is -quickly done without blocking the browser. Finally, the socket -will generate a signal whenever I/O is possible. - - ----------------- -Handling queries ----------------- - - In the case of a HTTP URL, queries typically translate into a -short transmission (the HTTP query) and a lengthy retrieval -process. Queries are not always short though, specially when -requesting forms (all the form data is attached within the -query), and also when requesting CGI programs. - - Regardless of query length, query sending is handled in -background. The thread that was initiated at TCP connecting time -has all the transmission framework already set up; at this point, -packet sending is just a matter of waiting for the -write signal (G_IO_OUT) to come and then sending the data. When -the socket gets ready for transmission, the data is sent using -IO_write. - - --------------- -Receiving data --------------- - - Although conceptually similar to sending queries, retrieving -data is very different as the data received can easily exceed the -size of the query by many orders of magnitude (for example when -downloading images or files). This is one of the main sources of -latency, the retrieval can take several seconds or even minutes -when downloading large files. - - The data retrieving process for a single file, that began by -setting up the expecting framework at TCP connecting time, simply -waits for the read signal (G_IO_IN). When it happens, the -low-level I/O engine gets called, the data is read into -pre-allocated buffers and the appropriate call-backs are -performed. Technically, whenever a G_IO_IN event is generated, -data is received from the socket file descriptor, by using the -IO_read function. This iterative process finishes upon EOF (or on -an error condition). - - ----------------------- -Closing the connection ----------------------- - - Closing a TCP connection requires four data segments, not an -impressive amount but twice the round trip time, which can be -substantial. When data retrieval finishes, socket closing is -triggered. There's nothing but a IO_close_fd call on the socket's -file descriptor. This process was originally designed to split -the four segment close into two partial closes, one when query -sending is done and the other when all data is in. This scheme is -not currently used because the write close also stops the reading -part. - - -The low-level I/O engine ------------------------- - - Dillo I/O is carried out in the background. This is achieved -by using low level file descriptors and signals. Anytime a file -descriptor shows activity, a signal is raised and the signal -handler takes care of the I/O. - - The low-level I/O engine ("I/O engine" from here on) was -designed as an internal abstraction layer for background file -descriptor activity. It is intended to be used by the cache -module only; higher level routines should ask the cache for its -URLs. Every operation that is meant to be carried out in -background should be handled by the I/O engine. In the case of -TCP sockets, they are created and submitted to the I/O engine for -any further processing. - - The submitting process (client) must fill a request structure -and let the I/O engine handle the file descriptor activity, until -it receives a call-back for finally processing the data. This is -better understood by examining the request structure: - - typedef struct { - gint Key; /* Primary Key (for klist) */ - gint Op; /* IORead | IOWrite | IOWrites */ - gint FD; /* Current File Descriptor */ - gint Flags; /* Flag array */ - glong Status; /* Number of bytes read, or -errno code */ - - void *Buf; /* Buffer place */ - size_t BufSize; /* Buffer length */ - void *BufStart; /* PRIVATE: only used inside IO.c! */ - - void *ExtData; /* External data reference (not used by IO.c) */ - void *Info; /* CCC Info structure for this IO */ - GIOChannel *GioCh; /* IO channel */ - guint watch_id; /* glib's event source id */ - } IOData_t; - - To request an I/O operation, this structure must be filled and -passed to the I/O engine. - - 'Op' and 'Buf' and 'BufSize' MUST be provided. - - 'ExtData' MAY be provided. - - 'Status', 'FD' and 'GioCh' are set by I/O engine internal -routines. - - When there is new data in the file descriptor, 'IO_callback' -gets called (by glib). Only after the I/O engine finishes -processing the data are the upper layers notified. - - -The I/O engine transfer buffer ------------------------------- - - The 'Buf' and 'BufSize' fields of the request structure -provide the transfer buffer for each operation. This buffer must -be set by the client (to increase performance by avoiding copying -data). - - On reads, the client specifies the amount and where to place -the retrieved data; on writes, it specifies the amount and source -of the data segment that is to be sent. Although this scheme -increases complexity, it has proven very fast and powerful. For -instance, when the size of a document is known in advance, a -buffer for all the data can be allocated at once, eliminating the -need for multiple memory reallocations. Even more, if the size is -known and the data transfer is taking the form of multiple small -chunks of data, the client only needs to update 'Buf' and -BufSize' to point to the next byte in its large preallocated -reception buffer (by adding the chunk size to 'Buf'). On the -other hand, if the size of the transfer isn't known in advance, -the reception buffer can remain untouched until the connection -closes, but the client must then accomplish the usual buffer -copying and reallocation. - - The I/O engine also lets the client specify a full length -transfer buffer when sending data. It doesn't matter (from the -client's point of view) if the data fits in a single packet or -not, it's the I/O engine's job to divide it into smaller chunks -if needed and to perform the operation accordingly. - - ------------------------------------------- -Handling multiple simultaneous connections ------------------------------------------- - - The previous sections describe the internal work for a single -connection, the I/O engine handles several of them in parallel. -This is the normal downloading behavior of a web page. Normally, -after retrieving the main document (HTML code), several -references to other files (typically images) and sometimes even -to other sites (mostly advertising today) are found inside the -page. In order to parse and complete the page rendering, those -other documents must be fetched and displayed, so it is not -uncommon to have multiple downloading connections (every one -requiring the whole fetching process) happening at the same time. - - Even though socket activity can reach a hectic pace, the -browser never blocks. Note also that the I/O engine is the one -that directs the execution flow of the program by triggering a -call-back chain whenever a file descriptor operation succeeds or -fails. - - A key point for this multiple call-back chained I/O engine is -that every single function in the chain must be guaranteed to -return quickly. Otherwise, the whole system blocks until it -returns. - - ------------ -Conclusions ------------ - - Dillo is currently in very stable beta state. It already shows -impressive performance, and its interactive ``feel'' is much -better than that of other web browsers. - - The modular structure of Dillo, and its reliance on GTK1 allow -it to be very small. Not every feature of HTML-4.01 has been -implemented yet, but no significant problems are foreseen in -doing this. - - The fact that Dillo's central I/O engine is written using -advanced features of POSIX and TCP/IP networking makes its -performance possible, but on the other hand this also means that -only a fraction of the interested hackers are able to work on it. - - A simple code base is critical when trying to attract hackers -to work on a project like this one. Using the GTK+ framework -helped both in creating the graphical user interface and in -handling the concurrency inside the browser. By having threads -communicate through pipes the need for explicit synchronization -is almost completely eliminated, and with it most of the -complexity of concurrent programming disappears. - - A clean, strictly applied layering approach based on clear -abstractions is vital in each programming project. A good, -supportive framework is of much help here. - - diff --git a/doc/Images.txt b/doc/Images.txt deleted file mode 100644 index 62082e48..00000000 --- a/doc/Images.txt +++ /dev/null @@ -1,129 +0,0 @@ - January 2009, --Jcid - -Update June 2015: See also doc/dw-images-and-backgrounds.doc, or -../html/dw-images-and-backgrounds.html (generated by doxygen). - - ------ - IMAGES - ------ - -* When a image tag is found within a HTML page, Html_tag_open_img -handles it by: - - - Parsing & getting attribute values. - - Creating a new image structure (DilloImage) and its - associated widget (DwImage). - i.e. If 'Image' is the var for the structure, then - 'Image->dw' is the widget. - - Requesting the image to be feeded by the cache. - - Sending some info to the browser interface. - -* The cache can either request the image data from the net, or -feed it directly from the dicache (decompressed image cache). - -* Both processes are somewhat different because the first one -requires to decode the image data into RGB format, and the second -one has the whole data already decoded. - -* Regardless of the RGB-data feeding method, the decoded data is -passed to the widget (DwImage) and drawn in a streamed way. - Note that INDEXED images are also decoded into RGB format. - - Html_tag_open_img // IMG element processing - Html_add_new_image // Read attributes, create image, add to HTML page - a_Image_new // Create a 'DilloImage' data structure, to coordinate - // decoded image-data transfer to an 'Imgbuf'. - Html_add_widget // Adds the dw::Image to the page - Html_load_image // Tells cache to retrieve image - - ---------------------- -Fetching from the net ---------------------- - -* a_Capi_open_url initiates the resource request, and when -finally the answer arrives, the HTTP header is examined for MIME -type and either the GIF or PNG or JPEG decoder is set to handle -the incoming data stream. - - Decoding functions: - a_Gif_callback, a_Jpeg_callback and a_Png_callback. - -* The decoding function calls the following dicache methods as -the data is processed (listed in order): - - a_Dicache_set_parms - a_Dicache_set_cmap (only for indexed-GIF images) - a_Dicache_write - a_Dicache_new_scan (MAY be called here or after set_cmap) - a_Dicache_close - - -* The dicache methods call the necessary functions to connect -with the widget code. This is done by calling image.c functions: - - a_Image_set_parms - a_Image_set_cmap - a_Image_write - a_Image_new_scan - a_Image_close - -* The functions in image.c make the required Dw calls. - - -------------------------- -Fetching from the dicache -------------------------- - -* a_Capi_open_url() tests the cache for the image, and the cache, -via a_Cache_open_url(), enqueues a client for it, without asking -the network for the data. When the client queue is processed (a -bit later), Dicache_image() is set as the callback. - -* When Dicache_image() is called, it sets the proper image data -decoder (RGB) and its data structure based on the entry's Type. -Then it substitutes itself with a_Dicache_callback() as the -handling function, and gets out of the way. - -* Thenceforth the rest of the functions calls is driven by -a_Dicache_callback(). - - ------------ -Misc. notes ------------ - -* Repeated images generate new cache clients, but they may share -the imgbuf. - Note: Currently there's no proper support for transparent -images (i.e. decode to RGBA), but most of the time they render -the background color OK. This is: when first loaded, repeated -images share a background color, but when cached they render -correctly ;-). There's no point in trying to fix this because the -correct solution is to decode to RGBA and let the toolkit (FLTK) -handle the transparency. - -* The first cache-client callback (Dicache_image()) is set when -the Content-type of the image is got. - -* Later on, when there's a shared imgbuf, the dicache's logic -avoids decoding it multiple times and reuses what's already done. - -* The dicache-entry and the Image structure hold bit arrays that -represent which rows have been decoded. - -* The image processing can be found in the following sources: - - - image.{cc,hh} - - dicache.[ch] - - gif.[ch], png.[ch], jpeg.[ch] - - dw/image.{cc,hh} - -* Bear in mind that there are four data structures for image -code: - - - DilloImage (image.hh) - - DICacheEntry (dicache.h) - - dw::Image (class Image in dw/image.hh) - - core::Imgbuf (imgbuf.hh) - diff --git a/doc/Makefile.am b/doc/Makefile.am index 71c7c32d..7b40d0a2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,48 +1,10 @@ dist_doc_DATA = user_help.html man_MANS = dillo.1 EXTRA_DIST = \ - index.doc \ - lout.doc \ - dw-map.doc \ - dw-overview.doc \ - dw-usage.doc \ - dw-layout-views.doc \ - dw-layout-widgets.doc \ - dw-widget-sizes.doc \ - dw-changes.doc \ - dw-images-and-backgrounds.doc \ - dw-out-of-flow.doc \ - dw-out-of-flow-2.doc \ - fltk-problems.doc \ - rounding-errors.doc \ - uml-legend.doc \ - dw-line-breaking.doc \ - dw-example-screenshot.png \ - dw-viewport-without-scrollbar.png \ - dw-viewport-with-scrollbar.png \ - dw-size-of-widget.png \ - dw-style-box-model.png \ - dw-style-length-absolute.png \ - dw-style-length-percentage.png \ - dw-style-length-relative.png \ - dw-textblock-collapsing-spaces-1-1.png \ - dw-textblock-collapsing-spaces-1-2.png \ - dw-textblock-collapsing-spaces-2-1.png \ - dw-textblock-collapsing-spaces-2-2.png \ - dw-floats-01.png \ - not-so-simple-container.png \ - Cache.txt \ - Cookies.txt \ - Dillo.txt \ - Dw.txt \ - HtmlParser.txt \ - IO.txt \ - Images.txt \ - NC_design.txt \ - Dpid.txt \ - CCCwork.txt \ README \ - dillo.1.in + Cookies.txt \ + dillo.1.in \ + user_help.html dillo.1: $(srcdir)/dillo.1.in Makefile sed 's%/usr/local%${prefix}%g' < $(srcdir)/dillo.1.in > dillo.1 diff --git a/doc/NC_design.txt b/doc/NC_design.txt deleted file mode 100644 index 380787f6..00000000 --- a/doc/NC_design.txt +++ /dev/null @@ -1,127 +0,0 @@ - - _________________________________________________________________ - - Naming&Coding design - _________________________________________________________________ - - Dillo's code is divided into modules. For instance: bookmark, cache, - dicache, gif. - - Let's think of a module named "menu", then: - * Every internal routine of the module, should start with "Menu_" - prefix. - * "Menu_" prefixed functions are not meant to be called from outside - the module. - * If the function is to be exported to other modules (i.e. it will - be called from the outside), it should be wrapped with an "a_" - prefix. - - For instance: if the function name is "Menu_create", then it's an - internal function, but if we need to call it from the outside, then it - should be renamed to "a_Menu_create". - - Why the "a_" prefix? - Because of historical reasons. - And "a_Menu_create" reads better than "d_Menu_create" because the - first one suggests "a Menu create" function! - - Another way of understanding this is thinking of "a_" prefixed - functions as Dillo's internal library, and the rest ("Menu_" prefixed - in our example) as a private module-library. - - Indentation: - - Source code must be indented with 3 blank spaces, no Tabs. - Why? - Because different editors expand or treat tabs in several ways; 8 - spaces being the most common, but that makes code really wide and - we'll try to keep it within the 80 columns bounds (printer friendly). - - You can use: indent -kr -sc -i3 -bad -nbbo -nut -l79 myfile.c - - Function commenting: - - Every single function of the module should start with a short comment - that explains its purpose; three lines must be enough, but if you - think it requires more, enlarge it. - - /* - * Try finding the url in the cache. If it hits, send the contents - * to the caller. If it misses, set up a new connection. - */ - int a_Cache_open_url(const char *url, void *Data) - { - ... - ... - ... - } - - We also have the BUG:, TODO:, and WORKAROUND: tags. - Use them within source code comments to spot hidden issues. For - instance: - - /* BUG: this counter is not accurate */ - ++i; - - /* TODO: get color from the right place */ - a = color; - - /* WORKAROUND: the canonical way of doing it doesn't work yet. */ - ++a; ++a; ++a; - - Function length: - - Let's try to keep functions within the 45 lines boundary. This eases - code reading, following, understanding and maintenance. - - Functions with a single exit: - - It's much easier to follow and maintain functions with a single exit - point at the bottom (instead of multiple returns). The exception to - the rule are calls like dReturn_if_fail() at its head. - - dlib functions: - - * Dillo uses dlib extensively in its C sources. Before starting - to code something new, a good starting point is to check what - this library has to offer (check dlib/dlib.h). - * Memory management must be done using dNew, dNew0, dMalloc, dFree - and their relatives. - * For debugging purposes and error catching (not for normal flow): - dReturn_if_fail, dReturn_val_if_fail etc. are encouraged. - * The MSG macro is extensively used to output additional information - to the calling terminal. - - _________________________________________________________________ - - C++ - - Source code in C++ should follow the same rules with these exceptions: - - * Class method names are camel-cased and start with lowercase - e.g. appendInputMultipart - * Classes and types start uppercased - e.g. class DilloHtmlReceiver - * Class methods don't need to prefix its module name - e.g. links->get() - - We also try to keep the C++ relatively simple. Dillo does use - inheritance and templates, but that's about all. - - _________________________________________________________________ - - What do we get with this? - - * A clear module API for Dillo; every function prefixed "a_" is to - be used outside the module. - * A way to identify where the function came from (the - capitalized word is the module name). - * An inner ADT (Abstract data type) for the module that can be - isolated, tested and replaced independently. - * A two stage instance for bug-fixing. You can change the exported - function algorithms while someone else fixes the internal - module-ADT! - * A coding standard ;) - _________________________________________________________________ - - Naming&Coding design by Jorge Arellano Cid diff --git a/doc/README b/doc/README index 9736a32b..41c11d87 100644 --- a/doc/README +++ b/doc/README @@ -1,51 +1,5 @@ -README: Last update Jul 2009 +Last update: June 2015 -These documents cover dillo's internals. -For user help, see http://www.dillo.org/dillo3-help.html - --------------------------------------------------------------------------- - -These documents need a review. -*.txt were current with Dillo1, but many have since become more or - less out-of-date. -*.doc are doxygen source for the Dillo Widget (dw) component, and - were written for Dillo2. - -They will give you an overview of what's going on, but take them -with a pinch of salt. - - Of course I'd like to have *.txt as doxygen files too! -If somebody wants to make this conversion, please let me know -to assign higher priority to updating these docs. - --- -Jorge.- - - -------------------------------------------------------------------------- - FILE DESCRIPTION STATE - -------------------------------------------------------------------------- - NC_design.txt Naming&Coding design (Be sure to Current - read it before any other doc) - Dillo.txt General overview of the program Current - IO.txt Extensive introduction Current - Cache.txt Informative description Current - Images.txt Image handling and processing Current - HtmlParser.txt A versatile parser Current - Dw.txt The New Dillo Widget (Overview) Current - Imgbuf.txt Image buffers Pending - Selection.txt Selections, and link activation Current (?) - Cookies.txt Explains how to enable cookies Current - Dpid.txt Dillo plugin daemon Current - -------------------------------------------------------------------------- - - - * BTW, there's a small program (srch) within the src/ dir. It searches - tokens within the whole code (*.[ch]). It has proven very useful. - Ex: ./srch a_Image_write - ./srch todo: - - * Please submit your patches with 'hg diff'. - - - Happy coding! - --Jcid +This directory contains user documentation. Developer documentation is +only stored in the Hg repository at , in +the directory "devdoc", but not part of the tarball. diff --git a/doc/dw-changes.doc b/doc/dw-changes.doc deleted file mode 100644 index 7050df9a..00000000 --- a/doc/dw-changes.doc +++ /dev/null @@ -1,105 +0,0 @@ -/** \page dw-changes Changes to the GTK+-based Release Version - -

Changes in Dw

- -Related to the FLTK port, there have been many changes, this is a -(hopefully complete) list: - -
    -
  • Rendering abstraction, read \ref dw-overview and \ref dw-layout-views - for details. Some important changes: - -
      -
    • The underlying platform (e.g. the UI toolkit) is fully abstract, - there are several platform independent structures replacing - GTK+ structures, e.g. dw::core::Event. - -
    • The central class managing the widget tree is not anymore - GtkDwViewport, but dw::core::Layout. - -
    • Drawing is done via dw::core::View, a pointer is passed to - dw::core::Widget::draw. - -
    • The distinction between viewport coordinates and canvas - coordinates (formerly world coordinates) has been mostly - removed. (Only for views, it sometimes plays a role, see - \ref dw-layout-views). -
    - -
  • Cursors have been moved to dw::core::style, see - dw::core::style::Style::cursor. dw::core::Widget::setCursor is now - protected (and so only called by widget implementations). - -
  • World coordinates are now called canvas coordinates. - -
  • There is now a distinction between dw::core::style::StyleAttrs and - dw::core::style::Style. - -
  • There is no base class for container widgets anymore. The former - DwContainer::for_all has been removed, instead this functionality - is now done via iterators (dw::core::Widget::iterator, - dw::core::Iterator). - -
  • DwPage is now called dw::Textblock, and DwAlignedPage - dw::AlignedTextblock. - -
  • dw::Textblock, all sub classes of it, and dw::Table do not read - "limit_text_width" from the preferences, but get it as an argument. - (May change again.) - -
  • dw::Table has been rewritten. - -
  • Instead of border_spacing in the old DwStyle, there are two attributes, - dw::core::style::Style::hBorderSpacing and - dw::core::style::Style::vBorderSpacing, since CSS allowes to specify - two values. Without CSS, both attributes should have the same value. - -
  • Images are handled differently, see \ref dw-images-and-backgrounds. - -
  • Embedded UI widgets (formerly GtkWidget's) are handled differently, - see dw::core::ui. - -
  • DwButton has been removed, instead, embedded UI widgets are used. See - dw::core::ui and dw::core::ui::ComplexButtonResource. -
- -Dw is now written C++, the transition should be obvious. All "Dw" -prefixes have been removed, instead, namespaces are used now: - -
    -
  • dw::core contains the core, -
  • dw::core::style styles, -
  • dw::core::ui embedded UI resources, -
  • dw::fltk classes related to FLTK, and -
  • ::dw the widgets. -
- -

Documentation

- -The old documentation has been moved to: - - -
Old New -
Dw.txt - general part \ref dw-overview, \ref dw-usage, - \ref dw-layout-widgets, - \ref dw-widget-sizes -
remarks on specific widgets respective source files: dw::Bullet, - dw::core::ui::Embed -
DwImage.txt - signals dw::core::Layout::LinkReceiver -
rest dw::Image, - \ref dw-images-and-backgrounds -
Imgbuf.txt dw::core::Imgbuf, - \ref dw-images-and-backgrounds -
DwPage.txt dw::Textblock -
DwRender.txt \ref dw-overview, \ref dw-layout-views, - dw::core::ui -
DwStyle.txt dw::core::style -
DwTable.txt dw::Table -
DwWidget.txt dw::core::Widget, \ref dw-layout-widgets, - \ref dw-widget-sizes -
Selection.txt dw::core::SelectionState -
- -*/ diff --git a/doc/dw-example-screenshot.png b/doc/dw-example-screenshot.png deleted file mode 100644 index 94f272ab..00000000 Binary files a/doc/dw-example-screenshot.png and /dev/null differ diff --git a/doc/dw-floats-01.png b/doc/dw-floats-01.png deleted file mode 100644 index 116d36b3..00000000 Binary files a/doc/dw-floats-01.png and /dev/null differ diff --git a/doc/dw-grows.doc b/doc/dw-grows.doc deleted file mode 100644 index a0304ef9..00000000 --- a/doc/dw-grows.doc +++ /dev/null @@ -1,202 +0,0 @@ -/** \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. - -
- Update: 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.
- -**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.) - -
- Notice: Currently, dw::core::Widget::getExtremesImpl must - set all four members in dw::core::Extremes; this may change.
- -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 adjust_min_width, -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. 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. - -*/ diff --git a/doc/dw-images-and-backgrounds.doc b/doc/dw-images-and-backgrounds.doc deleted file mode 100644 index 8f07766a..00000000 --- a/doc/dw-images-and-backgrounds.doc +++ /dev/null @@ -1,235 +0,0 @@ -/** \page dw-images-and-backgrounds Images and Backgrounds in Dw - -Image Buffers -============= - -Representation of the image data is done by dw::core::Imgbuf, see -there for details. Drawing is done by dw::core::View -(dw::core::View::drawImage). - -Since dw::core::Imgbuf provides memory management based on reference -counting, there may be an 1-to-n relation from image renderers (image -widgets or backgrounds, see below) and dw::core::Imgbuf. Since -dw::core::Imgbuf does not know about renderers, but just provides -rendering functionality, the caller must (typically after calling -dw::core::Imgbuf::copyRow) notify all renderers connected to the -buffer. - - -Image Renderer -============== - -Generally, there are no restrictions on how to manage -dw::core::Imgbuf; but to handle image data from web resources, the -interface dw::core::ImgRenderer should be implemented. It is again -wrapped by DilloImage (to make access from the C part possible, since -dw::core::ImgRenderer is written in C++), which is referenced by -DilloWeb. There are two positions where retrieving image data is -initiated: - -- Html_load_image: for embedded images (implemented by dw::Image, - which implements dw::core::ImgRenderer); -- StyleEngine::apply (search for "case - CSS_PROPERTY_BACKGROUND_IMAGE"): for backgrond images; there are - some implementations of dw::core::ImgRenderer within the context of - dw::core::style::StyleImage. - -Both are described in detail below. Notice that the code is quite -similar; only the implementation of dw::core::ImgRenderer differs. - -At this time, dw::core::ImgRenderer has got two methods (see more -documentation there): - -- dw::core::ImgRenderer::setBuffer, -- dw::core::ImgRenderer::drawRow, -- dw::core::ImgRenderer::finish, and -- dw::core::ImgRenderer::fatal. - - -Images -====== - -This is the simplest renderer, displaying an image. For each row to be -drawn, - -- first dw::core::Imgbuf::copyRow, and then -- for each dw::Image, dw::Image::drawRow must be called, with the same - argument (no scaling is necessary). - -dw::Image automatically scales the dw::core::Imgbuf, the root buffer -should be passed to dw::Image::setBuffer. - -\see dw::Image for more details. - - -Background Images -================= - -Since background images are style resources, they are associated with -dw::core::style::Style, as dw::core::style::StyleImage, which is -handled in a similar way (reference counting etc.) as -dw::core::style::Color and dw::core::style::Font, although it is -concrete and not platform-dependant. - -The actual renderer (passed to Web) is an instance of -dw::core::ImgRendererDist (distributes all calls to a set of other -instances of dw::core::ImgRenderer), which contains two kinds of -renderers: - -- one instance of dw::core::style::StyleImage::StyleImgRenderer, which - does everything needed for dw::core::style::StyleImage, and -- other renderers, used externally (widgets etc.), which are added by - dw::core::style::StyleImage::putExternalImgRenderer (and removed by - dw::core::style::StyleImage::removeExternalImgRenderer). - -This diagram gives an comprehensive overview: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="open", dir="both", arrowtail="none", - labelfontname=Helvetica, labelfontsize=10, color="#404040", - labelfontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - - subgraph cluster_dw_style { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - - Style [URL="\ref dw::core::style::Style"]; - StyleImage [URL="\ref dw::core::style::StyleImage"]; - Imgbuf [URL="\ref dw::core::Imgbuf", color="#a0a0a0"]; - StyleImgRenderer - [URL="\ref dw::core::style::StyleImage::StyleImgRenderer"]; - ImgRenderer [URL="\ref dw::core::ImgRenderer", color="#ff8080"]; - ImgRendererDist [URL="\ref dw::core::ImgRendererDist"]; - ExternalImgRenderer - [URL="\ref dw::core::style::StyleImage::ExternalImgRenderer", - color="#a0a0a0"]; - ExternalWidgetImgRenderer - [URL="\ref dw::core::style::StyleImage::ExternalWidgetImgRenderer", - color="#a0a0a0"]; - } - - subgraph cluster_dw_layout { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - - Layout [URL="\ref dw::core::Layout"]; - LayoutImgRenderer [URL="\ref dw::core::Layout::LayoutImgRenderer"]; - } - - subgraph cluster_dw_widget { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - - Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; - WidgetImgRenderer [URL="\ref dw::core::Widget::WidgetImgRenderer"]; - } - - subgraph cluster_dw_textblock { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - - Textblock [URL="\ref dw::Textblock"]; - Word [URL="\ref dw::Textblock::Word"]; - WordImgRenderer [URL="\ref dw::Textblock::WordImgRenderer"]; - SpaceImgRenderer [URL="\ref dw::Textblock::SpaceImgRenderer"]; - } - - Style -> StyleImage [headlabel="*", taillabel="1"]; - StyleImage -> Imgbuf [headlabel="*", taillabel="1"]; - StyleImage -> StyleImgRenderer [headlabel="1", taillabel="1"]; - StyleImage -> ImgRendererDist [headlabel="1", taillabel="1"]; - ImgRendererDist -> StyleImgRenderer [headlabel="1", taillabel="1"]; - ImgRendererDist -> ImgRenderer [headlabel="1", taillabel="*"]; - - ImgRenderer -> ImgRendererDist [arrowhead="none", arrowtail="empty", - dir="both", style="dashed"]; - ImgRenderer -> StyleImgRenderer [arrowhead="none", arrowtail="empty", - dir="both", style="dashed"]; - ImgRenderer -> ExternalImgRenderer [arrowhead="none", arrowtail="empty", - dir="both", style="dashed"]; - ExternalImgRenderer -> ExternalWidgetImgRenderer [arrowhead="none", - arrowtail="empty", dir="both", style="dashed"]; - - Layout -> LayoutImgRenderer [headlabel="1", taillabel="0..1"]; - ExternalImgRenderer -> LayoutImgRenderer [arrowhead="none", - arrowtail="empty", dir="both", style="dashed"]; - - Widget -> WidgetImgRenderer [headlabel="1", taillabel="0..1"]; - ExternalWidgetImgRenderer -> WidgetImgRenderer [arrowhead="none", - arrowtail="empty", dir="both", style="dashed"]; - - Textblock -> Word [headlabel="1", taillabel="*"]; - Word -> WordImgRenderer [headlabel="1", taillabel="0..1"]; - Word -> SpaceImgRenderer [headlabel="1", taillabel="0..1"]; - ExternalWidgetImgRenderer -> WordImgRenderer [arrowhead="none", - arrowtail="empty", dir="both", style="dashed"]; - WordImgRenderer -> SpaceImgRenderer [arrowhead="none", arrowtail="empty", - dir="both", style="dashed"]; -} -\enddot - -
[\ref uml-legend "legend"]
- - -Memory management ------------------ - -dw::core::style::StyleImage extends lout::signal::ObservedObject, so -that deleting this instance can be connected to code dealing with -cache clients etc. See StyleImageDeletionReceiver and how it is -attached in StyleEngine::apply ("case CSS_PROPERTY_BACKGROUND_IMAGE"). - - -Bugs and Things Needing Improvement -=================================== - -(Mostly related to image backgrounds, when not otherwise mentioned.) - -High Priority -------------- - -**Configurability, security/privacy aspects, etc.,** which are -currently available for image widgets, should be adopted. Perhaps some -more configuration options specially for background images. - - -Medium Priority ---------------- - -**Background-attachment** is not yet implemented, and will be postponed. - -**Calls to dw::core::ImgRenderer::fatal** are incomplete. As an -example, it is not called, when connecting to a server fails. (And so, -as far as I see, no cache client is started.) - - -Low Priority ------------- - -**Alpha support:** (not related to image backgrounds) currently alpha -support (and also colormap management) is done in dicache, while -dw::Image is only created with type RGB. This leads to several problems: - -- One dicache entry (representing an image related to the same URL), - which has only one background color, may refer to different images - with different background colors. -- The dicache only handles background colors, not background images. - -The solution is basicly simple: keep alpha support out of dicache; -instead implement RGBA in dw::Image. As it seems, the main problem is -alpha support in FLTK/X11. - - -Solved (Must Be Documented) ---------------------------- - -*Drawing background images row by row may become slow. As an -alternative, dw::core::ImgRenderer::finish could be used. However, -drawing row by row could become an option.* There is now -dw::core::style::drawBackgroundLineByLine, which can be changed in the -code, and is set to *false*. The old code still exists, so changing -this to *true* activates again drawing line by line. - -(For image widgets, this could also become an option: in contexts, -when image data is retrieved in a very fast way.) - -*/ diff --git a/doc/dw-layout-views.doc b/doc/dw-layout-views.doc deleted file mode 100644 index d1118489..00000000 --- a/doc/dw-layout-views.doc +++ /dev/null @@ -1,256 +0,0 @@ -/** \page dw-layout-views Layout and Views - -Rendering of Dw is done in a way resembling the model-view pattern, at -least formally. Actually, the counterpart of the model, the layout -(dw::core::Layout), does a bit more than a typical model, namely the -layouting (delegated to the widget tree, see \ref dw-layout-widgets), -and the view does a bit less than a typical view, i.e. only the actual -drawing. - -Additionally, there is a structure representing common properties of -the platform. A platform is typically related to the underlying UI -toolkit, but other uses may be thought of. - -This design helps to archieve two important goals: - -
    -
  • Abstraction of the actual drawing, by different implementations - of dw::core::View. - -
  • It makes portability simple. -
- - -

Viewports

- -Although the design implies that the usage of viewports should be -fully transparent to the layout module, this cannot be fully achieved, -for the following reasons: - -
    -
  • Some features, which are used on the level of dw::core::Widget, - e.g. anchors, refer to scrolling positions. - -
  • Size hints (see \ref dw-layout-widgets) depend on the viewport - sizes, e.g. when the user changes the window size, and so also - the size of a viewport, the text within should be rewrapped. -
- -Therefore, dw::core::Layout keeps track of the viewport size, the -viewport position, and even the thickness of the scrollbars, they are -relevant, see below for more details. -If a viewport is not used, however, the size is not defined. - -Whether a given dw::core::View implementation is a viewport or not, is -defined by the return value of dw::core::View::usesViewport. If this -method returns false, the following methods need not to be implemented -at all: - -
    -
  • dw::core::View::getHScrollbarThickness, -
  • dw::core::View::getVScrollbarThickness, -
  • dw::core::View::scrollTo, and -
  • dw::core::View::setViewportSize. -
- -

Scrolling Positions

- -The scrolling position is the canvas position at the upper left corner -of the viewport. Views using viewports must - -
    -
  1. change this value on request (dw::core::View::scrollTo), and -
  2. tell other changes to the layout, e.g. caused by user events - (dw::core::Layout::scrollPosChanged). -
- -Applications of scrolling positions (anchors, test search etc.) are -handled by the layout, in a way fully transparent to the view. - -

Scrollbars

- -A feature of the viewport size model are scrollbars. There may be a -vertical scrollbar and a horizontal scrollbar, displaying the -relationship between canvas and viewport height or width, -respectively. If they are not needed, they are hidden, to save screen -space. - -Since scrollbars decrease the usable space of a view, dw::core::Layout -must know how much space they take. The view returns, via -dw::core::View::getHScrollbarThickness and -dw::core::View::getVScrollbarThickness, how thick they will be, when -visible. - -Viewport sizes, which denote the size of the viewport widgets, include -scrollbar thicknesses. When referring to the viewport \em excluding -the scrollbars space, we will call it "usable viewport size", this is -the area, which is used to display the canvas. - -

Drawing

- -A view must implement several drawing methods, which work on the whole -canvas. If it is necessary to convert them (e.g. into -dw::fltk::FltkViewport), this is done in a way fully transparent to -dw::core::Widget and dw::core::Layout, instead, this is done by the -view implementation. - -There exist following situations: - -
    -
  • A view gets an expose event: It will delegate this to the - layout (dw::core::Layout::draw), which will then pass it to the - widgets (dw::core::Widget::draw), with the view as a parameter. - Eventually, the widgets will call drawing methods of the view. - -
  • A widget requests a redraw: In this case, the widget will - delegate this to the layout (dw::core::Layout::queueDraw), which - delegates it to the view (dw::core::View::queueDraw). - Typically, the view will queue these requests for efficiency. - -
  • A widget requests a resize: This case is described below, in short, - dw::core::View::queueDrawTotal is called for the view. -
- -If the draw method of a widget is implemented in a way that it may -draw outside of the widget's allocation, it should draw into a -clipping view. A clipping view is a view related to the actual -view, which guarantees that the parts drawn outside are discarded. At -the end, the clipping view is merged into the actual view. Sample -code: - -\code -void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) -{ - // 1. Create a clipping view. - dw::core::View clipView = - view->getClippingView (allocation.x, allocation.y, - allocation.width, getHeight ()); - - // 2. Draw into clip_view - clipView->doSomeDrawing (...); - - // 3. Draw the children, they receive the clipping view as argument. - dw::core::Rectangle *childArea - for () { - if (child->intersects (area, &childArea)) - child->draw (clipView, childArea); - } - - // 4. Merge - view->mergeClippingView (clipView); -} -\endcode - -A drawing process is always embedded into calls of -dw::core::View::startDrawing and dw::core::View::finishDrawing. An -implementation of this may e.g. use backing pixmaps, to prevent -flickering. - - -

Sizes

- -In the simplest case, the view does not have any influence on -the canvas size, so it is told about changes of the -canvas size by a call to dw::core::View::setCanvasSize. This happens -in the following situations: - -
    -
  • dw::core::Layout::addWidget, -
  • dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), - and -
  • dw::core::Layout::queueResize (called by - dw::core::Widget::queueResize, when a widget itself requests a size - change). -
- -

Viewports

- -There are two cases where the viewport size changes: - -
    -
  • As an reaction on a user event, e.g. when the user changes the - window size. In this case, the view delegates this - change to the layout, by calling - dw::core::Layout::viewportSizeChanged. - -
  • The viewport size may also depend on the visibility of UI - widgets, which depend on the world size, e.g scrollbars, - generally called "viewport markers". This is described in a separate - section. -
- -After the creation of the layout, the viewport size is undefined. When -a view is attached to a layout, and this view can already specify -its viewport size, it may call -dw::core::Layout::viewportSizeChanged within the implementation of -dw::core::Layout::setLayout. If not, it may do this as soon as the -viewport size is known. - -Generally, the scrollbars have to be considered. If e.g. an HTML page -is rather small, it looks like this: - -\image html dw-viewport-without-scrollbar.png - -If some more data is retrieved, so that the height exceeds the -viewport size, the text has to be rewrapped, since the available width -gets smaller, due to the vertical scrollbar: - -\image html dw-viewport-with-scrollbar.png - -Notice the different line breaks. - -This means circular dependencies between these different sizes: - -
    -
  1. Whether the scrollbars are visible or not, determines the - usable space of the viewport. - -
  2. From the usable space of the viewport, the size hints for the - toplevel are calculated. - -
  3. The size hints for the toplevel widgets may have an effect on its - size, which is actually the canvas size. - -
  4. The canvas size determines the visibility of the scrollbarss. -
- -To make an implementation simpler, we simplify the model: - -
    -
  1. For the calls to dw::core::Widget::setAscent and - dw::core::Widget::setDescent, we will always exclude the - horizontal scrollbar thickness (i.e. assume the horizontal - scrollbar is used, although the visibility is determined correctly). - -
  2. For the calls to dw::core::Widget::setWidth, we will calculate - the usable viewport width, but with the general assumption, that - the widget generally gets higher. -
- -This results in the following rules: - -
    -
  1. Send always (when it changes) dw::core::Layout::viewportHeight - minus the maximal value of dw::core::View::getHScrollbarThickness as - argument to dw::core::Widget::setAscent, and 0 as argument to - dw::core::Widget::setDescent. - -
  2. There is a flag, dw::core::Layout::canvasHeightGreater, which is set - to false in the following cases: - -
      -
    • dw::core::Layout::addWidget, -
    • dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget), - and -
    • dw::core::Layout::viewportSizeChanged. -
    - - Whenever the canvas size is calculated (dw::core::Layout::resizeIdle), - and dw::core::Layout::canvasHeightGreater is false, a test is made, - whether the widget has in the meantime grown that high, that the second - argument should be set to true (i.e. the vertical scrollbar gets visible). - As soon as and dw::core::Layout::canvasHeightGreater is true, no such test - is done anymore. -
- -*/ diff --git a/doc/dw-layout-widgets.doc b/doc/dw-layout-widgets.doc deleted file mode 100644 index e0215562..00000000 --- a/doc/dw-layout-widgets.doc +++ /dev/null @@ -1,267 +0,0 @@ -/** \page dw-layout-widgets Layout and Widgets - -Both, the layouting and the drawing is delegated to a tree of -widgets. A widget represents a given part of the document, e.g. a text -block, a table, or an image. Widgets may be nested, so layouting and -drawing may be delegated by one widget to its child widgets. - -Where to define the borders of a widget, whether to combine different -widgets to one, or to split one widget into multiple ones, should be -considered based on different concerns: - -
    -
  • First, there are some restrictions of Dw: - -
      -
    • The allocation (this is the space a widget allocates at - a time) of a dillo widget is always rectangular, and -
    • the allocation of a child widget must be a within the allocation - of the parent widget. -
    - -
  • Since some widgets are already rather complex, an important goal - is to keep the implementation of the widget simple. - -
  • Furthermore, the granularity should not be too fine, because of the - overhead each single widget adds. -
- -For CSS, there will be a document tree on top of Dw, this will be -flexible enough when mapping the document structure on the widget -structure, so you should not have the document structure in mind. - -

Sizes

- -\ref dw-widget-sizes - - -

Styles

- -Each widget is assigned a style, see dw::core::style for more -informations. - - -

Iterators

- -Widgets must implement dw::core::Widget::iterator. There are several -common iterators: - -
    -
  • dw::core::EmptyIterator, and -
  • dw::core::TextIterator. -
- -Both hide the constructor, use the \em create method. - -These simple iterators only iterate through one widget, it does not -have to iterate recursively through child widgets. Instead, the type -dw::core::Content::WIDGET is returned, and the next call of -dw::core::Iterator::next will return the piece of contents \em after -(not within) this child widget. - -This makes implementation much simpler, for recursive iteration, there -is dw::core::DeepIterator. - - -

Anchors and Scrolling

- -\todo This section is not implemented yet, after the implementation, - the documentation should be reviewed. - -Here is a description, what is to be done for a widget -implementation. How to jump to anchors, set scrolling positions -etc. is described in \ref dw-usage. - -

Anchors

- -Anchors are position markers, which are identified by a name, which is -unique in the widget tree. The widget must care about anchors in three -different situations: - -
    -
  1. Adding an anchor is inititiated by a specific widget method, e.g. - dw::Textblock::addAnchor. Here, dw::core::Widget::addAnchor must be - called, - -
  2. Whenever the position of an anchor is changed, - dw::core::Widget::changeAnchor is called (typically, this is done - in the implementation of dw::core::Widget::sizeAllocateImpl). - -
  3. When a widget is destroyed, the anchor must be removed, by calling - dw::core::Widget::removeAnchor. -
- -All these methods are delegated to dw::core::Layout, which manages -anchors centrally. If the anchor in question has been set to jump to, -the viewport position is automatically adjusted, see \ref -dw-usage. - - -

Drawing

- -In two cases, a widget has to be drawn: - -
    -
  1. as a reaction on an expose event, -
  2. if the widget content has changed and it needs to be redrawn. -
- -In both cases, drawing is done by the implementation of -dw::core::Widget::draw, which draws into the view. - - -Each view provides some primitive methods for drawing, most should be -obvious. Note that the views do not know anything about dillo -widgets, and so coordinates have to be passed as canvas coordinates. - -A widget may only draw in its own allocation. If this cannot be -achieved, a clipping view can be used, this is described in -\ref dw-layout-views. Generally, drawing should then look like: - -\code -void Foo::draw (dw::core::View *view, dw::core::Rectangle *area) -{ - // 1. Create a clipping view. - dw::core::View clipView = - view->getClippingView (allocation.x, allocation.y, - allocation.width, getHeight ()); - - // 2. Draw into clip_view - clipView->doSomeDrawing (...); - - // 3. Draw the children, they receive the clipping view as argument. - dw::core::Rectangle *childArea - for () { - if (child->intersects (area, &childArea)) - child->draw (clipView, childArea); - } - - // 4. Merge - view->mergeClippingView (clipView); -} -\endcode - -Clipping views are expensive, so they should be avoided when possible. - -The second argument to dw::core::Widget::draw is the region, which has -to be drawn. This may (but needs not) be used for optimization. - -If a widget contains child widgets, it must explicitly draw these -children (see also code example above). For this, there is the useful -method dw::core::Widget::intersects, which returns, which area of the -child must be drawn. - -

Explicit Redrawing

- -If a widget changes its contents, so that it must be redrawn, it must -call dw::core::Widget::queueDrawArea or -dw::core::Widget::queueDraw. The first variant expects a region within -the widget, the second will cause the whole widget to be redrawn. This -will cause an asynchronous call of dw::core::Widget::draw. - -If only the size changes, a call to dw::core::Widget::queueResize is -sufficient, this will also queue a complete redraw (see \ref -dw-widget-sizes.) - - -

Mouse Events

- -A widget may process mouse events. The view (\ref dw-layout-views) -passes mouse events to the layout, which then passes them to the -widgets. There are two kinds of mouse events: - -
    -
  • events returning bool, and -
  • events returning nothing (void). -
- -The first group consists of: - -
    -
  • dw::core::Widget::buttonPressImpl, -
  • dw::core::Widget::buttonReleaseImpl, and -
  • dw::core::Widget::motionNotifyImpl. -
- -For these events, a widget returns a boolean value, which denotes, -whether the widget has processed this event (true) or not (false). In -the latter case, the event is delegated according to the following -rules: - -
    -
  1. First, this event is passed to the bottom-most widget, in which - allocation the mouse position is in. -
  2. If the widget does not process this event (returning false), it is - passed to the parent, and so on. -
  3. The final result (whether \em any widget has processed this event) is - returned to the view. -
- -The view may return this to the UI toolkit, which then interprets this -in a similar way (whether the viewport, a UI widget, has processed -this event). - -These events return nothing: - -
    -
  • dw::core::Widget::enterNotifyImpl and -
  • dw::core::Widget::leaveNotifyImpl. -
- -since they are bound to a widget. - -When processing mouse events, the layout always deals with two -widgets: the widget, the mouse pointer was in, when the previous mouse -event was processed, (below called the "old widget") and the widget, -in which the mouse pointer is now ("new widget"). - -The following paths are calculated: - -
    -
  1. the path from the old widget to the nearest common ancestor of the old - and the new widget, and -
  2. the path from this ancestor to the new widget. -
- -For the widgets along these paths, dw::core::Widget::enterNotifyImpl -and dw::core::Widget::leaveNotifyImpl are called. - -

Signals

- -If a caller outside of the widget is interested in these events, he -can connect a dw::core::Layout::LinkReceiver. For those events with a -boolean return value, the results of the signal emission is regarded, -i.e. the delegation of an event to the parent of the widget can be -stopped by a signal receiver returning true, even if the widget method -returns false. - -First, the widget method is called, then (in any case) the signal is -emitted. - -

Selection

- -If your widget has selectable contents, it should delegate the events -to dw::core::SelectionState (dw::core::Layout::selectionState). - - -

Miscellaneous

- -

Cursors

- -Each widget has a cursor, which is set by -dw::core::Widget::setCursor. If a cursor is assigned to a part of a -widget, this widget must process mouse events, and call -dw::core::Widget::setCursor explicitly. - -(This will change, cursors should become part of -dw::core::style::Style.) - -

Background

- -Backgrounds are part of styles -(dw::core::style::Style::backgroundColor). If a widget assigns -background colors to parts of a widget (as dw::Table does for rows), -it must call dw::core::Widget::setBgColor for the children inside this -part. - -*/ diff --git a/doc/dw-line-breaking.doc b/doc/dw-line-breaking.doc deleted file mode 100644 index 14ab97c4..00000000 --- a/doc/dw-line-breaking.doc +++ /dev/null @@ -1,470 +0,0 @@ -/** \page dw-line-breaking Changes in Line-Breaking and Hyphenation - -
Info: -Should be incorporated into dw::Textblock.
- -Introduction -============ - -For the implementation of hyphenation in dillo, not only a -hyphenation algorithm was implemented, but also, the line breaking was -changed to a simple optimization per line. Aside from the improvement -by this change per se, an important aspect is the introduction of -"penalties". Before this change, dillo put all words into a line which -fitted into it; now, a "badness" is calculated for a possible -breakpoint, and the best breakpoint, i. e. the breakpoint with the -smallest value for "badness", is chosen. This can be simply refined -to define "good" and "bad" breakpoints by assigning a "penalty"; the -best breakpoint is then the one with the smallest value of "badness + -penalty". Details can be found below. - -Example: Normal spaces have a penalty of 0, while hyphenation points -get a penalty of, say, 1, since hyphenation is generally considered as -a bit "ugly" and should rather be avoided. Consider a situation where -the word "dillo" could be hyphenated, with the following badnesses: - -- before "dillo": 0.6; -- between "dil-" and "lo": 0.2; -- after "dillo": 0.5. - -Since the penalty is added, the last value is the best one, so "dillo" -is put at the end of the line, without hyphenation. - -Under other circumstances (e. g. narrower lines), the values -might be different: - -- before "dillo": infinite; -- between "dil-" and "lo": 0.3; -- after "dillo": 1.5. - -In this case, even the addition of the penalty makes hyphenation the -best choice. - - -Literature -========== - -Breaking Paragraphs Into Lines ------------------------------- - -Although dillo does not (yet?) implement the algorithm TEX -uses for line breaking, this document shares much of the notation used -by the article *Breaking Paragraphs Into Lines* by Donald E. Knuth and -Michael F. Plass; originally published in: Software -- Practice and -Experience **11** (1981), 1119-1184; reprinted in: *Digital -Typography* by Donalt E. Knuth, CSLI Publications 1999. Anyway an -interesting reading. - -Hyphenation ------------ - -Dillo uses the algorithm by Frank Liang, which is described in his -doctoral dissertation found at http://www.tug.org/docs/liang/. There -is also a description in chapter H ("Hyphenation") of *The -TEXbook* by Donald E. Knuth, Addison-Wesley 1984. - -Pattern files can be found at -http://www.ctan.org/tex-archive/language/hyphenation. - - -Overview of Changes -=================== - -Starting with this change, dw/textblock.cc has been split up; anything -related to line breaking has been moved into -dw/textblock_linebreaking.cc. This will also be done for other aspects -like floats. (Better, however, would be a clean logical split.) - -An important change relates to the way that lines are added: before, -dillo would add a line as soon as a new word for this line was -added. Now, a line is added not before the *last* word of this line is -known. This has two important implications: - -- Some values in dw::Textblock::Line, which represented values - accumulated within the line, could be removed, since now, these - values can be calculated simply in a loop. -- On the other hand, this means that some words may not belong to any - line. For this reason, in some cases (e. g. in - dw::Textblock::sizeRequestImpl) dw::Textblock::showMissingLines is - called, which creates temporary lines, which must, under other - circumstances, be removed again by - dw::Textblock::removeTemporaryLines, since they have been created - based on limited information, and so possibly in a wrong way. (See - below for details.) - -When a word can be hyphenated, an instance of dw::Textblock::Word is -used for each part. Notice that soft hyphens are evaluated -immediately, but automatic hyphenation is done in a lazy way (details -below), so the number of instances may change. There are some new -attributes: only when dw::Textblock::Word::canBeHyphenated is set to -*true*, automatic hyphenation is allowed; it is set to false when soft -hyphens are used for a word, and (of course) by the automatic -hyphenation itself. Furthermore, dw::Textblock::Word::hyphenWidth -(more details in the comment there) has to be included when -calculating line widths. - -Some values should be configurable: dw::Textblock::HYPHEN_BREAK, the -penalty for hyphens. Also dw::Textblock::Word::stretchability, -dw::Textblock::Word::shrinkability, which are both set in -dw::Textblock::addSpace. - - -Criteria for Line-Breaking -========================== - -Before these changes to line breaking, a word (represented by -dw::Textblock::Word) had the following attributes related to -line-breaking: - -- the width of the word itself, represented by - dw::Textblock::Word::size; -- the width of the space following the word, represented by - dw::Textblock::Word::origSpace. - -In a more mathematical notation, the \f$i\f$th word has a width -\f$w_i\f$ and a space \f$s_i\f$. - -A break was possible, when there was a space between the two words, -and the first possible break was chosen. - -With hyphenation, the criteria are refined. Hyphenation should only be -used when otherwise line breaking results in very large spaces. We -define: - -- the badness \f$\beta\f$ of a line, which is greater the more the - spaces between the words differ from the ideal space; -- a penalty \f$p\f$ for any possible break point. - -The goal is to find those break points, where \f$\beta + p\f$ is -minimal. - -Examples for the penalty \f$p\f$: - -- 0 for normal line breaks (between words); -- \f$\infty\f$ to prevent a line break at all costs; -- \f$-\infty\f$ to force a line -- a positive, but finite, value for hyphenation points. - -So we need the following values: - -- \f$w_i\f$ (the width of the word \f$i\f$ itself); -- \f$s_i\f$ (the width of the space following the word \f$i\f$); -- the stretchability \f$y_i\f$, a value denoting how much the space - after word\f$i\f$ can be stretched (typically \f${1\over 2} s_i\f$ - for justified text; otherwise 0, since the spaces are not - stretched); -- the shrinkability \f$y_i\f$, a value denoting how much the space - after word\f$i\f$ can be shrunken (typically \f${1\over 3} s_i\f$ - for justified text; otherwise 0, since the spaces are not shrinked); -- the penalty \f$p_i\f$, if the line is broken after word \f$i\f$; -- a width \f$h_i\f$, which is added, when the line is broken after - word \f$i\f$. - -\f$h_i\f$ is the width of the hyphen, if the word \f$i\f$ is a part of -the hyphenated word (except the last part); otherwise 0. - -Let \f$l\f$ be the (ideal) width (length) of the line, which is -e. at the top given by the browser window width. Furthermore, all words -from \f$a\f$ to \f$b\f$ are added to the line. \f$a\f$ is fixed: we do -not modify the previous lines anymore; but our task is to find a -suitable \f$b\f$. - -We define: - -\f[W_a^b = \sum_{i=a}^{b} w_i + \sum_{i=a}^{b-1} s_i + h_b\f] - -\f[Y_a^b = {Y_0}_a^b + \sum_{i=a}^{b-1} y_i\f] - -\f[Z_a^b = {Z_0}_a^b + \sum_{i=a}^{b-1} z_i\f] - - -\f$W_a^b\f$ is the total width, \f$Y_a^b\f$ the total stretchability, -and \f$Z_a^b\f$ the total shrinkability. \f${Y_0}_a^b\f$ and -\f${Z_0}_a^b\f$ are the stretchability and shrinkability defined per -line, and applied at the borders; they are 0 for justified text, but -\f${Y_0}_a^b\f$ has a positive value otherwise, see below for details. - -Furthermore the *adjustment ratio* \f$r_a^b\f$: - -- in the ideal case that \f$W_a^b = l\f$: \f$r_a^b = 0\f$; -- if \f$W_a^b < l\f$: \f$r_a^b = (l - W_a^b) / Y_a^b\f$ - (\f$r_a^b < 0\f$ in this case); -- if \f$W_a^b > l\f$: \f$r_a^b = (l - W_a^b) / Z_a^b\f$ - (\f$r_a^b < 0\f$ in this case). - -The badness \f$\beta_a^b\f$ is defined as follows: - -- if \f$r_a^b\f$ is undefined or \f$r_a^b < -1\f$: \f$\beta_a^b = \infty\f$; -- otherwise: \f$\beta_a^b = |r_a^b|^3\f$ - -The goal is to find the value of \f$b\f$ where \f$\beta_a^b + p_b\f$ -is minimal. (\f$a\f$ is given, since we do not modify the previous -lines.) - -After a couple of words, it is not predictable whether this minimum -has already been reached. There are two cases where this is possible -for a given \f$b'\f$: - -- \f$\beta_{b'}^a = \infty\f$ (line gets too tight): - \f$a \le b < b'\f$, the minimum has to be searched between these two - values; -- \f$p_{b'} = -\infty\f$ (forced line break): - \f$a \le b \le b'\f$ (there may be another minimum of - \f$\beta_a^b\f$ before; note the \f$\le\f$ instead of \f$<\f$). - -This leads to a problem that the last words of a text block are not -displayed this way, since they do not fulfill these rules for being -added to a line. For this reason, there are "temporary" lines already -described above. - -(Note that the actual calculation differs from this description, since -integer arithmetic is used for performance, which make the actual -code more complicated. See dw::Textblock::BadnessAndPenalty for -details.) - -Ragged Borders --------------- - -For other than justified text (left-, right-aligned and centered), the -spaces between the words are not shrinked or stretched (so \f$y_i\f$ -and \f$z_i\f$ are 0), but additional space is added to the left or -right border or to both. For this reason, an additional stretchability -\f${Y_0}_a^b\f$ is added (see definition above). Since this space at -the border is 0 in an ideal case (\f$W_a^b = l\f$), it cannot be -shrunken, so \f${Z_0}_a^b\f$ is 0. - -This is not equivalent to the calculation of the total stretchability -as done for justified text, since in this case, the stretchability -depends on the number of words: consider the typical case that all -spaces and stretchabilities are equal (\f$y_a = y_{a + 1} = \ldots = -y_b\f$). With \f$n\f$ words, the total strechability would be \f$n -\cdot y_a\f$, so increase with an increasing number of words -(\f$y_a\f$ is constant). This is correct for justified text, but for -other alignments, where only one space (or two, for centered text) is -changed, this would mean that a line with many narrow words is more -stretchable than a line with few wide words. - -It is obvious that left-aligned text can be handled in the same way as -right-aligned text. [... Centered text? ...] - -The default value for the stretchability is the line height without -the space between the lines (more precisely: the maximum of all word -heights). The exact value not so important when comparing different -possible values for the badness \f$\beta_a^b\f$, when \f${Y_0}_a^b\f$ -is nearly constant for different \f$b\f$ (which is the case for the -actual value), but it is important for the comparison with penalties, -which are constant. To be considered is also that for non-justified -text, hyphenation is differently (less) desirable; this effect can be -achieved by enlarging the stretchability, which will lead to a smaller -badness, and so make hyphenation less likely. The user can configure -the stretchability by changing the preference value -*stretchability_factor* (default: 1.0). - -(Comparison to TEX: Knuth and Plass describe a method for -ragged borders, which is effectively the same as described here (Knuth -1999, pp. 93--94). The value for the stretchability of the line -is slightly less, 1 em (ibid., see also p. 72 for the -definition of the units). However, this article suggests a value for -the hyphenation penalty, which is ten times larger than the value for -justified text; this would suggest a larger value for -*stretchability_factor*.) - - -Hyphens -======= - -Words (instances of dw::Textblock::Word), which are actually part of a -hyphenated word, are always drawn as a whole, not seperately. This -way, the underlying platform is able to apply kerning, ligatures, etc. - -Calculating the width of such words causes some problems, since it is -not required that the width of text "AB" is identical to the width of -"A" plus the width of "B", just for the reasons mentioned above. It -gets even a bit more complicated, since it is required that a word -part (instance of dw::Textblock::Word) has always the same length, -independent of whether hyphenation is applied or not. Furthermore, the -hyphen length is fixed for a word; for practical reasons, it is always -the width of a hyphen, in the given font. - -For calculating the widths, consider a word of four syllables: -A-B-C-D. There are 3 hyphenation points, and so 23 = 8 -possible ways of hyphenation: ABCD, ABC-D, AB-CD, AB-C-D, A-BCD, -A-BC-D, A-B-CD, A-B-C-D. (Some of them, like the last one, are only -probable for very narrow lines.) - -Let w(A), w(B), w(C), w(D) be the word widths (part of -dw::Textblock::Word::size), which have to be calculated, and l be a -shorthand for dw::core::Platform::textWidth. Without considering -this problem, the calculation would be simple: w(A) = l(A) -etc. However, it gets a bit more complicated. Since all -non-hyphenations are drawn as a whole, the following conditions can be -concluded: - -- from drawing "ABCD" (not hyphenated at all): w(A) + w(B) + w(C) + - w(D) = l(ABCD); -- from drawing "BCD", when hyphenated as "A-BCD" ("A-" is not - considered here): w(B) + w(C) + w(D) = l(BCD); -- likewise, from drawing "CD" (cases "AB-CD" and "A-B-CD"): w(C) + - w(D) = l(CD); -- finally, for the cases "ABC-D", "AB-C-D", "A-BC-D", and "A-B-C-D": - w(D) = l(D). - -So, the calculation is simple: - -- w(D) = l(D) -- w(C) = l(CD) - w(D) -- w(B) = l(BCD) - (w(C) + w(D)) -- w(A) = l(ABCD) - (w(B) + w(C) + w(D)) - -For calculation the hyphen widths, the exact conditions would be -over-determined, even when the possibility for individual hyphen -widths (instead of simply the text width of a hyphen character) would -be used. However, a simple approach of fixed hyphen widths will have -near-perfect results, so this is kept simple. - - -Automatic Hyphenation -===================== - -When soft hyphens are used, words are immediately divided into -different parts, and so different instances of -dw::Textblock::Word. Automatic hyphenation (using Liang's algorithm) -is, however, not applied always, but only when possibly needed, after -calculating a line without hyphenation: - -- When the line is tight, the last word of the line is hyphenated; - possibly this will result in a line with less parts of this word, - and so a less tight line. -- When the line is loose, and there is another word (for the next - line) available, this word is hyphenated; possibly, some parts of - this word are taken into this line, making it less loose. - -After this, the line is re-calculated. - -A problem arrises when the textblock is rewrapped, e. g. when the -user changes the window width. In this case, some new instances of -dw::Textblock::Word must be inserted into the word list, -dw::Textblock::words. This word list is implemented as an array, which -is dynamically increased; a simple approach would involve moving all -of the n elements after position i, so -n - i steps are necessary. This would not be a -problem, since O(n) steps are necessary; however, this will be -necessary again for the next hyphenated word (at the end of a -following line), and so on, so that -(n - i1) + -(n - i2) + ..., with -i1 < i2 < ..., -which results in O(n2) steps. For this reason, the word -list is managed by the class lout::misc::NotSoSimpleVector, which uses -a trick (a second array) to deal with exactly this problem. See there -for more details. - - -Tests -===== - -There are test HTML files in the test directory. Also, there is -a program testing automatic hyphenation, test/liang, which can -be easily extended. - - -Bugs and Things Needing Improvement -=================================== - -High Priority -------------- - -None. - -Medium Priority ---------------- - -None. - -Low Priority ------------- - -**Mark the end of a paragraph:** Should dw::core::Content::BREAK still -be used? Currently, this is redundant to -dw::Textblock::BadnessAndPenalty. - -Solved (Must Be Documented) ---------------------------- - -These have been solved recently and should be documented above. - -*Bugs in hyphenation:* There seem to be problems when breaking words -containing hyphens already. Example: "Abtei-Stadt", which is divided -into "Abtei-" and "Stadt", resulting possibly in -"Abtei--[new line]Stadt". See also below under -"Medium Priority", on how to deal with hyphens and dashes. - -**Solution:** See next. - -*Break hyphens and dashes:* The following rules seem to be relevant: - -- In English, an em-dash is used with no spaces around. Breaking - before and after the dash should be possible, perhaps with a - penalty > 0. (In German, an en-dash (Halbgeviert) with spaces around - is used instead.) -- After a hyphen, which is part of a compound word, a break should be - possible. As described above ("Abtei-Stadt"), this collides with - hyphenation. - -Where to implement? In the same dynamic, lazy way like hyphenation? As -part of hyphenation? - -Notice that Liang's algorithm may behave different regarding hyphens: -"Abtei-Stadt" is (using the patterns from CTAN) divided into "Abtei-" -and "Stadt", but "Nordrhein-Westfalen" is divided into "Nord", -"rhein-West", "fa", "len": the part containing the hyphen -("rhein-West") is untouched. (Sorry for the German words; if you have -got English examples, send them me.) - -**Solution for both:** This has been implemented in -dw::Textblock::addText, in a similar way to soft hyphens. Liang's -algorithm now only operates on the parts: "Abtei" and "Stadt"; -"Nordrhein" and "Westfalen". - -*Hyphens in adjacent lines:* It should be simple to assign a larger -penalty for hyphens, when the line before is already hyphenated. This -way, hyphens in adjacent lines are penalized further. - -**Solved:** There are always two penalties. Must be documented in -detail. - -*Incorrect calculation of extremes:* The minimal width of a text block -(as part of the width extremes, which are mainly used for tables) is -defined by everything between two possible breaks. A possible break -may also be a hyphenation point; however, hyphenation points are -calculated in a lazy way, when the lines are broken, and not when -extremes are calculated. So, it is a matter of chance whether the -calculation of the minimal width will take the two parts "dil-" and -"lo" into account (when "dillo" has already been hyphenated), or only -one part, "dillo" (when "dillo" has not yet been hyphenated), -resulting possibly in a different value for the minimal width. - -Possible strategies to deal with this problem: - -- Ignore. The implications should be minimal. -- Any solution will make it neccessary to hyphenate at least some - words when calculating extremes. Since the minimal widths of all - words are used to calculate the minimal width of the text block, the - simplest approach will hyphenate all words. This would, of course, - eliminate the performance gains of the current lazy approach. -- The latter approach could be optimized in some ways. Examples: (i) - If a word is already narrower than the current accumulated value for - the minimal width, it makes no sense to hyphenate it. (ii) In other - cases, heuristics may be used to estimate the number of syllables, - the width of the widest of them etc. - -**Solved:** Hyphenated parts of a word are not considered anymore for -width extremes, but only whole words. This is also one reason for the -introduction of the paragraphs list. - -**Also:** - -- Configuration of penalties. - -*/ diff --git a/doc/dw-map.doc b/doc/dw-map.doc deleted file mode 100644 index aebeb7da..00000000 --- a/doc/dw-map.doc +++ /dev/null @@ -1,59 +0,0 @@ -/** \page dw-map Dillo Widget Documentation Map - -This maps includes special documentations as well as longer comments -in the sources. Arrows denote references between the documents. - -\dot -digraph G { - rankdir=LR; - node [shape=record, fontname=Helvetica, fontsize=8]; - fontname=Helvetica; fontsize=8; - - dw_overview [label="Dillo Widget Overview", URL="\ref dw-overview"]; - dw_usage [label="Dillo Widget Usage", URL="\ref dw-usage"]; - dw_layout_views [label="Layout and Views", URL="\ref dw-layout-views"]; - dw_layout_widgets [label="Layout and Widgets", - URL="\ref dw-layout-widgets"]; - dw_widget_sizes [label="Sizes of Dillo Widgets", - URL="\ref dw-widget-sizes"]; - dw_changes [label="Changes to the GTK+-based Release Version", - URL="\ref dw-changes"]; - dw_images_and_backgrounds [label="Images and Backgrounds in Dw", - URL="\ref dw-images-and-backgrounds"]; - dw_Image [label="dw::Image", URL="\ref dw::Image"]; - dw_core_Imgbuf [label="dw::core::Imgbuf", URL="\ref dw::core::Imgbuf"]; - dw_core_SelectionState [label="dw::core::SelectionState", - URL="\ref dw::core::SelectionState"]; - dw_core_style [label="dw::core::style", URL="\ref dw::core::style"]; - dw_Table [label="dw::Table", URL="\ref dw::Table"]; - dw_Textblock [label="dw::Textblock", URL="\ref dw::Textblock"]; - dw_core_ui [label="dw::core::ui", URL="\ref dw::core::ui"]; - - dw_overview -> dw_changes; - dw_overview -> dw_usage; - dw_overview -> dw_core_style; - dw_overview -> dw_core_ui; - dw_overview -> dw_images_and_backgrounds; - dw_overview -> dw_layout_widgets; - dw_overview -> dw_widget_sizes; - dw_overview -> dw_layout_views; - - dw_usage -> dw_Table; - dw_usage -> dw_Textblock; - dw_usage -> dw_core_style; - dw_usage -> dw_core_ui; - dw_usage -> dw_images_and_backgrounds; - - dw_layout_widgets -> dw_widget_sizes; - dw_layout_widgets -> dw_core_SelectionState; - - dw_widget_sizes -> dw_Table; - dw_widget_sizes -> dw_Textblock; - - dw_images_and_backgrounds -> dw_core_Imgbuf; - dw_images_and_backgrounds -> dw_Image; - - dw_core_style -> dw_Textblock; -} -\enddot -*/ \ No newline at end of file diff --git a/doc/dw-out-of-flow-2.doc b/doc/dw-out-of-flow-2.doc deleted file mode 100644 index d9d70565..00000000 --- a/doc/dw-out-of-flow-2.doc +++ /dev/null @@ -1,69 +0,0 @@ -/** \page dw-out-of-flow-2 Handling Elements Out Of Flow (notes 2) - -This has to be integrated into \ref dw-out-of-flow. - -Constructing a page with floats -------------------------------- -When a page is constructed (dw::Textblock::addWord), the *generating* -block tells the positions of floats (or, generally, widgets out of -flow) via dw::OutOfFlowMgr::tellPosition. This method considers -already collisions with other floats (only previous floats; floats -following this float are not considered); after the call, -dw::OutOfFlowMgr::getBorder will return correct values. - -dw::OutOfFlowMgr::tellPosition also checks for overlaps of this float -with other textblocks, except this textblock (the *generator*, which -is just constructed, so nothing has to be done). The fact that the -position of the float is the top, and so the float has only an -allocation below this position, leads to the effect that only the -textblocks following the generator are affected. (**Check:** Can the -search be limited here?) When a page is constructed, no textblocks -should be following the generating block, so no textblocks are -affected. - -**Todo:** Clarify details of line breaking (\ref dw-line-breaking). - -Float changes its size ----------------------- -The float itself will call queueResize, which will result in a call of -markSizeChange for the *containing* block, which will then call -dw::OutOfFlowMgr::markSizeChange. Here, the vloat is only *marked* as -dirty; the size will be calculated later (in -dw::OutOfFlowMgr::ensureFloatSize). - -This will trigger the resize idle function, so sizeRequest and -sizeAllocate for all floats and textblocks. In this run, -dw::OutOfFlowMgr::hasRelationChanged will return *true*, and so result -in a call of dw::Textblock::borderChanged, and trigger a second run of -the resize idle function, dealing correctly with the new size. - -(This case is handles in a not perfectly optimal way, since two runs -of the resize idle function are neccessary; but size changes of floats -is not a very common case. - -When a page is constructed (see above), a changing size of a float -currently constructed typically only affects the most bottom -textblock; the other textblocks are not covered by this float.) - -**Error:** In this case, new collisions are not yet considered. - - -Changing the width of the page ------------------------------- - -When the page width is changed, this will result in a reconstruction -of the page; see *Constructing a page with floats*. Anyway, checking -for overlaps will play a more important role. This is handled in an -optimal way by dw::OutOfFlowMgr::hasRelationChanged. - -**Check:** Are "cascades" avoided, like this: - -1. All textblocks are constructed. A float in textblock 1 overlaps - with textblock 2, so dw::Textblock::borderChanged is called for - textblock 2. -2. In another resize idle run, textblock 2 is constructed again. A - float in textblock 2 overlaps with textblock 3, so that - dw::Textblock::borderChanged is called for textblock 3. -3. Etc. - -*/ \ No newline at end of file diff --git a/doc/dw-out-of-flow-floats.doc b/doc/dw-out-of-flow-floats.doc deleted file mode 100644 index 53c6b220..00000000 --- a/doc/dw-out-of-flow-floats.doc +++ /dev/null @@ -1,121 +0,0 @@ -/** \page dw-out-of-flow-floats Handling Elements Out Of Flow: Floats - -(Note: Bases on work at , I plan -to split the documentation on elements out of flow into different -parts: general part, floats, positioned elements. In this document, -informations about floats are collected.) - - -GB lists and CB lists -===================== - -Floats generated by a block which is not yet allocated are initially -put into a list related to the *generator*: - -- dw::OutOfFlowMgr::TBInfo::leftFloatsGB or -- dw::OutOfFlowMgr::TBInfo::rightFloatsGB. - -These lists are also called GB lists. - -Floats of allocated generators are put into lists related to the -*container* (called CB lists): - -- dw::OutOfFlowMgr::leftFloatsCB or -- dw::OutOfFlowMgr::rightFloatsCB. - -As soon as the container is allocated, all floats are moved from the -GB lists to the CB lists (dw::OutOfFlowMgr::sizeAllocateStart → -dw::OutOfFlowMgr::moveFromGBToCB). - -Here, it is important to preserve the *generation order* (for reasons, -see below: *Sorting floats*), i. e. the order in which floats have -been added (dw::OutOfFlowMgr::addWidgetOOF). This may become a bit -more complicated in a case like this: - - - - - -
-
float 1
-
-
float 2
-
-
float 3
-
- - -The floats are generated in this order: - -- \#fl-1 (generated by \#bl-1), -- \#fl-2 (generated by \#bl-2), -- \#fl-3 (generated by \#bl-1). - -Since the floats must be moved into the CB list in this order, it -becomes clear that the floats from one GB list cannot be moved at -once. For this reason, each float is assigned a "mark", which is -different from the last one as soon as the generator is *before* the -generator of the float added before. In the example above, there are -three generators: body, \#bl-1, and \#bl-2 (in this order), and floats -are assigned these marks: - -- \#fl-1: 0, -- \#fl-2: also 0, -- \#fl-3 is assigned 1, since its generator (\#bl-1) lies before the - last generator (\#bl-2). - -dw::OutOfFlowMgr::moveFromGBToCB will then iterate over all marks, so -that the generation order is preserved. - - -Sorting floats -============== - -Floats are sorted, to make binary search possible, in these lists: - -- for each generator: dw::OutOfFlowMgr::TBInfo::leftFloatsGB and - dw::OutOfFlowMgr::TBInfo::rightFloatsGB; -- for the container: dw::OutOfFlowMgr::leftFloatsCB and - dw::OutOfFlowMgr::rightFloatsCB. - -The other two lists, dw::OutOfFlowMgr::leftFloatsAll and -dw::OutOfFlowMgr::rightFloatsAll are not sorted at all. - -New floats are always added to the end of either list; this order is -called *generation order*. See also above: *GB lists and CB lists*. - -On the other hand, there are different sorting criteria, implemented -by different comparators, so that different kinds of keys may be used -for searching. These sorting criteria are equivalent to the generation -order. - -dw::OutOfFlowMgr::Float::CompareSideSpanningIndex compares -*sideSpanningIndex* (used to compare floats to those on the respective -other side); if you look at the definition -(dw::OutOfFlowMgr::addWidgetOOF) it becomes clear that this order is -equivalent to the generation order. - -dw::OutOfFlowMgr::Float::CompareGBAndExtIndex compares *externalIndex* -for floats with same generators, otherwise: (i) if one generator (T1) -is a direct anchestor of the other generator (T2), the child of T1, -which is an anchestor of, or identical to, T2 is compared to the float -generated by T1, using *externalIndex*, as in this example: - - T1 -+-> child --> ... -> T2 -> Float - `-> Float - -Otherwise, the two blocks are compared, according to their position in -dw::OutOfFlowMgr::tbInfos: - - common anchestor -+-> ... --> T1 -> Float - `-> ... --> T2 -> Float - -This is equivalent to the generation order, as long it is ensured that -*externalIndex* reflects the generation order within a generating -block, for both floats and child blocks. - -dw::OutOfFlowMgr::Float::ComparePosition ... - -*/ diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc deleted file mode 100644 index ea4a52bc..00000000 --- a/doc/dw-out-of-flow.doc +++ /dev/null @@ -1,214 +0,0 @@ -/** \page dw-out-of-flow Handling Elements Out Of Flow - - -
Info: -Should be incorporated into dw::Textblock.
- -Introduction -============ - -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): - - -
    -
  • Some text.
  • -
  • -
    Some longer text, so - that the effect described in this passage can be - demonstrated. -
    - Some more and longer text.
  • -
  • Final text. Plus some more to demonstrate how text flows - around the float on the right side.
  • -
- -which may be rendered like this - -\image html dw-floats-01.png - -The float (the DIV section, yellow in the image) is defined -("generated") within the list item (blue), 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. - -(Notice also that other text blocks must regard floats to calculate -their borders, and so their size. In this example, the following list -item (green) must consider the position of the float. This is -discussed in detail in the next section.) - -Both in this text and the code, generating and containing block are -abbreviated with **GB** and **CB**, respectively. - - -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 rules -which should be defined in this document). - -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 | - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - | left float index | 0 | 0 | 1 | - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - | right float index | 1 | 0 | 1 | - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - | absolutely positioned index | 1 | 1 | - +---+ - - - +---+---+- - - - - -+---+---+---+---+ - -Details are hidden by static inline methods of dw::OutOfFlowMgr. - - -The sizeRequest/sizeAllocate problem -======================================== - -*See also:* \ref dw-widget-sizes, especially the section *Rules for -Methods Related to Resizing*. - -The size/position model of ::dw consists mainly of the following two -steps: - -1. First, the size of the toplevel widget is calculated. Size - calculation typically depends on the sizes of the widgets, which - are calculated recursively, but not more. -2. After this, the toplevel widget is allocated at position (0, 0), - with the previosly calculated size. Each widget must allocate its - children; here, the condition for the toplevel widget (allocated - size equals requested size) is not necessary; instead, each widget - may be allocated at every size. - -Especially for floats, this model becomes a bit difficult, for reasons -described below. For the solutions, much is centralized at the level -of the containing block, which delegates most to an instance of -dw::OutOfFlowMgr (details below). - -**The size of a widget depends on the size not only of the children.** -In the example above, the last list item (green, following the -generating list item) must know the size of the the float (which is -not a child or, generally, descendant) to determine the borders, which -is done in dw::Textblock::sizeRequestImpl. - -For this, the size model has been extended (see \ref dw-widget-sizes, -section *Rules for Methods Related to Resizing*): *sizeRequest* can be -called within *sizeRequestImpl* for other widgets that children (with -some caution). Namely, dw::Textblock::sizeRequestImpl calls -dw::core::Widget::sizeRequest for the float, via -dw::OutOfFlowMgr::getBorder and dw::OutOfFlowMgr::ensureFloatSize. - -**The size of a widget depends on the allocation of another widget.** -In the example above, both list items (blue and green) must know the -position of the float widget, within dw::Textblock::sizeRequestImpl, -to calculate the borders. The position, however, is stored in the -allocation, which is typically calculated later. - -Here, two cases must be distinguished. The position of a float is -always **relative to its generating block**, so for calculating the -borders for the generating block, the allocation needs not to be -know. For other textblocks, it needs to be known, so the calculation -of the borders will ignore floats generated by other textblocks, until -all widgets are allocated. The latter will call (when neccessary) -dw::core::Widget::queueResize, so that all border calculations are -repeated. See below (*hasRelationChanged*) for details. - -Generally, this pattern (distinguishing between GB and CB) can be -found everywhere in dw::OutOfFlowMgr. - -For details see: - -- dw::OutOfFlowMgr::getLeftBorder, dw::OutOfFlowMgr::getRightBorder, - dw::OutOfFlowMgr::getBorder (called by the first two), and - especially, dw::OutOfFlowMgr::getFloatsListForTextblock (called by - the latter), where these three cases are distinguished; -- dw::OutOfFlowMgr::sizeAllocateStart, - dw::OutOfFlowMgr::sizeAllocateEnd which are called by the containing - block. - -(This could be solved in a more simple, elegant way, when -*sizeRequest* would depend on the position. This is, however, only a -vague idea, perhaps not even feasible, and for which there are no -concrete plans, certainly not in \ref dw-grows.) - - -Implementation details -====================== - -- CB and GB lists (general pattern) (see previous section) -- binary search; different search criteria, how they accord -- lastLeftTBIndex, lastRightTBIndex etc. -- limitiation of search; extIndex etc. - - -How *hasRelationChanged* works -============================== - -... - - -Integration of line breaking and floats -======================================= - -(Positioning of floats, loop, recent works.) - - -Absolute and fixed positiones -============================= - -See . - -*/ \ No newline at end of file diff --git a/doc/dw-overview.doc b/doc/dw-overview.doc deleted file mode 100644 index 0c4ffb53..00000000 --- a/doc/dw-overview.doc +++ /dev/null @@ -1,158 +0,0 @@ -/** \page dw-overview Dillo Widget Overview - -Note: If you are already familiar with the Gtk+-based version of Dw, -read \ref dw-changes. - - -The module Dw (Dillo Widget) is responsible for the low-level rendering of -all resources, e.g. images, plain text, and HTML pages (this is the -most complex type). Dw is \em not responsible for parsing HTML, or -decoding image data. Furthermore, the document tree, which is planned -for CSS, is neither a part of Dw, instead, it is a new module on top -of Dw. - -The rendering, as done by Dw, is split into two phases: - -
    -
  • the \em layouting, this means calculating the exact positions of - words, lines, etc. (in pixel position), and -
  • the \em drawing, i.e. making the result of the layouting visible - on the screen. -
- -The result of the layouting allocates an area, which is called -\em canvas. - -

Structure

- -The whole Dw module can be split into the following parts: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="open", fontname=Helvetica, fontsize=10, - labelfontname=Helvetica, labelfontsize=10, - color="#404040", labelfontcolor="#000080"]; - - subgraph cluster_core { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="Platform independent core"; - - Layout [URL="\ref dw::core::Layout"]; - Platform [URL="\ref dw::core::Platform", color="#ff8080"]; - View [URL="\ref dw::core::View", color="#ff8080"]; - Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; - } - - subgraph cluster_fltk { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="FLTK specific part (as an\nexample for the platform specific\n\ -implementations)"; - - subgraph cluster_fltkcore { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="FLTK core"; - - FltkPlatform [URL="\ref dw::fltk::FltkPlatform"]; - FltkView [URL="\ref dw::fltk::FltkView", color="#ff8080"]; - } - - FltkViewport [URL="\ref dw::fltk::FltkViewport"]; - FltkPreview [URL="\ref dw::fltk::FltkPreview"]; - } - - subgraph cluster_widgets { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="Platform independent widgets"; - - Textblock [URL="\ref dw::Textblock"]; - AlignedTextblock [URL="\ref dw::AlignedTextblock", color="#a0a0a0"]; - Table [URL="\ref dw::Table"]; - Image [URL="\ref dw::Image"]; - etc1 [label="..."]; - etc2 [label="..."]; - } - - Layout -> Platform [headlabel="1", taillabel="1"]; - Layout -> View [headlabel="*", taillabel="1"]; - - Layout -> Widget [headlabel="1", taillabel="1", label="topLevel"]; - Widget -> Widget [headlabel="*", taillabel="1", label="children"]; - - Widget -> Textblock [arrowhead="none", arrowtail="empty", dir="both"]; - Widget -> Table [arrowhead="none", arrowtail="empty", dir="both"]; - Widget -> Image [arrowhead="none", arrowtail="empty", dir="both"]; - Widget -> etc1 [arrowhead="none", arrowtail="empty", dir="both"]; - Textblock -> AlignedTextblock [arrowhead="none", arrowtail="empty", - dir="both"]; - AlignedTextblock -> etc2 [arrowhead="none", arrowtail="empty", dir="both"]; - - Platform -> FltkPlatform [arrowhead="none", arrowtail="empty", dir="both", - style="dashed"]; - FltkPlatform -> FltkView [headlabel="*", taillabel="1"]; - - View -> FltkView [arrowhead="none", arrowtail="empty", dir="both"]; - FltkView -> FltkViewport [arrowhead="none", arrowtail="empty", dir="both", - style="dashed"]; - FltkView -> FltkPreview [arrowhead="none", arrowtail="empty", dir="both", - style="dashed"]; -} -\enddot - -
[\ref uml-legend "legend"]
- -\em Platform means in most cases the underlying UI toolkit -(e.g. FLTK). A layout is bound to a specific platform, but multiple -platforms may be handled in one program. - -A short overview: - -
    -
  • dw::core::Layout is the central class, it manages the widgets and the - view, and provides delegation methods for the platform. - -
  • The layouting is done by a tree of widgets (details are described in - \ref dw-layout-widgets), also the drawing, which is finally delegated - to the view. - -
  • The view (implementation of dw::core::View) provides primitive methods - for drawing, but also have an influence on - the canvas size (via size hints). See \ref dw-layout-views for details. - -
  • Some platform dependencies are handled by implementations - of dw::core::Platform. -
- - -

Header Files

- -The structures mentioned above can be found in the following header -files: - -
    -
  • Anything from the Dw core in core.hh. Do not include the single files. - -
  • The single widgets can be found in the respective header files, e.g. - image.hh for dw::Image. - -
  • The core of the FLTK implementation is defined in fltkcore.hh. This - includes dw::fltk::FltkPlatform, dw::fltk::FltkView, but not the concrete - view implementations. - -
  • The views can be found in single header files, e.g fltkviewport.hh for - dw::fltk::FltkViewport. -
- - -

Further Documentations

- -A complete map can be found at \ref dw-map. - -
    -
  • For learning, how to use Dw, read \ref dw-usage and related documents, - dw::core::style, dw::core::ui and \ref dw-images-and-backgrounds. -
  • Advanced topics are described in \ref dw-layout-widgets, - \ref dw-widget-sizes and \ref dw-layout-views. -
- -*/ diff --git a/doc/dw-size-of-widget.png b/doc/dw-size-of-widget.png deleted file mode 100644 index dbdbe0c4..00000000 Binary files a/doc/dw-size-of-widget.png and /dev/null differ diff --git a/doc/dw-style-box-model.png b/doc/dw-style-box-model.png deleted file mode 100644 index bf2fb1f1..00000000 Binary files a/doc/dw-style-box-model.png and /dev/null differ diff --git a/doc/dw-style-length-absolute.png b/doc/dw-style-length-absolute.png deleted file mode 100644 index 9ea28cad..00000000 Binary files a/doc/dw-style-length-absolute.png and /dev/null differ diff --git a/doc/dw-style-length-percentage.png b/doc/dw-style-length-percentage.png deleted file mode 100644 index b1ad79c9..00000000 Binary files a/doc/dw-style-length-percentage.png and /dev/null differ diff --git a/doc/dw-style-length-relative.png b/doc/dw-style-length-relative.png deleted file mode 100644 index ee79b1a9..00000000 Binary files a/doc/dw-style-length-relative.png and /dev/null differ diff --git a/doc/dw-textblock-collapsing-spaces-1-1.png b/doc/dw-textblock-collapsing-spaces-1-1.png deleted file mode 100644 index d528dfb2..00000000 Binary files a/doc/dw-textblock-collapsing-spaces-1-1.png and /dev/null differ diff --git a/doc/dw-textblock-collapsing-spaces-1-2.png b/doc/dw-textblock-collapsing-spaces-1-2.png deleted file mode 100644 index 483e79d1..00000000 Binary files a/doc/dw-textblock-collapsing-spaces-1-2.png and /dev/null differ diff --git a/doc/dw-textblock-collapsing-spaces-2-1.png b/doc/dw-textblock-collapsing-spaces-2-1.png deleted file mode 100644 index 0a03ea80..00000000 Binary files a/doc/dw-textblock-collapsing-spaces-2-1.png and /dev/null differ diff --git a/doc/dw-textblock-collapsing-spaces-2-2.png b/doc/dw-textblock-collapsing-spaces-2-2.png deleted file mode 100644 index b89c6254..00000000 Binary files a/doc/dw-textblock-collapsing-spaces-2-2.png and /dev/null differ diff --git a/doc/dw-usage.doc b/doc/dw-usage.doc deleted file mode 100644 index a23920b8..00000000 --- a/doc/dw-usage.doc +++ /dev/null @@ -1,375 +0,0 @@ -/** \page dw-usage Dillo Widget Usage - -This document describes the usage of Dw, without going too much into -detail. - - -

Getting Started

- -In this section, a small runnable example is described, based on the -FLTK implementation. - -As described in \ref dw-overview, the following objects are needed: - -
    -
  • dw::core::Layout, -
  • an implementation of dw::core::Platform (we will use - dw::fltk::FltkPlatform), -
  • at least one implementation of dw::core::View (dw::fltk::FltkViewport), - and -
  • some widgets (for this example, only a simple dw::Textblock). -
- -First of all, the necessary \#include's: - -\code -#include -#include - -#include "dw/core.hh" -#include "dw/fltkcore.hh" -#include "dw/fltkviewport.hh" -#include "dw/textblock.hh" -\endcode - -Everything is put into one function: - -\code -int main(int argc, char **argv) -{ -\endcode - -As the first object, the platform is instantiated: - -\code - dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform (); -\endcode - -Then, the layout is created, with the platform attached: - -\code - dw::core::Layout *layout = new dw::core::Layout (platform); -\endcode - -For the view, we first need a FLTK window: - -\code - Fl_Window *window = new Fl_Window(200, 300, "Dw Example"); - window->begin(); -\endcode - -After this, we can create a viewport, and attach it to the layout: - -\code - dw::fltk::FltkViewport *viewport = - new dw::fltk::FltkViewport (0, 0, 200, 300); - layout->attachView (viewport); -\endcode - -Each widget needs a style (dw::core::style::Style, see dw::core::style), -so we construct it here. For this, we need to fill a -dw::core::style::StyleAttrs structure with values, and call -dw::core::style::Style::create (latter is done further below): - -\code - dw::core::style::StyleAttrs styleAttrs; - styleAttrs.initValues (); - styleAttrs.margin.setVal (5); -\endcode - -dw::core::style::StyleAttrs::initValues sets several default -values. The last line sets a margin of 5 pixels. Next, we need a -font. Fonts are created in a similar way, first, the attributes are -defined: - -\code - dw::core::style::FontAttrs fontAttrs; - fontAttrs.name = "Bitstream Charter"; - fontAttrs.size = 14; - fontAttrs.weight = 400; - fontAttrs.style = dw::core::style::FONT_STYLE_NORMAL; - fontAttrs.letterSpacing = 0; - fontAttrs.fontVariant = dw::core::style::FONT_VARIANT_NORMAL; -\endcode - -Now, the font can be created: - -\code - styleAttrs.font = dw::core::style::Font::create (layout, &fontAttrs); -\endcode - -As the last attributes, the background and forground colors are -defined, here dw::core::style::Color::createSimple must be called: - -\code - styleAttrs.color = - dw::core::style::Color::create (layout, 0x000000); - styleAttrs.backgroundColor = - dw::core::style::Color::create (layout, 0xffffff); -\endcode - -Finally, the style for the widget is created: - -\code - dw::core::style::Style *widgetStyle = - dw::core::style::Style::create (layout, &styleAttrs); -\endcode - -Now, we create a widget, assign a style to it, and set it as the -toplevel widget of the layout: - -\code - dw::Textblock *textblock = new dw::Textblock (false); - textblock->setStyle (widgetStyle); - layout->setWidget (textblock); -\endcode - -The style is not needed anymore (a reference is added in -dw::core::Widget::setStyle), so it should be unreferred: - -\code - widgetStyle->unref(); -\endcode - -Now, some text should be added to the textblock. For this, we first -need another style. \em styleAttrs can still be used for this. We set -the margin to 0, and the background color to "transparent": - -\code - styleAttrs.margin.setVal (0); - styleAttrs.backgroundColor = NULL; - - dw::core::style::Style *wordStyle = - dw::core::style::Style::create (layout, &styleAttrs); -\endcode - -This loop adds some paragraphs: - -\code - for(int i = 1; i <= 10; i++) { - char buf[4]; - sprintf(buf, "%d.", i); - - char *words[] = { "This", "is", "the", buf, "paragraph.", - "Here", "comes", "some", "more", "text", - "to", "demonstrate", "word", "wrapping.", - NULL }; - - for(int j = 0; words[j]; j++) { - textblock->addText(strdup(words[j]), wordStyle); -\endcode - -Notice the \em strdup, dw::Textblock::addText will feel responsible -for the string, and free the text at the end. (This has been done to -avoid some overhead in the HTML parser.) - -The rest is simple, it also includes spaces (which also have styles): - -\code - textblock->addSpace(wordStyle); - } -\endcode - -Finally, a paragraph break is added, which is 10 pixels high: - -\code - textblock->addParbreak(10, wordStyle); - } -\endcode - -Again, this style should be unreferred: - -\code - wordStyle->unref(); -\endcode - -After adding text, this method should always be called (for faster -adding large text blocks): - -\code - textblock->flush (); -\endcode - -Some FLTK stuff to finally show the window: - -\code - window->resizable(viewport); - window->show(); - int errorCode = Fl::run(); -\endcode - -For cleaning up, it is sufficient to destroy the layout: - -\code - delete layout; -\endcode - -And the rest - -\code - return errorCode; -} -\endcode - -If you compile and start the program, you should see the following: - -\image html dw-example-screenshot.png - -Try to scroll, or to resize the window, you will see, that everything -is done automatically. - -Of course, creating new widgets, adding text to widgets etc. can also -be done while the program is running, i.e. after fltk::run has been -called, within timeouts, idles, I/O functions etc. Notice that Dw is -not thread safe, so that everything should be done within one thread. - -With the exception, that you have to call dw::Textblock::flush, -everything gets immediately visible, within reasonable times; Dw has -been optimized for frequent updates. - - -

List of all Widgets

- -These widgets are used within dillo: - -
    -
  • dw::core::ui::Embed -
  • dw::AlignedTextblock -
  • dw::Bullet -
  • dw::Ruler -
  • dw::Image -
  • dw::ListItem -
  • dw::Table -
  • dw::TableCell -
  • dw::Textblock -
- -If you want to create a new widget, refer to \ref dw-layout-widgets. - - -

List of Views

- -There are three dw::core::View implementations for FLTK: - -
    -
  • dw::fltk::FltkViewport implements a viewport, which is used in the - example above. - -
  • dw::fltk::FltkPreview implements a preview window, together with - dw::fltk::FltkPreviewButton, it is possible to have a scaled down - overview of the whole canvas. - -
  • dw::fltk::FltkFlatView is a "flat" view, i.e. it does not support - scrolling. It is used for HTML buttons, see - dw::fltk::ui::FltkComplexButtonResource and especially - dw::fltk::ui::FltkComplexButtonResource::createNewWidget for details. -
- -More informations about views in general can be found in \ref -dw-layout-views. - - -

Iterators

- -For examining generally the contents of widgets, there are iterators -(dw::core::Iterator), created by the method -dw::core::Widget::iterator (see there for more details). - -These simple iterators only iterate through one widget, and return -child widgets as dw::core::Content::WIDGET. The next call of -dw::core::Iterator::next will return the piece of contents \em after -(not within) this child widget. - -If you want to iterate through the whole widget trees, there are two -possibilities: - -
    -
  1. Use a recursive function. Of course, with this approach, you are - limited by the program flow. - -
  2. Maintain a stack of iterators, so you can freely pass this stack - around. This is already implemented, as dw::core::DeepIterator. -
- -As an example, dw::core::SelectionState represents the selected region -as two instances of dw::core::DeepIterator. - - -

Finding Text

- -See dw::core::Layout::findtextState and dw::core::FindtextState -(details in the latter). There are delegation methods: - -
    -
  • dw::core::Layout::search and -
  • dw::core::Layout::resetSearch. -
- - -

Anchors and Scrolling

- -In some cases, it is necessary to scroll to a given position, or to -an anchor, programmatically. - -

Anchors

- -Anchors are defined by widgets, e.g. dw::Textblock defines them, when -dw::Textblock::addAnchor is called. To jump to a specific anchor -within the current widget tree, use dw::core::Layout::setAnchor. - -This can be done immediately after assignig a toplevel widget, even -when the anchor has not yet been defined. The layout will remember the -anchor, and jump to the respective position, as soon as possible. Even -if the anchor position changes (e.g., when an anchor is moved -downwards, since some space is needed for an image in the text above), -the position is corrected. - -As soon as the user scrolls the viewport, this correction is not done -anymore. If in dillo, the user request a page with an anchor, which is -quite at the bottom of the page, he may be get interested in the text -at the beginning of the page, and so scrolling down. If then, after -the anchor has been read and added to the dw::Textblock, this anchor -would be jumped at, the user would become confused. - -The anchor is dismissed, too, when the toplevel widget is removed -again. - -\todo Currently, anchors only define vertical positions. - -

Scrolling

- -To scroll to a given position, use the method -dw::core::Layout::scrollTo. It expects several parameters: - -
    -
  • a horizontal adjustment parameter, defined by dw::core::HPosition, -
  • a vertical adjustment parameter, defined by dw::core::VPosition, and -
  • a rectangle (\em x, \em y, \em width and \em heigh) of the region - to be adjusted. -
- -If you just want to move the canvas coordinate (\em x, \em y) into the -upper left corner of the viewport, you can call: - -\code -dw::core::Layout *layout; -// ... -layout->scrollTo(dw::core::HPOS_LEFT, dw::core::VPOS_TOP, 0, 0, 0, 0); -\endcode - -By using dw::core::HPOS_NO_CHANGE or dw::core::VPOS_NO_CHANGE, you can -change only one dimension. dw::core::HPOS_INTO_VIEW and -dw::core::VPOS_INTO_VIEW will cause the viewport to move as much as -necessary, that the region is visible in the viewport (this is -e.g. used for finding text). - - -

Further Documentations

- -
    -
  • dw::core::style -
  • dw::core::ui -
  • \ref dw-images-and-backgrounds -
- -*/ diff --git a/doc/dw-viewport-with-scrollbar.png b/doc/dw-viewport-with-scrollbar.png deleted file mode 100644 index 7ac62de3..00000000 Binary files a/doc/dw-viewport-with-scrollbar.png and /dev/null differ diff --git a/doc/dw-viewport-without-scrollbar.png b/doc/dw-viewport-without-scrollbar.png deleted file mode 100644 index 8aa20fec..00000000 Binary files a/doc/dw-viewport-without-scrollbar.png and /dev/null differ diff --git a/doc/dw-widget-sizes.doc b/doc/dw-widget-sizes.doc deleted file mode 100644 index a82d3b99..00000000 --- a/doc/dw-widget-sizes.doc +++ /dev/null @@ -1,277 +0,0 @@ -/** \page dw-widget-sizes Sizes of Dillo Widgets - -
Info: -Not up to date, see \ref dw-grows.
- -Allocation -========== - -Each widget has an \em allocation at a given time, this includes - -- 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. - -- 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 -divided into an ascender (which height is called \em ascent), and a -descender (which height is called \em descent). The total height is so -the sum of \em ascent and \em descent. - -Sizes of zero are allowed. The upper limit for the size of a widget is -defined by the limits of the C++ type \em int. - -\image html dw-size-of-widget.png Allocation of a Widget - -In the example in the image, the widget has the following allocation: - -- \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 -calling dw::core::Widget::sizeAllocate. This is a concrete method, -which will call dw::core::Widget::sizeAllocateImpl (see code of -dw::core::Widget::sizeAllocate for details). - -For trivial widgets (like dw::Bullet), -dw::core::Widget::sizeAllocateImpl does not need to be -implemented. For more complex widgets, the implementation should call -dw::core::Widget::sizeAllocate (not -dw::core::Widget::sizeAllocateImpl) on all child widgets, with -appropriate child allocations. dw::core::Widget::allocation should not -be changed here, this is already done in -dw::core::Widget::sizeAllocate. - - -Requisitions -============ - -A widget may prefer a given size for the allocation. This size, the -\em requisition, should be returned by the method -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: - -- 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 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. - -From the outside, dw::Image::sizeRequest should be called, which does -a bit of optimization. Notice that in dw::Image::sizeRequestImpl, no -optimization like lazy evaluation is necessary, this is already done -in dw::Image::sizeRequest. - -A widget, which has children, will likely call dw::Image::sizeRequest -on its children, to calculate the total requisition. - -The caller (this is either the dw::core::Layout, or the parent -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.) - - -Size Hints -========== - -
Info: -Size hints have been removed, see \ref dw-grows.
- - -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: - -- 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: - -- 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 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. - -- 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. - - -Resizing -======== - -When the widget changes its size (requisition), it should call -dw::core::Widget::queueResize. The next call of -dw::core::Widget::sizeRequestImpl should then return the new -size. See dw::Image::setBuffer as an example. - -Interna are described in the code of dw::core::Widget::queueResize. - -

Incremental Resizing

- -A widget may calculate its size based on size calculations already -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: - -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: - 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 -===================================== - -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 - *sizeRequestImpl* (called by *sizeRequest*), *markSizeChange*, and - *markExtremesChange* (the latter two are called by *queueResize*). -2. On the other hand, to make sure that the calls, which are allowed, - are handled correctly, especially in implementations of - *sizeRequestImpl*, *markSizeChange*, *markExtremesChange* - -Generally, the rules defined below are, in case of doubt, rather -strict; when changing the rules, loosening is simpler than to tighten -them, since this will make it neccessary to review old code for calls -previously allowed but now forbidden. - -Short recap: - -- *QueueResize* directly calls *markSizeChange* and - *markExtremesChanges*, and queues an idle function for the actual - resizing (dw::core::Layout::resizeIdle). (The idle function is - called some time after *queueResize* is finished.) -- The resize idle function first calls *sizeRequest*, then - *sizeAllocate*, for the toplevel widget. - -In the following table, the rules are defined in detail. "Within call -of ..." includes all methods called from the original method: the -first row (*queueResize*) defines also the rules for -*markExtremesChanges* and *markExtremesChanges*, and in the second row -(*sizeAllocate*), even *sizeRequest* has to be considered. - -
Info: -Not up to date: *queueResize* can now be called recursively (so to -speak). See code there.
- - - - - - - - -
Within call of ... ↓ - ... is call allowed of ... ? → - queueResize - sizeAllocate - sizeRequest - getExtremes -
queueResize - No - No1 - No1 - No1 -
sizeAllocate - Yes - Only for children2 - Yes(?) - Yes(?) -
sizeRequest - Yes3 - No - Limited4 - Limited4 -
getExtremes - Yes3 - No - Limited4 - Limited4 -
1) Otherwise, since these other methods -may be call *queueResize*, the limitation that *queueResize* must not -call *queueResize* can be violated. - -2) Could perhaps be loosened as for *sizeRequest* and -*getExtremes*, but there is probably no need. - -3) Therefore the distinction between *RESIZE_QUEUED* and -*NEEDS_RESIZE*, and *EXTREMES_QUEUED* and *EXTREMES_CHANGED*, -respectively. - -4) Calls only for children are safe. In other cases, you -take a large responsibility to prevent endless recursions by -(typically indirectly) calling *sizeRequest* / *getExtremes* for -direct ancestors. -
- -Furthermore, *sizeAllocate* can only be called within a call of -dw::core::Layout::resizeIdleId, so (if you do not touch dw::core) do -not call it outside of *sizeAllocateImpl*. The other methods can be -called outsize; e. g. *sizeRequest* is called in -dw::Textblock::addWidget. - -To avoid painful debugging, there are some tests for the cases that -one method call is strictly forbidden while another method is called. - -This could be done furthermore: - -- The tests could be refined. -- Is it possible to define exacter rules, along with a proof that no - problems (like endless recursion) can occur? - - -See also -======== - -- \ref dw-grows - -*/ diff --git a/doc/fltk-problems.doc b/doc/fltk-problems.doc deleted file mode 100644 index df4f1f14..00000000 --- a/doc/fltk-problems.doc +++ /dev/null @@ -1,180 +0,0 @@ -/** \page fltk-problems Problems with FLTK - -

dw::fltk::FltkViewport

- -Current problems: - -
    -
  • How should dw::fltk::FltkViewport::cancelQueueDraw be implemented? - -
  • If the value of a scrollbar is changed by the program, not the user, - the callback seems not to be called. Can this be assured? - -
  • The same for dw::fltk::FltkViewport::layout? - -
  • Also, the problems with the widgets seems to work. Also sure? - -
  • When drawing, clipping of 32 bit values is not working properly. - -
  • The item group within a selection widget (menu) should not be selectable. -
- - -

dw::fltk::FltkPlatform

- -
    -
  • There is the problem, that fltk::font always returns a font, the - required one, or a replacements. The latter is not wanted in all - cases, e.g. when several fonts are tested. Perhaps, this could be - solved by searching in the font list. [This was true of fltk2. - What is the state of font handling now with fltk-1.3?] - -
  • Distinction between italics and oblique would be nice - (dw::fltk::FltkFont::FltkFont). -
- - -

dw::fltk::ui::FltkCheckButtonResource

- -Groups of Fl_Radio_Button must be added to one Fl_Group, which is -not possible in this context. There are two alternatives: - -
    -
  1. there is a more flexible way to group radio buttons, or -
  2. radio buttons are not grouped, instead, grouping (especially - unchecking other buttons) is done by the application. -
- -(This is mostly solved.) - -

dw::fltk::FltkImgbuf

- -Alpha transparency should be best abstracted by FLTK itself. If not, -perhaps different implementations for different window systems could -be used. Then, it is for X necessary to use GCs with clipping masks. - - -

dw::fltk::ui::ComplexButton

- -Unfortunately, FLTK does not provide a button with Fl_Group as parent, so -that children may be added to the button. dw::fltk::ui::ComplexButton does -exactly this, and is, in an ugly way, a modified copy of the FLTK -button. - -It would be nice, if this is merged with the standard FLTK -button. Furthermore, setting the type is strange. - -If the files do not compile, it may be useful to create a new one from -the FLTK source: - -
    -
  1. Copy Fl_Button.H from FLTK to dw/fltkcomplexbutton.hh and - src/Button.cxx to dw/fltkcomplexbutton.cc. - -
  2. In both files, rename "Button" to "ComplexButton". Automatic replacing - should work. - -
  3. Apply the changes below. -
- -The following changes should be applied manually. - -

Changes in fltkcomplexbutton.hh

- -First of all, the \#define's for avoiding multiple includes: - -\code --#ifndef fltk_ComplexButton_h // fltk_Button_h formerly --#define fltk_ComplexButton_h -+#ifndef __FLTK_COMPLEX_BUTTON_HH__ -+#define __FLTK_COMPLEX_BUTTON_HH__ -\endcode - -at the beginning and - -\code --#endif -+#endif // __FLTK_COMPLEX_BUTTON_HH__ -\endcode - -at the end. Then, the namespace is changed: - -\code --namespace fltk { -+namespace dw { -+namespace fltk { -+namespace ui { -\endcode - -at the beginning and - -\code --} -+} // namespace ui -+} // namespace fltk -+} // namespace dw -\endcode - -at the end. Most important, the base class is changed: - -\code --#include "FL/Fl_Widget.H" -+#include -\endcode - -and - -\code --class FL_API ComplexButton : public Fl_Widget { -+class ComplexButton: public Fl_Group -+{ -\endcode - -Finally, for dw::fltk::ui::ComplexButton::default_style, there is a -namespace conflict: - -\code -- static NamedStyle* default_style; -+ static ::fltk::NamedStyle* default_style; -\endcode - -

Changes in fltkcomplexbutton.cc

- -First, \#include's: - -\code - - #include --#include // formerly - #include - #include -+ -+#include "fltkcomplexbutton.hh" -\endcode - -Second, namespaces: - -\code -+using namespace dw::fltk::ui; -\endcode - -Since the base class is now Fl_Group, the constructor must be changed: - -\code --ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : Fl_Widget(x,y,w,h,l) { -+ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : -+ Fl_Group(x,y,w,h,l) -+{ -\endcode - -Finally, the button must draw its children (end of -dw::fltk::ui::ComplexButton::draw()): - -\code -+ -+ for (int i = children () - 1; i >= 0; i--) -+ draw_child (*child (i)); - } -\endcode - -*/ diff --git a/doc/index.doc b/doc/index.doc deleted file mode 100644 index 59de8cd8..00000000 --- a/doc/index.doc +++ /dev/null @@ -1,48 +0,0 @@ -/** \mainpage - -

Overview

- -This is a list of documents to start with: - -
    -
  • \ref lout -
  • \ref dw-overview (map at \ref dw-map) -
- -Currently, a document \ref fltk-problems is maintained, ideally, it -will be removed soon. - -

Historical

- -

Replacements for GTK+ and GLib

- -There are several classes etc., which are used for tasks formerly (in the GTK+ -version of dillo) achieved by GtkObject (in 1.2.x, this is part of Gtk+) and -GLib. For an overview on all this, take a look at \ref lout. - -GtkObject is replaced by the following: - -
    -
  • lout::object::Object is a common base class for many classes used - dillo. In the namespace lout::object, there are also some more common - classes and interfaces. - -
  • A sub class of lout::object::Object is - lout::identity::IdentifiableObject, which allows to determine the - class at run-time (equivalent to GTK_CHECK_CAST in GtkObject). - -
  • For signals, there is the namespace lout::signal. -
- -Hash tables, linked lists etc. can be found in the lout::container namespace, -several useful macros from GLib have been implemented as inline functions -in the lout::misc namespace. - -As an alternative to the macros defined in list.h, there is also a template -class, lout::misc::SimpleVector, which does the same. - -

Changes in Dw

- -If you have been familiar with Dw before, take a look at \ref dw-changes. - -*/ diff --git a/doc/lout.doc b/doc/lout.doc deleted file mode 100644 index 4e1503c6..00000000 --- a/doc/lout.doc +++ /dev/null @@ -1,95 +0,0 @@ -/** \page lout Lots of Useful Tools - -In the "lout" directory, there are some common base functionality for -C++. Most is described as doxygen comments, this text gives an -overview. - -

Common Base Class

- -Many classes are derived from lout::object::Object, which defines some -general methods. See there for more information. - -For the case, that you need primitive C++ types, there are some -wrappers: - - -
C++ Type Wrapper Class -
void* lout::object::Pointer -
specific pointer lout::object::TypedPointer (template class) -
int lout::object::Integer -
const char* lout::object::ConstString -
char* lout::object::String -
- - -

Containers

- -In the namespace lout::container, several container classes are defined, -which all deal with instances of lout::object::Object. - -

Untyped Containers

- -In lout::container::untyped, there are the following containers: - -
    -
  • lout::container::untyped::Vector, a dynamically increases array, -
  • lout::container::untyped::List, a linked list, -
  • lout::container::untyped::HashTable, a hash table, and -
  • lout::container::untyped::Stack, a stack. -
- -All provide specific methods, but since they have a common base class, -lout::container::untyped::Collection, they all provide iterators, by the -method lout::container::untyped::Collection::iterator. - -

Typed Containers

- -lout::container::typed provides wrappers for the container classes defined -in lout::container::untyped, which are more type safe, by using C++ -templates. - - -

Signals

- -For how to connect objects at run-time (to reduce dependencies), take a -look at the lout::signal namespace. - -There is also a base class lout::signal::ObservedObject, which implements -signals for deletion. - - -

Debugging

- -In debug.hh, there are some some useful macros for debugging messages, -see the file for mor informations. - - -

Identifying Classes at Runtime

- -If the class of an object must be identified at runtime, -lout::identity::IdentifiableObject should be used as the base class, -see there for more details. - - -

Miscellaneous

- -The lout::misc namespace provides several miscellaneous stuff: - -
    -
  • In some contexts, it is necessary to compare objects - (less/greater), for this, also lout::misc::Comparable must be - implemented. For example., lout::container::untyped::Vector::sort and - lout::container::typed::Vector::sort cast the elements to - lout::misc::Comparable. This can be mixed with lout::object::Object. -
  • lout::misc::SimpleVector, a simple, template based vector class - (not depending on lout::object::Object) (a variant for handling a - special case in an efficient way is lout::misc::NotSoSimpleVector), -
  • lout::misc::StringBuffer, class for fast concatenation of a large number - of strings, -
  • lout::misc::BitSet implements a bitset. -
  • useful (template) functions (lout::misc::min, lout::misc::max), and -
  • some functions useful for runtime checks (lout::misc::assert, - lout::misc::assertNotReached). -
- -*/ diff --git a/doc/not-so-simple-container.png b/doc/not-so-simple-container.png deleted file mode 100644 index 0af067b5..00000000 Binary files a/doc/not-so-simple-container.png and /dev/null differ diff --git a/doc/rounding-errors.doc b/doc/rounding-errors.doc deleted file mode 100644 index a442033e..00000000 --- a/doc/rounding-errors.doc +++ /dev/null @@ -1,35 +0,0 @@ -/** \page rounding-errors How to Avoid Rounding Errors - -(Probably, this is a standard algorithm, so if someone knows the name, -drop me a note.) - -If something like - -\f[y_i = {x_i a \over b}\f] - -is to be calculated, and all numbers are integers, a naive -implementation would result in something, for which - -\f[\sum y_i \ne {(\sum x_i) a \over b}\f] - -because of rounding errors, due to the integer division. This can be -avoided by transforming the formula into - -\f[y_i = {(\sum_{j=0}^{j=i} x_j) a \over b} - \sum_{j=0}^{j=i-1} y_j\f] - -Of corse, when all \f$y_i\f$ are calculated in a sequence, -\f$\sum_{j=0}^{j=i} x_j\f$ and \f$\sum_{j=0}^{j=i-1} y_j\f$ can be -accumulated in the same loop. Regard this as sample: - -\code -int n, x[n], a, b; // Should all be initialized. -int y[n], cumX = 0, cumY = 0; - -for (int i = 0; i < n; i++) { - cumX += x[i] - y[i] = (cumX * a) / b - cumY; - cumY += y[i]; -} -\endcode - -*/ diff --git a/doc/uml-legend.doc b/doc/uml-legend.doc deleted file mode 100644 index 54004ccd..00000000 --- a/doc/uml-legend.doc +++ /dev/null @@ -1,195 +0,0 @@ -/** \page uml-legend UML Legend - -This page describes the notation for several diagrams used in the -documentation, which is a slight variation of UML. - - -

Classes

- -Classes are represented by boxes, containing there names: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - fontname=Helvetica; fontsize=8; - "Concrete Class"; - "Abstract Class" [color="#a0a0a0"]; - Interface [color="#ff8080"]; -} -\enddot - -(In most cases, the attributes and operations are left away, for -better readibility. Just click on it, to get to the detailed -description.) - -Of course, in C++, there are no interfaces, but here, we call a class, -which has only virtual abstract methods, and so does not provide any -functionality, an interface. - -Templates get a yellow background color: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10, - fillcolor="#ffffc0", style="filled"]; - fontname=Helvetica; fontsize=8; - "Concrete Class Template"; - "Abstract Class Template" [color="#a0a0a0"]; - "Interface Template" [color="#ff8080"]; -} -\enddot - - -

Objects

- -In some cases, an examle for a concrete constellation of objects is -shown. An object is represented by a box containing a name and the -class, separated by a colon. - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, - color="#404040", labelfontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - - "x: A" -> "y1: B"; - "x: A" -> "y2: B"; -} -\enddot - -The names (\em x, \em y, and \em z) are only meant within the context -of the diagram, there needs not to be a relation to the actual names -in the program. They should be unique within the diagram. - -Classes and objects may be mixed in one diagram. - - -

Associations

- -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, - color="#404040", labelfontcolor="#000080", - fontname=Helvetica, fontsize=10, fontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - A -> B [headlabel="*", taillabel="1", label="x"]; -} -\enddot - -In this example, one instance of A refers to an arbitrary number of B -instances (denoted by the "*"), and each instance of B is referred by -exactly one ("1") A. The label \em x is the name of the association, -in most cases the name of the field, e.g. A::x. - -Possible other values for the \em multiplicity: - -
    -
  • a concrete number, in most cases "1", -
  • a range, e.g. "0..1", -
  • "*", denoting an arbitrary number. -
- - -

Implementations and Inheritance

- -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="none", dir="both", arrowtail="empty", - labelfontname=Helvetica, labelfontsize=10, color="#404040", - labelfontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - A[color="#ff8080"]; - B[color="#ff8080"]; - C; - D; - A -> B; - A -> C [style="dashed"]; - C -> D; -} -\enddot - -In this example, - -
    -
  • the interface B extends the interface A, -
  • the class C implements the interface A, and -
  • the class D extends the class C. -
- - -

Template Instantiations

- -Template instantiations are shown as own classes/interfaces, the -instantiation by the template is shown by a yellow dashed arrow: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="none", arrowtail="empty", dir="both", - labelfontname=Helvetica, labelfontsize=10, color="#404040", - labelfontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - - A[color="#ff8080"]; - B[color="#ff8080"]; - C[color="#ff8080", fillcolor="#ffffc0", style="filled"]; - C_A[color="#ff8080", label="C \"]; - C_B[color="#ff8080", label="C \"]; - D; - - C -> C_A [arrowhead="open", arrowtail="none", style="dashed", - color="#808000"]; - C -> C_B [arrowhead="open", arrowtail="none", style="dashed", - color="#808000"]; - A -> C_A; - B -> C_B; - C_A -> D [style="dashed"]; -} -\enddot - -In this example, the interface template C uses the template argument -as super interface. - - -

Packages

- -Packages are presented by dashed rectangles: - -\dot -digraph G { - node [shape=record, fontname=Helvetica, fontsize=10]; - edge [arrowhead="none", arrowtail="empty", dir="both", - labelfontname=Helvetica, labelfontsize=10, color="#404040", - labelfontcolor="#000080"]; - fontname=Helvetica; fontsize=10; - - subgraph cluster_1 { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="package 1"; - - A; - B [color="#a0a0a0"]; - } - - subgraph cluster_2 { - style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; - label="package 2"; - - C; - D [color="#a0a0a0"]; - E - } - - A -> C; - B -> D; - D -> E; - E -> A [arrowhead="open", arrowtail="none"]; -} -\enddot - -Packages may be nested. - -*/ \ No newline at end of file -- cgit v1.2.3 From e9e3d1e1c27dab1b3abcc84aee687fa4a74bff64 Mon Sep 17 00:00:00 2001 From: corvid Date: Mon, 1 Jun 2015 20:35:23 +0000 Subject: dillo man page date --- doc/dillo.1.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/dillo.1.in b/doc/dillo.1.in index f86d050c..0853e6eb 100644 --- a/doc/dillo.1.in +++ b/doc/dillo.1.in @@ -1,4 +1,4 @@ -.TH dillo 1 "December 20, 2014" "" "USER COMMANDS" +.TH dillo 1 "May 28, 2015" "" "USER COMMANDS" .SH NAME dillo \- web browser .SH SYNOPSIS -- cgit v1.2.3