aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/Cache.txt185
-rw-r--r--doc/Cookies.txt85
-rw-r--r--doc/Dillo.txt103
-rw-r--r--doc/Dpid.txt454
-rw-r--r--doc/Dw.txt383
-rw-r--r--doc/DwImage.txt201
-rw-r--r--doc/DwPage.txt152
-rw-r--r--doc/DwRender.txt620
-rw-r--r--doc/DwStyle.txt310
-rw-r--r--doc/DwTable.txt205
-rw-r--r--doc/DwWidget.txt339
-rw-r--r--doc/HtmlParser.txt116
-rw-r--r--doc/IO.txt468
-rw-r--r--doc/Images.txt114
-rw-r--r--doc/Imgbuf.txt177
-rw-r--r--doc/Makefile.am19
-rw-r--r--doc/NC_design.txt80
-rw-r--r--doc/README53
-rw-r--r--doc/Selection.txt149
19 files changed, 4213 insertions, 0 deletions
diff --git a/doc/Cache.txt b/doc/Cache.txt
new file mode 100644
index 00000000..ac1ecf87
--- /dev/null
+++ b/doc/Cache.txt
@@ -0,0 +1,185 @@
+ June 2000, --Jcid
+ Last update: Oct 2004
+
+ -------
+ 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, no matter
+if it is a http, file, dpi or whatever type of request. The capi
+asks the dpi module for dpi URLs and the Cache for everything
+else.
+
+ Here we'll document non dpi requests.
+
+ The cache, at its turn, sends the requested-data from memory
+(if cached), or opens a new network connection (if not cached).
+
+ This means that no mattering whether the answer comes from
+memory or the net, the client requests it through the capi
+wrapper, in a single uniform way.
+
+
+ ----------------
+ CACHE PHILOSOPHY
+ ----------------
+
+ Dillo's cache is very simple, every single resource that's
+retrieved (URL) is kept in memory. NOTHING is saved. 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 (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, Url.c and web.c.
+
+ Cache.c is the principal source, and it also is the main
+responsible for processing cache-clients (held in a queue).
+Dicache.c is the "decompressed image cache" and it holds the
+original data and its corresponding decompressed RGB
+representation (more on this subject in Images.txt).
+
+ Url.c, mime.c and web.c are used for secondary tasks; as
+assigning the right "viewer" or "decoder" for a given URL.
+
+
+----------------
+A bit of history
+----------------
+
+ Some time ago, the cache functions, URL retrieving 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 gets known
+when the resource header is retrieved (think of http), and it
+happens when the cache has the control so, the cache sets the
+proper viewer for it! (unless the Callback function is specified
+with the URL request).
+
+ You'll find a good example in http.c.
+
+ Note: Files don't have a header, but the file handler inside
+dillo tries to determine the Content-Type and sends it back in
+HTTP form!
+
+
+-------------
+Cache clients
+-------------
+
+ Cache clients MUST use a_Cache_open_url to request an URL. The
+client structure and the callback-function prototype are defined,
+in cache.h, as follows:
+
+struct _CacheClient {
+ gint Key; /* Primary Key for this client */
+ const char *Url; /* Pointer to a cache entry Url */
+ guchar *Buf; /* Pointer to cache-data */
+ guint 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(const char *Url, CA_Callback_t Call, void *CbData)
+
+ if Url is not cached
+ Create a cache-entry for that URL
+ Send client to cache queue
+ Initiate a new connection
+ else
+ Feed our client with cached data
+
+································································
+ChainFunction_t a_Url_get_ccc_funct(const char *Url)
+
+ Scan the Url handlers for a handler that matches
+ If found
+ Return the CCC function for it
+ else
+ Return NULL
+
+ * Ex: If Url is an http request, a_Http_ccc is the matching
+handler.
+
+································································
+
+----------------------
+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 troughly,
+write me a note, just to assign a higher priority on further
+improving of this doc.
+ Hope this helps!
+
+
diff --git a/doc/Cookies.txt b/doc/Cookies.txt
new file mode 100644
index 00000000..8b5111b8
--- /dev/null
+++ b/doc/Cookies.txt
@@ -0,0 +1,85 @@
+Jan 2002, Jörgen Viksell - jorgen.viksell@telia.com,
+ Jorge Arellano Cid --
+Last update: Dec 2004
+
+
+==================
+ Cookies in Dillo
+==================
+
+ The cookie support in Dillo aims to support cookies of the old
+original Netscape style, as well as the kind specified in RFC 2109.
+ Between sessions, the cookies get saved to ~/.dillo/cookies.
+At the moment the only enforcements on the amount of cookies to
+save to disk is max 20 per domain.
+ There's also a file for controlling cookies: ~/.dillo/cookiesrc. Dillo
+initially sets it to ignore (reject) all cookies, so if you want to use
+cookies, change it to meet your needs.
+
+ If you don't want cookies at all, you have two options:
+
+1.- Delete ~/.dillo/cookiesrc (or leave it just as dillo creates it).
+2. Configure Dillo with ./configure --disable-cookies. Then all the
+ cookie stuff will be skipped at compilation.
+
+
+=====================
+ Controlling cookies
+=====================
+
+ There is a small and simple way to restrict urls from setting cookies
+in Dillo. In the file ~/.dillo/cookiesrc You may specify rules
+for different domains. The syntax looks something like this:
+
+DEFAULT DENY
+slashdot.org ACCEPT
+.host.com ACCEPT_SESSION
+
+ The first line says that we should deny all cookies from all domains
+by default.
+ The second one tells Dillo to save all cookies from slashdot.org
+across sessions, until it expires.
+ And finally, the third says that all subdomains of host.com should be
+allowed to set cookies. But these cookies will only be saved in
+memory until you exit.
+
+
+===================
+ Cookies & Privacy
+===================
+
+ Cookies can be a severe threat to personal privacy. The pages you
+visit can be tracked, logged, and associated to a peronal data-record,
+allowing the possibility of building a detailed profile of your
+browsing habits.
+
+ This data is sold to companies that profit from direct use of such
+information (SPAM, Spying, etc).
+
+ If this data is cross-referenced with other databases, they can end up
+with more information than you have about yourself.
+
+ Some people may tell you this is "paranoid". But please, take my words
+as those of someone that has written a web browser, a cookies implementation,
+and that has deep understanding of HTTP (RFC-2068) and cookies (RFC-2965).
+
+ Non technical persons may like to read:
+ http://www.junkbusters.com/cookies.html
+ http://www.newsfactor.com/perl/story/16455.html (about user-spying)
+
+ The dillo project is especially concerned about privacy and security
+issues. Our advice is to avoid cookies whenever possible and at most set
+ACCEPT_SESSION to specific, trusted sites. -- You have been warned.
+
+
+==============
+ Restrictions
+==============
+
+ If you use a single dillo with multiple windows, then there's no
+problem, but if you launch different dillos the latter ones will
+have cookies disabled.
+
+
+
+Thats all folks!
diff --git a/doc/Dillo.txt b/doc/Dillo.txt
new file mode 100644
index 00000000..47f89780
--- /dev/null
+++ b/doc/Dillo.txt
@@ -0,0 +1,103 @@
+"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, FLTK2 based, that holds the
+neccesary 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_Cache_open_url (Described briefly in Cache.txt, source
+contained in cache.c).
+ IO is described in IO.txt (recommended), source in 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.c).
+
+ 4.- Image processing code: The part that handles image
+retrieving, decoding, caching and displaying. (Described in
+Images.txt. Sources: image.c, dw_image.c, 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_Interface_entry_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_Interface_stop and a_Interface_stop, and then calls
+a_Capi_open_url wich calls a_Cache_open_url (or the dpi module if
+this gateway is used).
+
+ If Cache_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 commited to fetch the
+URL. Note that a_Cache_open_url will return the requested URL,
+whether cached or not.
+
+ The next CCC link is dynamically assigned by examining the
+URL's protocol. It can be:
+
+ a_Http_ccc
+ a_File_ccc
+ a_About_ccc
+ a_Plugin_ccc (not implemented yet)
+
+
+ If we have a 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
new file mode 100644
index 00000000..8f69843e
--- /dev/null
+++ b/doc/Dpid.txt
@@ -0,0 +1,454 @@
+Aug 2003, Jorge Arellano Cid,
+ Ferdi Franceschini --
+Last update: Dec 2004
+
+
+ ------
+ 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:
+ Any program/script that can read or write to stdio. If you can write a
+ shell script you can write one of these (see examples at the end).
+ Warning, dpid will run multiple instances of filter plugins if requested.
+ This is safe if the plugin only writes to stdout which is what the filter
+ type dpis do at the moment.
+
+-----------
+About dpid:
+-----------
+
+ * dpid is a program which manages dpi connections.
+ * dpid is a daemon that serves dillo using unix domain
+ sockets (UDS).
+ * 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 Unix
+domain socket and returns the socket name 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 synchronise 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 the 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.
+ * ...
+
+ 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 having more than one for the
+ same service.
+
+ * Upgrading a service:
+ to a new version or implementation without requiring
+ bringing down the dpid or patching dillo's core.
+
+
+ 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 TERM signal" 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 <name>.dpi as "bookmarks.dpi" and <name>.filter.dpi as in
+ "hello.filter.dpi". The ".filter" plugins simply read and write to stdio
+ and can be implemented with a shell script easily.
+ * Register/update/remove dpis from list of available dpis when a
+ <dpi cmd='register_all'> is received.
+ * dpid terminates when it receives a <dpi cmd='DpiBye'> command.
+ * dpis can be terminated with a <dpi cmd='DpiBye'> command.
+ * dpidc control program for dpid, currently allows register and stop.
+
+
+-----
+todo:
+-----
+
+ These features are already designed, waiting for implementation:
+
+ * How to register/update/remove/ individual dpis?
+ * How to kill dpis? (signals)
+
+ How:
+
+ A useful and flexible way is to have a "control program" for
+dpid (it avoids having to find its PID among others).
+
+ Let's say:
+
+ dpidc [register | upgrade | stop | ...]
+
+ It can talk to a dpid UDS that serves for that (the same that
+dillo would use). That way we may also have a dpidc dpi! :-)
+
+ Seriously, what I like from this approach is that it is very
+flexible and can be implemented incrementally ("dpidc register"
+is enough to start).
+
+ It also avoids the burden of having to periodically check the
+dpis directory structure for changes).
+
+ It also lets shell scripts an easy way to do the "dirty" work
+of installing dpis; as is required with distros' package
+systems.
+
+<note>
+ How do we tell a crashed dpi? That's the question.
+ We're thinking about using the "lease" concept (as in JINI).
+</note>
+
+
+-----------------
+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 ~/.dillo/dpi_socket_dir is then checked for the name of the dpi socket
+ directory, if dpi_socket_dir does not exist it will be created.
+
+o next it creates Unix domain sockets for the available plugins and
+ then listens for service requests on its own socket (dpid.srs)
+ and for connections to the sockets of inactive plugins.
+
+o dpid returns the name 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) duplicates the connection on stdio
+ 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).
+
+
+-----------------------------------------------
+How are the unix-domain-sockets for dpis named?
+-----------------------------------------------
+
+ Let's say we have two users, "fred" and "joe".
+
+ When Fred's dillo starts its dpid, the dpid creates the
+following directory (rwx------):
+
+ /tmp/fred-XXXXXX
+
+ using mkdtemp().
+
+ and saves that filename within "~/.dillo/dpi_socket_dir".
+
+ That way, another dillo instance of user Fred can easily find
+the running dpid's service request socket at:
+
+ /tmp/fred-XXXXXX/dpid.srs
+
+ (because it is saved in "~/.dillo/dpi_socket_dir").
+
+ Now, we have a dpi directory per user, and its permissions are
+locked so only the user has access, thus the following directory
+tree structure should pose no problems:
+
+ /tmp/fred-XXXXXX/bookmarks
+ /downloads
+ /cookies
+ /ftp
+ ...
+ dpid.srs
+
+ If user Joe starts his dillo, the same happens for him:
+
+ /tmp/joe-XXXXXX/bookmarks
+ /downloads
+ /cookies
+ /ftp
+ ...
+ dpid.srs
+
+
+ What should dpid do at start time:
+
+ Check if both, ~/.dillo/dpi_socket_dir and its directory, exist
+ (it can also check the ownership and permissions).
+
+ If (both exist)
+ use them!
+ else
+ delete ~/.dillo/dpi_socket_dir
+ create another /tmp/<user>-XXXXXX directory
+ save the new directory name into ~/.dillo/dpi_socket_dir
+ (we could also add some paranoid level checks)
+
+ To some degree, this scheme solves the tmpnam issue, different
+users of dillo at the same time, multiple dillo instances,
+polluting /tmp (cosmetic), and reasonably accounts for an
+eventual dillo or dpid crash.
+
+ It has worked very well so far!
+
+
+--------------------------------
+So, how do I make my own plugin?
+--------------------------------
+
+ First, at least, read the "Developing a dillo plugin" section
+of dpi1 spec! :-)
+
+ Note that the dpi1 spec may not be absolutely accurate, but the
+main ideas remain.
+
+ Once you've got the concepts, contrast them with the drawings
+in this document. Once it all makes sense, start playing with
+hello.dpi, you can run it by starting dillo with
+ dillo dpi:/hello/
+or entering
+ dpi:/hello/
+as the url. Then try to understand how it works (use the drawings)
+and finally look at its code.
+
+ Really, the order is not that important, what really matters is
+to do it all.
+
+ Start modifying hello.dpi, and then some more. When you feel
+like trying new things, review the code of the other plugins for
+ideas.
+
+ 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.
+
+
+---------------------------------
+Examples: Simple 'filter' plugins
+---------------------------------
+
+ For a quick and dirty introduction to dpis try the following shell scripts.
+
+ #!/bin/sh
+
+ read -d'>' dpip_tag # Read dillo's request
+
+ # Don't forget the empty line after the Content-type
+ cat <<EOF
+ <dpi cmd='start_send_page' url='dpi:/hi/hi.filter.dpi'>
+ Content-type: text
+
+ EOF
+
+ echo Hi
+
+ Of course you should use html in a real application (perl makes this easy).
+
+ A more useful example uses the "si" system info viewer:
+
+ #!/bin/sh
+ # si - System Information Viewer
+
+ read -d'>' dpip_tag
+
+ # We don't need to send the Content-type because "si --html" does this
+ # for us.
+ cat <<EOF
+ <dpi cmd='start_send_page' url='dpi:/si/si.dpi.filter'>
+ EOF
+
+ si --html
+
+ just make sure that you have si installed or you wont get far.
+
+To try out the examples create two directories for the scripts under your home directory as follows:
+ mkdir -p ~/.dillo/dpi/hi
+ mkdir -p ~/.dillo/dpi/si
+
+then create the scripts and put them in the dpi service directories so that you end up with
+ ~/.dillo/dpi/hi/hi.filter.dpi
+ ~/.dillo/dpi/si/si.filter.dpi
+
+Don't forget to make them executable.
+
+If dpid is already running register the new plugins with
+ dpidc register
+
+You can now test them by entering
+ dpi:/hi/
+or
+ dpi:/si/
+as the url. Or simply passing the url to dillo on startup
+
+ dillo dpi:/si/
+
+
+ You can edit the files in place while dpid is running and reload them in
+dillo to see the result, however if you change the file name or add a new
+script you must run 'dpidc register'.
+
+WARNING
+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.
+ >>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<
+
diff --git a/doc/Dw.txt b/doc/Dw.txt
new file mode 100644
index 00000000..6ffd55d0
--- /dev/null
+++ b/doc/Dw.txt
@@ -0,0 +1,383 @@
+Jan 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+================
+Dw: Dillo Widget
+================
+
+NOTE (Aug 2004): The rendering has changed quite much, and many other
+documents are out of date, in ways described in DwRendering.txt. They
+will be updated some day.
+
+Dw is mainly the module for rendering HTML. It provides a framework
+for widgets, based on the Gtk+ object framework, and is very similar
+to Gtk+, so that experiences in using and extending Gtk+ help very
+much in understanding Dw. There is some documentation at www.gtk.org
+(and probably on your local harddisk, somewhere in /usr/doc/*gtk*),
+you should especially have read the chapter "Writing Your Own
+Widgets" in the tutorial.
+
+
+Why Not Gtk+?
+=============
+
+There are two reasons for designing a new model instead of simply
+using Gtk+ objects:
+
+ 1. Most important, Gtk+ widgets are limited in size, because X
+ windows are so.
+ 2. There are a few extensions which are due to the different needs
+ for HTML rendering compared to GUI's. (Of course, this could
+ have been solved by defining a new object derived from
+ GtkWidget.)
+
+
+Notes On Naming
+===============
+
+According to the naming standards, functions beginning with "a_Dw_"
+may be used outside of Dw, while, as an extention, functions used
+within Dw (e.g. p_Dw_widget_queue_resize) are prefixed with "p_Dw_".
+[todo: This could be included in NC_design.txt.]
+
+Non-static functions beginning with "Dw_" are only used between
+GtkDwViewport and DwWidget (e.g. Dw_gtk_viewport_remove_dw), they
+belong to the core of Dw. And, of course, functions only used within a
+sub-module (e.g. a specific widget) start with "Dw_" and are static
+(e.g. Dw_page_find_line_index).
+
+Dw widgets and some other structures have the prefix "Dw", while Gtk+
+widgets in Dw have the prefix "GtkDw", but functions of them begin
+with "Dw_gtk_" or "a_Dw_gtk", respectively.
+
+
+Basic Overview
+==============
+
+Dw widgets are objects derived from DwWidget, which itself derives
+from GtkObject. DwWidget is quite similar to GtkWidget, the main
+difference is that Dw widgets are always windowless and that they are
+presented in a viewport, so there is no need to limit the size. Much
+of the functionality normally provided by the X server is simulated
+by Dw.
+
+The interface between Gtk+ and Dw is the Gtk+ widget GtkDwViewport,
+which contains (at most) one top-level Dw widget.
+
+A Few Definitions:
+
+ - world coordinates: coordinates relative to the upper left corner
+ of the whole scrolled area ("the world")
+ - viewport coordinates: coordinates relative to the upper left
+ corner of the visible area
+ - widget coordinates: coordinates relative to the upper left corner
+ of the widget
+
+Dw widgets draw into the viewport window, and must adhere to
+*viewport coordinates*: the "world" is only an abstract term, there
+is no window for it. When GtkDwViewport processes expose events, they
+are automatically delivered to the Dw widgets. Redrawing requests due
+to scrolling of the viewport is done by the base object GtkLayout,
+you will not find any code for this in Dw.
+
+Mouse events also contain viewport coordinates. Dw will try to find
+the right Dw widget to deliver the event to.
+
+Resizing the GtkDwViewport will not resize the top-level Dw widget,
+but the latter will get some hints, so that, e.g., the page widget
+rewraps the lines at the appropriate width.
+
+See DwWidget.txt for more details.
+
+
+Embedding Gtk+ Widgets In Dw
+----------------------------
+Dw Widgets may embed Gtk+ widgets, this is done by the Dw widget
+DwEmbedGtk. For Gtk+, these embedded Gtk+ widgets are themselves
+children of the GtkDwViewport, since Gtk+ does not care about Dw.
+
+Of course, embedded Gtk+ widgets are again limited in size, but but
+in position: GtkDwViewport is derived from GtkLayout which is exactly
+designed for positioning widgets in an infinite scrolled area.
+
+
+How To Get The Top-Level Dw Widget From A BrowserWindow
+-------------------------------------------------------
+The member "docwin" of BrowserWindow points on a GtkDwScrolledWindow,
+which contains a GtkDwScrolledFrame, which contains a GtkDwViewport.
+The member "child" of the latter points on the top-level Dw widget,
+or may be NULL. The top-level Dw is (currently) a DwPage (HTML and
+plain text documents) or a DwImage (images).
+
+There is a function a_Dw_gtk_scrolled_window_get_dw for this.
+
+
+Sizes
+-----
+A feature adapted from the old Dw are baselines. As well DwAllocation
+as DwRequisition do not have a height member, but instead ascent and
+descent, both positive or zero. (Originally I removed this, but there
+will be a few widgets in future depending on this, e.g., math
+formulas.)
+
+Unlike in Gtk, sizes of zero are allowed. The upper limit for the
+size of a widget is 2^31 (this will be enough to show the contents of
+a small library in a web page).
+
+
+Resizing
+========
+
+From outside: When writing a new widget, you should implement the
+signal "size_request". When the widget changes its size, it should
+call p_Dw_widget_queue_resize, as in a_Dw_image_size. See "Incremental
+Resizing" below for a way to increase the speed.
+
+Even if the implementation of "size_request" gets quite expensive,
+you do not have to check whether the size has changed, this is done
+by a_Dw_widget_size_request.
+
+Inside: q_Dw_widget_queue_resize will set the DW_NEEDS_RESIZE flag, a
+further call of a_Dw_widget_size_request will only then emit the
+"size_request" signal. Furthermore, mark_size_change and
+mark_extremes_change are called (see below). After that, the resizing
+is done in an idle loop, this prevents too many size requests. The
+algorithm is quite simple: any widget with a child which needs
+resizing, needs resizing, thus all parents up to top-level widget are
+marked.
+
+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 size_request is necessary. To make use of this, a widget
+must implement the following:
+
+ 1. There is a member in DwWidget, called parent_ref, which is
+ totally under control of the parent widget (and so sometimes not
+ used at all). It is necessary to define how parent_ref is used
+ by a specific parent widget, and it has to be set to the correct
+ value whenever necessary.
+
+ 2. The widget must implement mark_size_change and
+ mark_extremes_change, these methods are called in two cases:
+
+ a) directly after q_Dw_widget_queue_resize, with the argument
+ ref was passed to q_Dw_widget_queue_resize, and
+ b) if a child widget has called q_Dw_widget_queue_resize,
+ 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 the DwPage widget, see DwPage.txt for details.
+
+
+Anchors and Scrolling
+=====================
+
+Anchors
+-------
+todo: This section is out of sync with the actual code.
+
+To set the anchor a page is viewed at, you can use one of the
+following functions:
+
+ - void a_Dw_gtk_viewport_set_anchor (GtkDwViewport *viewport,
+ gchar *anchor)
+
+ Scroll directly to an anchor. The anchor does not need to exist
+ already, see below.
+
+ - void a_Dw_gtk_viewport_queue_anchor (GtkDwViewport *viewport,
+ gchar *anchor)
+
+ Set the anchor for the next top-level DwWidget (the next call
+ of a_Dw_gtk_viewport_add_dw).
+
+There are wrappers, a_Dw_gtk_scrolled_window_queue_anchor and
+a_Dw_gtk_scrolled_window_set_anchor.
+
+After a_Dw_gtk_viewport_set_anchor has been called (indirectly by
+Nav_open_url, or by a_Dw_gtk_viewport_add_dw), changes of anchor
+positions (e.g., if widgets change there size or the anchor was not
+known before) will correct the viewport adjustment (in function
+p_Dw_gtk_viewport_update_anchor), but only as long as the user did not
+change it directly. Look at Dw_gtk_scrolled_window_init for details
+about the latter.
+
+Use p_Dw_widget_set_anchor to add anchors to a widget, see
+DwWidget.txt.
+
+Scrolling
+---------
+Here is an overview on more functions for scrolling:
+
+ - To scroll to a given position, there are two possibilities:
+ a_Dw_gtk_viewport_set_scrolling_position simply scrolls to this
+ position, while Dw_gtk_viewport_scroll_to has more facilities:
+ you specify a rectangle you want to see, and the way how it is
+ seen (at the border, centered, or just scroll as much as
+ necessary, that it is seen). If you have a widget, you can also
+ use Dw_widget_scroll_to. There is also a wrapper for
+ GtkDwScrolledWindow,
+ a_Dw_gtk_scrolled_window_set_scrolling_position, and two
+ functions for getting the position,
+ a_Dw_gtk_scrolled_window_get_scrolling_position_x, and
+ a_Dw_gtk_scrolled_window_get_scrolling_position_y.
+
+ - If you have a region, and want to display it, use
+ a_Dw_iterator_scroll_to. For example, the findtext module makes
+ use of it. There are equivalents for DwExtIterator and
+ DwWordIterator. See comments on and in the function for more
+ informations.
+
+ - If you just want to determine where some content is allocated,
+ represented by an iterator, you can use
+ a_Dw_iterator_get_allocation. There are equivalents for
+ DwExtIterator and DwWordIterator.
+
+
+The Objects
+===========
+
+This is the hierarchy of all objects of Dw:
+
+ (GtkObject)
+ +-DwWidget
+ | +----DwBullet
+ | +----DwContainer
+ | | `----DwPage
+ | +----DwEmbedGtk
+ | +----DwHruler
+ | `----DwImage
+ `----(GtkWidget)
+ `----(GtkContainer)
+ +----(GtkBin)
+ | +----(GtkScrolledWindow)
+ | | `----GtkDwScrolledWindow
+ | `----GtkDwScrolledFrame
+ `----(GtkLayout)
+ `----GtkDwViewport
+
+Objects in parentheses are part of Gtk+, not of Dw.
+
+
+DwBullet
+--------
+Simple widget used for unnumbered list (<ul>).
+
+
+DwContainer
+-----------
+The base object for Dw widgets which contain other Dw widgets. As in
+Gtk+, containers are responsible for storing the children, there is
+no common data structure. There are a few signals:
+
+ - void add (DwContainer *container,
+ DwWidget *child);
+
+ Currently not used, but may be in future.
+
+ - void remove (DwContainer *container,
+ DwWidget *widget);
+
+ *Recognize* that a widget is destroyed, i.e., an implementation
+ should remove *the pointer* from the list or so, but not
+ destroy the child widget. It is called by Dw_widget_shutdown.
+
+ - void forall (DwContainer *container,
+ DwCallback callback,
+ gpointer callback_data);
+
+ Process callback for all children, in the form
+ (*callback)(child, callback_data).
+
+ The include_internals of the Gtk+ equivalent was not adapted,
+ since it is used for more sophisticated purposes not needed in
+ Dw.
+
+
+DwEmbedGtk
+----------
+This Dw widget is used to embed Gtk+ widgets into Dw container
+widgets. The Gtk+ widget is set by a_Dw_embed_gtk_add_gtk, and can
+simply be removed by destroying it.
+
+If the DwEmbedGtk contains no Gtk+ widget, it always returns 0x0x0 as
+size, so, for speed reasons, first add the Gtk+ widget into the
+DwEmbedGtk, and then the DwEmbedGtk into the other Dw widget, as at
+the end of Html_tag_open_input.
+
+
+DwHruler
+--------
+Simple widget used for the <hr> tag.
+
+
+DwImage
+-------
+Widget for displaying image. See DwImage.txt for details.
+
+
+DwPage
+------
+A widget for displaying texts. See DwPage.txt for details.
+
+
+DwTable
+-------
+A container widget for rendering tables. See DwTable.txt for details.
+
+
+DwWidget
+--------
+The base object for all Dw widgets. See DwWidget.txt for details.
+
+
+GtkDwScrolledWindow
+-------------------
+Adds a few functionalities to GtkScrolledWindow: it creates the
+GtkDwScrolledFrame and the GtkDwViewport, connects some signals, and
+provides some wrappers for using the GtkDwViewport.
+
+
+GtkDwScrolledFrame
+------------------
+General purpose scrolled widget containing another scrolled widget,
+adding a border and a focus frame. Furthermore, it processes key
+presses and mouse drags (button 2, as in Gimp) to move the viewport.
+
+There are two signals (except "set_scroll_adjustments"),
+"user_hchanged" and "user_vchanged", which are emitted when the user
+changed the viewport adjustments horizontally/vertically by using the
+keys or button 2 dragging.
+
+
+GtkDwViewport
+-------------
+The interface between Gtk+ and Dw. It is responsible for displaying
+Dw Widgets and processing their events. It is derived from GtkLayout,
+to make embedding Gtk+ widgets into Dw widgets simpler, see the
+documentation of GtkLayout in the Gtk+ tutorial for details.
+
+GtkDwViewport contains at most one top-level Dw Widget, if it exists.
+The Gtk+ methods of GtkDwViewport are more or less mapped on the
+methods of the DwWidget. In detail:
+
+ - Dw_gtk_viewport_size_allocate will call a_Dw_widget_set_width,
+ a_Dw_widget_set_ascent (with allocation->height) and
+ a_Dw_widget_set_descent (with zero as argument), and then allocate
+ the Dw widget at the size returned by a_Dw_widget_size_request.
+
+ - Dw_gtk_viewport_draw and Dw_gtk_viewport_expose will call
+ a_Dw_widget_draw, which will emit the "draw" signal.
+
+ - Handling of mouse events is mostly done in Dw_widget_mouse_event,
+ see DwWidget.txt for details. Note that the functions return
+ FALSE, if the event was not processed, so that they are delivered
+ to the parent widget(s) of the GtkDwViewport, this scheme e.g.
+ prevents dragging of the viewport (done by GtkScrolledFrame) when
+ pressing mouse button 2 on a link.
+
+You may call gtk_container_set_border_width for a border around the
+scrolled area.
diff --git a/doc/DwImage.txt b/doc/DwImage.txt
new file mode 100644
index 00000000..d79f50bf
--- /dev/null
+++ b/doc/DwImage.txt
@@ -0,0 +1,201 @@
+Jan 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+=======
+DwImage
+=======
+
+A widget for displaying images and handling image maps.
+
+
+Image Maps
+==========
+
+Client Side Image Maps
+----------------------
+You must first create a list of image maps: Allocate a DwImageMapList,
+and initialize it by calling a_Dw_image_map_list_init. Adding a map is
+done by a_Dw_image_map_list_add_map. a_Dw_image_map_list_add_shape
+adds a shape to the last map. For the meaning of the link argument,
+see Section "Signals".
+
+Image maps are referred by a URL (not only by a name). But currently,
+the image map list is stored in DilloHtmlLB and there is no
+possibility to parse documents without rendering, so images can only
+use maps defined in the same document.
+
+To use a map in an image, call a_Dw_image_set_usemap with the image,
+the map list, and the URL of the map. Passing the whole list makes it
+possible to use maps parsed after the image is created.
+
+
+Server Side Image Maps
+----------------------
+To use images for server side image maps, you must call
+a_Dw_image_set_ismap and the style must contain a valid link
+element. See section "Signals" for more details.
+
+
+Signals
+=======
+
+There are five signals, which can be connected to process actions with
+links. All have at least three arguments:
+
+ - link is the link element of the DwStyle (server side image maps)
+ or DwImageMapShape (client side image maps). The value is an
+ integer, which is currently only used for hypertext links. But
+ generally, it depends on the signal callback how this value is
+ used.
+
+ - x and y are, when server side image maps are used, the relative
+ coordinates of the mouse pointer, otherwise always -1.
+
+Note that, unlike by DwPage before, no cursors are set. Instead, the
+signal callback function has to do this.
+
+The signals:
+
+ - void link_entered (DwImage *image,
+ gint link, gint x, gint y)
+
+ Emitted when the link the mouse pointer is over has
+ changed. "Changed" includes link, x and y, so this signal is also
+ emitted each time the pointer is moved within a server side image
+ map. If the pointer is outside of a link, all arguments have the
+ value -1.
+
+
+ - void link_pressed (DwImage *image,
+ gint link, gint x, gint y,
+ GdkEventButton *event)
+
+ Emitted when the user presses a mouse button _inside_ a link,
+ this signal is never emitted with link = -1. You can use the
+ event to get information about the button, shift keys, etc.
+
+
+ - void link_released (DwImage *image,
+ gint link, gint x, gint y,
+ GdkEventButton *event)
+
+ - void link_clicked (DwImage *image,
+ gint link, gint x, gint y,
+ GdkEventButton *event)
+
+ Analogue to link_pressed.
+
+ - void void (*image_pressed) (DwImage *page,
+ GdkEventButton *event)
+
+ Emitted when the user presses the mouse button on an image which
+ has no related map. In some cases, it may be neccessary to
+ suppress event processing by a_Dw_widget_set_button_sensitive().
+
+
+Future Extentions
+=================
+
+(See also Imgbuf.txt, what is named DilloImageBuffer here, has been
+implemented under the name Imgbuf.)
+
+These are some ideas for a different design, which will solve several
+problems (image transparency, memory usage when implementing a global
+size factor):
+
+1. Instead of a guchar array, a new data type, DilloImageBuffer,
+ should be used (DICacheEntry::ImageBuffer and DwImage::buffer). Any
+ access is done by function calls. Copying the lines (in
+ a_Image_write) is done by a_Image_buffer_copy_line, etc. The call to
+ Image_line becomes obsolete, since DilloImageBuffer will deal with
+ different types: indexed, RGB, gray, RGBA, gray-alpha(?). This may
+ be useful for a more efficient implementation of DilloImageBuffer.
+
+2. The modules Png, Jpeg, Gif, Image and DICache deal with the
+ original image size (read by the decoders), while DwImage gets the
+ "viewed" size (original size, multiplied by the global image
+ scaling factor) from DilloImageBuffer.
+
+3. For DwImage, there are further methods which replace the current
+ direct access. Note to worth:
+
+ - Scaled buffers are shared, reference counters are used. Copying
+ rows will automatically also affect the related scaled buffers.
+
+ - There are two methods for drawing, one called after expose events
+ (Dw_image_draw) and another called by a_Dw_image_draw_row. The
+ exact rules, how the buffer is scaled (this can, e.g., differ by a
+ pixel or so), is hidden by DilloImageBuffer.
+
+ - As noted above, all DwImage code is based on the viewed size.
+
+4. The global image scaling factor is used in two places. The HTML
+ parser must apply it on the WIDTH and HEIGHT attributes of the
+ <IMG> tag and DilloImageBuffer must use it to scale the inherent
+ size of an image. There are two modes, which the user can switch
+ by a dillorc option:
+
+ (i) The original image data is preserved, and an additional scaled
+ buffer is created:
+
+ +-------+ +------------------+ additional
+ | Image | -- copy --> | DilloImageBuffer | --> scaled
+ +-------+ rows | (original size) | buffers
+ +------------------+
+ | ^
+ | |
+ scale requests
+ each row for scaled
+ | buffers
+ | |
+ v |
+ +------------------+
+ | DilloImageBuffer |
+ | (viewed size) |
+ +------------------+
+ ^
+ |
+ +---------+
+ | DwImage |
+ +---------+
+
+ (ii) The original data gets lost just after scaling:
+
+ +-------+ +------------------+
+ | Image | -- copy --> | DilloImageBuffer | --> scaled
+ +-------+ rows | (viewed size) | buffers
+ +------------------+
+ ^
+ |
+ +---------+
+ | DwImage |
+ +---------+
+
+ (ii) uses generally less memory, while in some cases leads to a
+ lower rendering quality, as in this example:
+
+ "foo.png" has a size of 100x100 pixels, the image scaling factor is
+ 50%, and the following HTML sniplet is rendered:
+
+ <img src="foo.png">
+ <img src="foo.png" width=200 height=200>
+
+ The first image is displayed at a size of 50x50, the second at
+ 100x100. (i) will, for the second, use the original buffer, but
+ (ii) will enlarge the buffer, which was scaled down before, so
+ resulting in a "pixelized" image.
+
+5. Any implementation of DilloImageBuffer will handle transparency
+ independent of the background, i.e., the background colour will not
+ be used anymore. The first implementation may be based on GdkRGB
+ and (when needed) dithered clipping bitmaps. Better implementations
+ may then be developed in the future.
+
+6. Background images: The modules Image and DICache do no longer
+ access the DwImage directly, all calls are replaced by an
+ Interface, which is then implemented by DwImage and an appropriate
+ structure for background images (part of DwStyle). The interface is
+ in C realized by a struct of function pointers, and a generic
+ pointer on DwImage, etc.
+
+7. If someone really needs it, animated GIF's may be considered.
diff --git a/doc/DwPage.txt b/doc/DwPage.txt
new file mode 100644
index 00000000..71e6af88
--- /dev/null
+++ b/doc/DwPage.txt
@@ -0,0 +1,152 @@
+Nov 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+======
+DwPage
+======
+
+A widget for displaying texts. It is (currently) the main widget for
+rendering HTML documents.
+
+
+Signals
+=======
+
+DwPage defines the same signals as DwImage, except "image_pressed",
+with the exception that the coordinates are always -1. See
+DwImage.txt for more details.
+
+
+Collapsing Spaces
+=================
+
+The idea behind this is that every text box has a specific vertical
+space around and that they are combined to one space, according to
+rules stated below. A rule is either a paragraph within a DwPage
+widget, or a DwPage within a DwPage widget, in a single line; the
+latter is used for indented boxes and list items.
+
+The rules:
+
+ 1. If a box is following another, the space between them is the
+ maximum of both box spaces:
+
+ +---------+
+ |/////////|
+ |/////////| +---------+
+ +---------+ |/////////|
+ | A | |/////////|
+ +---------+ +---------+
+ |/////////| | A |
+ |/////////| +---------+
+ +---------+ are combined like this: |/////////|
+ |XXXXXXXXX|
+ +---------+ +---------+
+ |\\\\\\\\\| | B |
+ +---------+ +---------+
+ | B | |\\\\\\\\\|
+ +---------+ +---------+
+ |\\\\\\\\\|
+ +---------+
+
+ 2. a) If one box is the first box within another, the upper space
+ of these boxes collapse. b) The analogue is the case for the
+ last box:
+
+ +---------+ If B and C are put into A,
+ |/////////| the result is:
+ |/////////|
+ +---------+ +---------+ +---------+
+ | A | <--+-- |\\\\\\\\\| |/////////|
+ +---------+ ¦ +---------+ |XXXXXXXXX|
+ |/////////| | | B | +---------+
+ |/////////| | +---------+ | B |
+ +---------+ | |\\\\\\\\\| +---------+
+ | +---------+ |\\\\\\\\\|
+ | |\\\\\\\\\|
+ | +---------+ |\\\\\\\\\|
+ `-- |\\\\\\\\\| +---------+
+ |\\\\\\\\\| | C |
+ |\\\\\\\\\| +---------+
+ +---------+ |\\\\\\\\\|
+ | C | |XXXXXXXXX|
+ +---------+ |XXXXXXXXX|
+ |\\\\\\\\\| +---------+
+ |\\\\\\\\\|
+ |\\\\\\\\\|
+ +---------+
+
+For achieving this, there are some features of DwPage:
+
+ - Consequent breaks are automatically combined, according to
+ rule 1. See the code of a_Dw_page_add_break for details.
+
+ - If a break is added as the first word of the DwPage within
+ another DwPage, collapsing according to rule 2a is done
+ automatically. See the code of a_Dw_page_add_break.
+
+ - To collapse spaces according to rule 2b,
+ a_Dw_page_hand_over_break must be called for the *inner*
+ widget. The HTML parser does this in Html_eventually_pop_dw.
+
+
+Collapsing Margins
+==================
+
+Collapsing margins, as defined in the CSS2 specification, are,
+supported in addition to collapsing spaces. Also, spaces and margins
+collapse themselves. I.e., the space between two paragraphs is the
+maximum of the space calculated as described in "Collapsing Spaces"
+and the space calculated according to the rules for collapsing margins.
+
+(This is an intermediate hybrid state, collapsing spaces are used in
+the current version of dillo, while I implemented collapsing margins
+for CSS and integrated it already into the main trunk. For a pure
+CSS-based dillo, collapsing spaces will not be needed anymore, and may
+be removed for simplicity.)
+
+
+Some Internals
+==============
+
+There are two lists, words and lines. The word list is quite static;
+only new words may be added. A word is either text, a widget, a break
+or an anchor. Anchors are stored in the text, because it may be
+necessary to correct the scroller positions at rewrapping.
+
+Lines refer to the word list (first and last), they are completely
+redundant, i.e., they can be rebuilt from the words. Lines can be
+rewrapped either completely or partially (see "Incremental Resizing"
+below). For the latter purpose, several values are accumulated in the
+lines. See the file "dw_page.h" for details.
+
+
+Incremental Resizing
+--------------------
+DwPage makes use of incremental resizing as described in Dw.txt,
+section "Resizing". The parent_ref is, for children of a DwPage,
+simply the number of the line.
+
+Generally, there are three cases which may change the size of the
+widget:
+
+ 1. The available size of the widget has changed, e.g., because the
+ user has changed the size of the browser window. In this case,
+ it is necessary to rewrap all the lines.
+
+ 2. A child widget has changed its size. In this case, only a rewrap
+ down from the line where this widget is located is necessary.
+
+ (This case is very important for tables. Tables are quite at the
+ bottom, so that a partial rewrap is relevant. Otherwise, tables
+ change their size quite often, so that this is necessary for a
+ fast, non-blocking rendering)
+
+ 3. A word (or widget, break etc.) is added to the page. This makes
+ it possible to reuse the old size by simply adjusting the
+ current width and height, so no rewrapping is necessary.
+
+The state of the size calculation is stored in wrap_ref within DwPage,
+which has the value -1 if no rewrapping of lines necessary, or
+otherwise the line from which a rewrap is necessary.
+
diff --git a/doc/DwRender.txt b/doc/DwRender.txt
new file mode 100644
index 00000000..73fd0ded
--- /dev/null
+++ b/doc/DwRender.txt
@@ -0,0 +1,620 @@
+Aug 2004, S.Geerken@ping.de
+
+===========================
+ Dw Render Abstraction
+===========================
+
+This document describes the rendering abstraction used in Dw. At the
+time this document was written, some other documents about Dw were out
+of date, and have to be rewritten.
+
+Sometimes, you will find remarks about the old design (with one
+concrete Gtk+ widget instead of the layout/multiple rendering views);
+those are useful for those, who are already familiar with the old
+design. Furthermore, it makes the explanation often simpler, because
+the new design is a bit more complex.
+
+Naming
+------
+As stated in "Dw.txt", the prefix "p_Dw_" is used for functions used
+within the whole Dw module, but not outside. Typically, these are
+protected functions, which are called by inherited classes. E.g., a
+specific widget will have to call p_Dw_widget_queue_resize(), but this
+function should not called outside from Dw.
+
+The "Dw_" prefix is not only used for functions, which use is
+restricted to a sub-module, but also for functions used only within
+the core of Dw. The distinction between both can simply made, whether
+the function is declared as static or not. The core of Dw consists of
+the modules Dw_widget and Dw_render, anything else is inherited from
+these two modules (widgets, platforms, views). As an example,
+Dw_gtk_viewport_queue_resize() is only called in the Dw_widget module,
+it should not be called by a widget implementation.
+
+
+Overview
+========
+
+Rendering of Dw is done in a way resembling the model-view pattern, at
+least formally. Actually, the counterpart of the model, the layout
+(DwRenderLayout), does a bit more than a typical model, namely
+calculating the layout, and the views do a bit less than a typical
+view, i.e. only the actual drawing.
+
+Additionally, there is a structure representing common properties of
+the platform, views generally work only together with one specific
+platform. A platform is typically related to the underlying UI
+toolkit, but other uses may be thought of.
+
+The general structure looks like this:
+
+ 1 +------------------+
+ .---->| DwRenderPlatform |
+ +----------------+ 1 / +------------------+
+ | DwRenderLayout |--< ^ 1
+ +----------------+ \ | *
+ 1 ^ | 1 \ +--------------+
+ | | `---->| DwRenderView |
+ | | * +--------------+
+ | |
+ layout | | toplevel_dw
+ | |
+ * | V 0..1
+ +----------+ 0..1
+ | DwWidget |--. parent
+ +----------+ |
+ * | |
+ `-------'
+ (children)
+
+(This is a bit simplified, actually, only DwContainer has child
+widgets, and the relation is only defined in an abstract way).
+
+DwRenderLayout and DwWidget (including sub classes) are platform and
+view independant, i.e., it should be possible to adopt them into
+another platform, after suitable implementations of DwRenderPlatform
+and DwRenderView have been developed.
+
+(The only exception is DwEmbedGtk, a widget which, in the old design,
+embeds Gtk+ widgets into the DwWidget tree. This will still remain a
+platform specific widget, see notes in the section "UI Widgets".
+
+Furthermore, this design does not yet cover DwStyle, which is still
+bound to the Gtk+ platform. It may be simply replaced for other
+platforms, but this will lose the possibility to have multiple
+implementations of DwRenderPlatform running within the same program.
+The same aplies to DwTooltip and Imgbuf.)
+
+This new design helps to archieve two important goals:
+
+ 1. Abstraction of the actual rendering. Currently, we only have the
+ normal viewport, but a list of planned implementations can be
+ found below in this text.
+
+ 2. It makes different views of the same document simple, e.g. the
+ normal viewport and the preview window.
+
+ 3. It makes portability simpler.
+
+Vieports are handles by this design, but only in a rather abstract
+way, and may be removed completely, i.e., they will be only part of
+specific view implementations. This also means, that the distinction
+between world coordinates and viewport coordinates vanishes from most
+parts of Dw.
+
+
+World
+=====
+
+The world is the whole area, in which content is rendered. For a view
+without a viewport, this is the whole itself. A view with a viewport
+provides a way, so that the user may see some part of the world within
+a (in most cases) smaller window, the viewport.
+
+The world may have a base line, so that the worls size is described by
+three numbers, width, ascent and descent.
+
+Any view must implement the method set_world_size(), which is called,
+whenever the world size changes. For viewports, this will change
+scroll bars etc., for views without viewport, this will normally
+change the size of the view itself. (Although on this level, "view
+size" is not defined. This should not be confused with the viewport
+size!)
+
+
+Drawing
+=======
+
+A view must implement several drawing methods, which work on the whole
+world. If it is neccesary to convert them (e.g. in DwGtkViewport),
+this is done in a way fully transparent to DwWidget and
+DwRenderingLayout, instead, this is done by the view implementation.
+
+There exist following situations:
+
+ - A view gets an expose event: It will delegate this to the
+ rendering layout, which will then pass it to the widgets, 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. The drawing requests are queued, and
+ compressed. in an this idle function, DwWidget::draw is called
+ for the toplevel widget, for each view.
+
+ (This is still something to consider, the queueing may be moved
+ again into the view implementations.)
+
+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 rendering view related to the
+actual rendering view, which guarantees that the parts drawn outside
+are discarded. At the end, the clipping view is merged into the actual
+view. Sample code for widget DwFoo:
+
+ void Dw_foo_draw (DwWidget *widget,
+ DwRenderView *view,
+ DwRectangle *area)
+ {
+ DwRenderView *clip_view;
+
+ /* 1. Create a clipping view. */
+ clip_view =
+ p_Dw_render_view_get_clipping_view (view,
+ widget->allocation.x,
+ widget->allocation.y,
+ widget->allocation.width
+ DW_WIDGET_HEIGHT (widget));
+
+ /* 2. Draw into clip_view. */
+ Dw_render_view_do_some_drawing (clip_view, ...);
+
+ /* 3. Draw the children, they receive the clipping view as argument. */
+ for (<all relevant children>) {
+ if (p_Dw_widget_intersect (button->child, area, &child_area))
+ p_Dw_widget_draw (child, clip_view, child_area);
+ }
+
+ p_Dw_render_view_merge_clipping_view (view, clip_view);
+ }
+
+A drawing process is always embedded into calls of
+DwRenderView::start_drawing() and DwRenderView::finish_drawing(). An
+implementation of this are backing pixmaps, to prevent flickering.
+
+
+Viewports and Scrolling Positions
+=================================
+
+Although the design implies that the usage of viewports should be
+fully transparent to the Dw_render module, this cannot be fully
+archived, for the following reasons:
+
+ 1. Some features, which are used on the level of DwWidget,
+ e.g. anchors, refer to scrolling positions.
+
+ 2. Some code in DwWidget is currently tightly bound to viewports.
+ This may be change, by delegating some of this functionality to
+ viewports, and defining scrolling positions in a more abstract
+ way.
+
+Therefor, DwRenderLayout keeps track of the viewport size, the
+viewport position, and even the thickness of the scrollbars (or,
+generally, "viewport marker"), they are relevant, see below. These
+sizes are always equal in all views. However, a given view may not use
+viewports at all, and there may be the case, that no view related to a
+layout uses viewports, in this case, the viewport size is not defined
+at all.
+
+Unlike world sized, viewports are not considered to have a base line,
+i.e., they are described by only two numbers, width and height.
+
+Viewport Size
+-------------
+All viewport sizes and positions are the same in all views, which uses
+viewports. There are two cases, in which the viewport size changes:
+
+ 1. As an reaction on a user event, e.g. when the user changes the
+ window size. In this case, the affected view delegates this
+ change to the layout, by calling
+ p_Dw_render_layout_vieport_size_changed(). All other views are
+ told about this, by calling DwRenderView::set_viewport_size().
+
+ 2. 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 an own
+ section.
+
+After the creation of the layout, the viewport size is undefined. When
+a view is attached to a layout, and this view is already to be able to
+define its viewport size, it may already call
+p_Dw_render_layout_vieport_size_changed() within the implementation of
+set_layout. If not, it may do this, as soon as the viewport size gets
+known.
+
+Each call of p_Dw_render_layout_vieport_size_changed() will change the
+viewport size of all other views, which use viewports, so this
+function has to be called with care.
+
+If there is no view attached, which used viewports, the viewport size
+remains undefined.
+
+Viewport Markers
+----------------
+Viewport markers are UI widgets, which display to the user the
+relation of the world size and the widget size. Most commonly,
+scrollbars will be used.
+
+When they are not needed, they are hidden, as in the following figure:
+
+
+ +--------------------+
+ | This is only a |
+ | very short text. |
+ | |
+ | |
+ | |
+ +--------------------+
+
+but shown, as soon as the world size exceeds the viewport size:
+
+ +------------------+-+
+ | In this example, |^|
+ | there is some |#|
+ | more text, so |#|
+ | that the | |
+ | vertical |v|
+ +------------------+-+
+
+A view using viewports must provide, how large the differences
+are. Generally, there are four cases, from the combinations of whether
+the world width is smaller (-) or greater (+) than the viewport width,
+and whether the world height is smaller (-) or greater (+) than the
+viewport height. So there are eight numbers, the horizontal difference
+dh, and the vertical difference dv, for the cases --, -+, +-, and ++.
+
+For scrollbars, the values are rather simple:
+
+ - dh is 0 for the cases -- and -+, and the thickness of the
+ vertical scrollbar in the cases +- and ++.
+
+ - dv is 0 for the cases -- and +-, and the thickness of the
+ horizontal scrollbar in the cases -+ and ++.
+
+For any view implementation, the following rules must be fullfeeded
+(dx means either dh or dv):
+
+ - dx(-+) >= d(--)
+ - dx(++) >= d(+-)
+ - dx(+-) >= d(--)
+ - dx(++) >= d(-+)
+
+In short, when smaller world dimensions (-) grow (switch to +), the
+differences may not become less.
+
+The sizes of viewport markers are part of the viewport size, the
+method DwRenderView::set_viewport_size() has four parameters:
+
+ - two for the size of the viewport, *including* the markers
+ (i.e. the markers never change the size), and
+
+ - two, which denote the differences between the above and the
+ actual viewport size, caused by the markers. If a value of these
+ is 0, the respective marker is hidden, if it is greater than 0,
+ it is shown. In the latter case, the maximun is calculated, and
+ passed to all views.
+
+(Actually, the decision, whether the markers are visible or not, is a
+bit more complicated, since the vieport size also defines the size
+hints for the topmost widget, which may affect the widget size, and so
+the world size. Handling this problem is done within DwRenderLayout,
+look at the comments there.)
+
+Scrolling Positions
+-------------------
+The scrolling position is the world position at the upper left corner
+of the viewport. Views using viewports must
+
+ 1. change this value on request, and
+ 2. tell other changes to the layout, e.g. caused by user events.
+
+Applications of scrolling positions (anchors, test search etc.) are
+handled by the layout, in a way fully transparent to the views.
+
+
+An Example with Nested Views
+============================
+The following example refers to graphical plugins, which are not yet
+realized (I have some working proof-of-concept code), but which will
+most likely follow the design, which is here shortly described, as
+needed to understand the example (since there is no specification of
+graphical plugins yet). I included this, to demonstrate, how nested
+layouts can be used.
+
+Graphical plugins will communicate with dillo via two protocols, dpi1
+(for anything not directly related to rendering), and a new protocol,
+which is an extension of the XEmbed protocol (see somewhere at
+http://freedesktop.org, this is the protocol, which GtkPlug and
+GtkSocket use). Within dillo, a socket window will be created, which
+window id will be (via dpi1?) passed to the plugin. The plugin will
+then create a plugin window, in which the contents of a web recource
+is shown, which dillo cannot show natively.
+
+XEmbed will be extended, so that the plugins may make use of the
+extensions, which the Dw size model adds to the XEmbed size
+model. Such a plugin behaves (on an abstract level) like a DwWidget,
+so following extensions are necessary:
+
+ - a plugin may not simply have a size, but instead distinguish
+ between ascent and descent,
+ - a plugin may return width extremes, and
+ - it is possible to send size hints to the plugin.
+
+Within Dw, the socket will be realized by a special plugin,
+DwSocketGtk (or a respective widget for other platforms), which is a
+sub class of DwEmbedGtk, and embeds another UI widget, which will
+provide the socket window (for Gtk+, either GtkSocket, or a sub class
+of this).
+
+The plugins may be implemented independently of Dw, they either do not
+support the extensions to XEmbed (then, the respective features behave
+in a default way), or they may contain there own implementation.
+However, Dw may be extracted from dillo, to become an own library. A
+plugin using this library may then use a special type of view,
+GtkDwFlatView (for plugins based on Gtk+, actually, the UI toolkit for
+dillo and the plugin must not be the same, since the protocol will be
+UI toolkit independant.)
+
+This will lead to a structure like this:
+
+ top_layout:DwRenderLayout ----- top_page:DwPage
+ / \ |
+ :GtkDwPlatform top_view:GtkDwView `- table:DwTable
+ |
+ `- cell:DwTableCell
+ |
+ `- socket:DwSocketGtk
+ |
+ DILLO gtk_socket:GtkSocket
+ .
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - . (extension of
+ . XEmbed)
+ PLUGIN
+ plugin_layout:DwRenderLayout ----- dw_flat_view:GtkDwFlatView
+ \
+ `------- foo:DwFoo
+
+GtkDwFlatView is both an extension of GtkSocket, as well as an
+implementation of DwRenderView.
+
+This case must be equivalent to the case, that the widget "foo" is a
+direct child of the widget "cell", since all objects between them only
+delegate all functionality. Size hints must so sent as in the
+following scenario:
+
+ 1. The view "top_view" receieves an event, which will change the
+ viewport size, and delegates this to the layout.
+
+ 2. The layout will make size hints of this viewport size, i.e., it
+ calls the set_* methods of the widget "top_page".
+
+ 3. DwPage::set_* will queue a resize request, which is delegated
+ to the layout.
+
+ 4. Handling the resize request is done within a idle loop. Here,
+ size_request is called for the widget "top_page", to determine
+ the preferred size.
+
+ 5. DwPage::size_request will depend on the size hints, especially,
+ it will use the hinted size to determine the word wrap width.
+ Within DwPage::size_request, size hints will be sent to the
+ child widgets. The size hints sent to the children are those
+ sent to the page, minus the respective border widths (margins,
+ borders, paddings). (How the ascent and descent hints should
+ generally be delegated to the children, is still a matter of
+ consideration, and may change.)
+
+ 6. DwTable::size_request, which is called within this context, has
+ a different way to delegate the size hints to the children:
+ ascent and descent are handled the same way, but the widths are
+ calculated from the column widths, which are calculated within
+ DwTable::size_request.
+
+ 7. Via the widget "cell", finally the widget "socket" receives
+ appropriate size hints. These must be (equally) delegated to
+ the widget "foo", this is done in a way described in the
+ following steps.
+
+ 8. The size hints are transmitted via the protocol extending
+ XEmbed. The Gtk+ widget "dw_flat_view" receives them (via the
+ widget "gtk_socket"), and delegates them to the respective
+ layout "plugin_layout". (TODO: How is this done? What has to be
+ done is to send the size hints to the toplevel widget, but a
+ view has no access to it.)
+
+ 9. The layout "plugin_layout" will then delegate this (what ever
+ "this" means), as size hints, to the widget "foo".
+
+ 10. The widget "foo" will queue a size_request, which is delegated
+ to the layout. In the idle function handling this request, the
+ recalculation of the widget size will change the world size,
+ which is delegated to the view "dw_flat_view".
+
+ 11. For GtkDwFlatView, the world size is the view size. For this
+ reason, it changes its size, to fit the world size. This size
+ is send to the DwSocket, which will then request a size
+ request.
+
+
+UI Widgets
+==========
+A note before: This chapter refers often to Gtk+ as base UI toolkit,
+just to make naming simpler, For other UI toolkits, the same, mostly
+only with other names, applies.
+
+In some cases, it is necessary to embed widgets from the UI toolkit
+into the view, e.g. to realize HTML forms in dillo.
+
+The Dw_render module provides no interface at all, instead, this is
+completely left to the platform implementations. Below, two design
+approaches are discussed, which have following in common:
+
+ 1. There is a special Dw widget, which embeds something related to
+ the UI widgets (below called DwEmbedGtk).
+
+ 2. This Dw widget, the platform, and the views are tightly bound,
+ beyond the methods, which the respective interfaces provide. The
+ Dw widget can simply refer to the platform by
+ (DwWidget::render_layout->platform, and the platform may refer
+ to the views, when DwPlatform::attach_view and
+ DwPlatform::detach_view are implemented.
+
+General Problems
+----------------
+For most UI toolkits, there have to be multiple instances of widgets
+in different views. Furthermore, there may be, on the same platform,
+different classes for the same widgets. Consider this simple example:
+
+ :DwRenderLayout ------------------- :DwPage
+ / \ |
+ ,----' `----. dw:DwEmbedGtk
+ / \
+ view1:GtkDwViewport view2:GtkDwViewport
+ | |
+ gtk1:GtkButton gtk2:GtkButton
+
+This structure represents a page with one button in it, which is, in
+the DwWidget tree, represented by the DwEmbedGtk "dw", and, in the
+views "view1" and "view2", by the Gtk+ widgets "gtk1" and "gtk2",
+respectively. The old approach, where the UI widget (in this case
+GtkButton) is not directly applicable, since there must be multiple
+instances of this UI widget.
+
+Here is a more complex example:
+
+ :DwRenderLayout ------------------- :DwPage
+ / \ |
+ ,----' `----. dw:DwEmbedGtk
+ / \
+ view1:GtkDwFooView view2:GtkDwBarView
+ | |
+ gtk1:GtkFooButton gtk2:GtkBarButton
+
+In this case, the different views GtkDwFooView and GtkDwBarView deal
+with different classes for buttons, GtkFooButton and GtkBarButton.
+
+Simple Approach
+---------------
+Within dillo, the following limitations are reasonable:
+
+ 1. There is only one view instance, which actually needs UI widgets
+ (GtkDwViewport for Gtk+). There may be multiple views, but these
+ additional views do not need instances of widgets, e.g. in the
+ preview, a UI widget is simply shown as a grey box.
+
+ 2. There is only one type of UI widget, i.e. normal Gtk+ widgets.
+
+Because of these limitations, the implementation of UI widgets is
+currently quite simple in dillo. As before, the widget DwEmbedGtk
+refers to an instance of a concrete Gtk+ widget. This Gtk+ widget is
+told to the platform, of which DwEmbedGtk knows, that it is an
+instance of GtkDwPlatform. GtkDwPlatform will add this Gtk+ widget to
+the single view, which needs it, and DwEmbedGtk will be responsible of
+allocating etc. of the Gtk+ widget.
+
+Advanced Approach
+-----------------
+This is a short overview of an approach, which will overcome the
+limitations of the simple approach, but with the costs of a greater
+complexity. It will be detailed, in the case, that it is implemented.
+
+ +------------+ factory +---------------------+
+ | DwEmbedGtk | ---------> | DwGtkWidgetFactory |
+ +------------+ 1 1 +---------------------+
+ | create_foo_widget() |
+ | create_bar_widget() |
+ +---------------------+
+ . . .
+ /_\ /_\ /_\
+ | | |
+ - - - - - - - - - - - - - - - - - .
+ | |
+ +---------------------+ +---------------------+ |
+ | DwGtkButtonFactory | | DwGtkListFactoty | (other ...)
+ +---------------------+ +---------------------+
+ | create_foo_widget() | | create_foo_widget() |
+ | create_bar_widget() | | create_bar_widget() |
+ +---------------------+ | add_list_item(...) |
+ +---------------------+
+
+DwEmbedGtk refers to a factory, which creates the UI widgets for each
+view. For each general widget type (e.g. button, list, ...), there is
+an implementation of this interface.
+
+This interface DwGtkWidgetFactory contains different method for
+different views. E.g., when a button is shown, and so DwEmbedGtk
+refers to a DwGtkButtonFactoty, GtkDwFooView may need a GtkFooButton,
+which is created by create_foo_widget(), while GtkDwBarView may call
+create_bar_widget(), to get a GtkBarButton. (This design still makes
+it hard to add new views, which then need, say, GtkBazButtons.)
+
+The concrete factories may contain additional methods, in the diagram
+above, DwGtkListFactory must provide a function to add items to the
+lists. This method will add a item to all list widget, which were
+created by this factory.
+
+
+More Ideas for View Implementations
+===================================
+
+Preview Window
+--------------
+The status bar gets a new button, on which the user may click to get a
+small image of the small page, in which he can select the viewport
+position by dragging a rubber-band rectangle. The actual scaling
+factor will probably depend on the aspect ratio of the page.
+
+(This has already been implemented for Gtk+, as GtkDwPreview and
+GtkDwPreviewButton.)
+
+Graphical Plugin
+----------------
+See section "An Example with Nested Views" for explanations.
+
+======================================================================
+
+Alternative design for handling UI widgets:
+
+- There is a platform *independant* widget, the platform dependencies
+ are within the factories.
+
+ DwEmbedUI::draw
+ -> DwRenderView::draw_ui_widget(..., factory)
+
+Implementation of "draw_ui_widget" in a preview view:
+ -> draw some gray boxes etc.
+
+Implementation of "draw_ui_widget" in a normal "bar" view (for platform "foo"):
+ -> determine that is is a factory for a "baz" widget?
+ -> (BarFactory*)factory->get_foo_bar_widget(this)
+
+This method either returns an already created widget, or creates one
+with the current state of the factory. "This" is taken as a key.
+
+----
+
+ | general | widget specific
+----------------------+------------------+------------------------
+ platform independant | nothing? | e.g. adding list items
+----------------------+------------------+------------------------
+ platform dependant | e.g. creating a | ???
+ | widget, or |
+ | informations |
+ | about drawing in |
+ | a preview |
+
+======================================================================
+
+Abstraction of DwStyle
+----------------------
+structures needed:
diff --git a/doc/DwStyle.txt b/doc/DwStyle.txt
new file mode 100644
index 00000000..9a1ec4e5
--- /dev/null
+++ b/doc/DwStyle.txt
@@ -0,0 +1,310 @@
+Apr 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+=======
+DwStyle
+=======
+
+Styles of Dillo Widgets
+
+
+Note
+====
+
+DwStyle has derived from DwPageAttr, and its current structure is very
+similar to it. In the future, there will be some changes and extensions.
+Namely:
+
+ - image maps will be handled differently (done),
+ - margins, borders, paddings (done),
+ - background colors/images, and
+ - cursors and tooltips will perhaps move into DwStyle.
+
+Furthermore, widgets will probably refer to different styles for
+different states.
+
+
+Overview
+========
+
+DwStyle provides some resources and attributes for drawing widgets, as
+well as for parts of a widget (e.g., DwPage uses DwStyle's for its
+words). Creating a style is done by filling a DwStyle with the
+attributes (except the ref_count), and calling Dw_style_new:
+
+ DwStyle style_attrs, *style;
+
+ style_attrs.foo = bar;
+ // etc.
+ style = a_Dw_style_new (&style_attrs, random_window);
+ // do something with style
+
+After this, the attributes of style should not be changed anymore,
+since styles are often shared between different widgets etc. (see
+below). Most times, you simply copy the attributes of another style
+and modify them:
+
+ style_attrs = *another_style;
+ style_attrs.foo = bar;
+ style = a_Dw_style_new (&style_attrs, random_window);
+
+The font structure can be created by Dw_style_font_new, in a similar
+way (the GdkFont in font_attrs will be ignored), and colors by
+Dw_style_color_new, passing 0xrrggbb as an argument. Note that fonts
+and colors are only intended to be used in conjunction with DwStyle.
+
+
+Lengths and Percentages
+=======================
+
+DwStyleLength is a simple data type for lengths and percentages:
+
+ - A length refers to an absolute measurement. It is used to
+ represent the HTML type %Pixels; and the CSS type <length>.
+
+ For CSS lenghts, there are two units: (i) pixels and absolute
+ units, which have to be converted to pixels (a pixel is, unlike
+ in the CSS specification, treated as absolute unit), and (ii) the
+ relative units "em" and "ex" (see below).
+
+ - A percentage refers to a value relative to another value. It is
+ used for the HTML type %Length; (except %Pixels;), and the CSS
+ type <percentage>.
+
+ - A relative length can be used in lists of HTML MultiLengths.
+
+Since many values in CSS may be either lengths or percentages, a
+single type is very useful.
+
+Useful macros and functions
+---------------------------
+Macros for creating lengths:
+
+ DW_STYLE_CREATE_LENGTH (n) Returns a length of n pixels.
+
+ DW_STYLE_CREATE_EX_LENGTH (n) Returns a length of n times the
+ 'x-height'
+
+ DW_STYLE_CREATE_EM_LENGTH (n) Returns a length of n times the
+ 'font-size'
+
+ DW_STYLE_CREATE_PERCENTAGE (n) Returns a percentage, n is relative
+ to 1, not to 100.
+
+ DW_STYLE_CREATE_RELATIVE (n) Returns a relative length.
+
+ DW_STYLE_UNDEF_LENGTH Used to indicate unspecified sizes,
+ errors, and the end of a list of
+ lengths.
+
+Furthermore, there are some functions in html.c:
+
+ DwStyleLength Html_parse_length (gchar *attr);
+
+ Returns a length or a percentage, or DW_STYLE_UNDEF_LENGTH in
+ case of an error.
+
+ DwStyleLength* Html_parse_multi_length (gchar *attr);
+
+ Returns a vector of lengths/percentages. The caller has to free
+ the result when it is not longer used.
+
+Macros for examining lengths:
+
+ DW_STYLE_IS_LENGTH (l) Returns TRUE if l is a length.
+
+ DW_STYLE_IS_PERCENTAGE (l) Returns TRUE if l is a percentage.
+
+ DW_STYLE_IS_RELATIVE (l) Returns TRUE if l is a relative
+ length.
+
+ DW_STYLE_GET_LENGTH (l, f) Returns the value of a length in
+ pixels, as an integer. f is the
+ font, this is used if l is based on
+ font sizes.
+
+ DW_STYLE_GET_PERCENTAGE (l) Returns the value of a percentage,
+ relative to 1, as a float.
+
+ DW_STYLE_GET_RELATIVE (l) Returns the value of a relative
+ length, as a float.
+
+
+Representation
+--------------
+Notes:
+
+ 1. This is not part of the interface and may change! Use the
+ macros described above.
+ 2. Negative numbers may not work yet.
+
+DwStyleLength is represented by an integer (n is the number of bits of
+an integer):
+
+ - Undefined lengths are represented by 0.
+
+ - Lenghts in pixel:
+
+ +---+ - - - +---+---+---+---+
+ | int value | 0 | 1 |
+ +---+ - - - +---+---+---+---+
+ n-1 3 2 1 0
+
+ - Lengths in in x-height:
+
+ +---+ - - - +---+---+---+---+
+ | real value | 0 | 1 | 1 |
+ +---+ - - - +---+---+---+---+
+ n-1 3 2 1 0
+
+ - Lengths in in font-size:
+
+ +---+ - - - +---+---+---+---+
+ | real value | 1 | 1 | 1 |
+ +---+ - - - +---+---+---+---+
+ n-1 3 2 1 0
+
+ - Percentages:
+
+ +---+ - - - +---+---+---+---+
+ | real value | 0 | 1 | 0 |
+ +---+ - - - +---+---+---+---+
+ n-1 3 2 1 0
+
+ - Relative lengths:
+
+ +---+ - - - +---+---+---+---+
+ | real value | 1 | 1 | 0 |
+ +---+ - - - +---+---+---+---+
+ n-1 3 2 1 0
+
+A "real value" is a fixed point number consisting of (m is the number
+of bits of the value, not the whole integer):
+
+ +---+ - - - +---+---+ - - - +---+
+ | integer part | rest |
+ +---+ - - - +---+---+ - - - +---+
+ m 16 15 0
+
+For *internal* use, there are two converting macros,
+DW_STYLE_REAL_TO_FLOAT and DW_STYLE_FLOAT_TO_REAL.
+
+
+DwStyle Boxes
+=============
+
+The CSS Box Model
+-----------------
+For borders, margins etc., DwStyle uses the box model defined by
+CSS2. DwStyle contains some members defining these attributes. A
+widget must use these values for any calculation of sizes. There are
+some helper functions (see dw_style.h). A DwStyle box looks quite
+similar to a CSS box:
+
+
+ ,-- margin.left
+ | ,-- border.left
+ | | ,-- padding.left
+ |---+---+---|
+ +---------------------------------------+ ---
+ | | | margin.top
+ | +-------------------------------+ | -+-
+ | | Border | | | border.top
+ | | +-----------------------+ | | -+-
+ | | | Padding | | | | padding.top
+ new widget | | | +---------------+ | | | ---
+ allocation -->| | | | | | | |
+ | | | | Content | | | |
+ former widget ------------>| | | | |
+ allocation | | | +---------------+ | | | ---
+ | | | | | | | margin.bottom
+ | | +-----------------------+ | | -+-
+ | | | | | border.bottom
+ | +-------------------------------+ | -+-
+ | | | padding.bottom
+ +---------------------------------------+ ---
+ |---+---+---|
+ padding.right --' | |
+ border.right --' |
+ margin.right --'
+
+Background colors
+-----------------
+The background color is stored in style->background_color, which be
+NULL (the background color of the parent widget is shining through).
+
+For toplevel widgets, this color is set as the background color of the
+viewport, for other widgets, a filled rectangle is drawn, covering the
+content and padding. (This is compliant with CSS2, the background
+color of the toplevel element covers the whole canvas.)
+
+Drawing
+-------
+There is a new function Dw_widget_draw_widget_box, which should be
+called at the beginning of Dw_foo_draw. For parts referring to styles
+(e.g., words in a page), Dw_widget_draw_box should be used.
+
+
+Notes on Memory Management
+==========================
+
+Memory management is done by reference counting, a_Dw_style_new
+returns a pointer to DwStyle with an increased reference counter, so
+you should care about calling Dw_style_unref if it is not used
+anymore. You do *not* need to care about the reference counters of
+fonts and styles.
+
+In detail:
+
+ - a_Dw_style_ref is called in
+
+ * a_Dw_widget_set_style, to assign a style to a widget,
+
+ * a_Dw_page_add_text, a_Dw_page_add_widget,
+ a_Dw_page_add_anchor, to assign a style to a word,
+
+ * and Html_push_tag (often the reference counter is again
+ decreased shortly after this).
+
+ - a_Dw_unref_style is called in:
+
+ * Dw_page_destroy, Dw_widget_destroy, Html_cleanup_tag,
+ Html_pop_tag, Html_close,
+
+ * a_Dw_widget_set_style, Html_set_top_font (and several
+ Html_tag_open_... functions), these functions overwrite an
+ existing style.
+
+
+HTML Stack
+==========
+
+(This is not DwStyle specific, but may be useful if you are working on
+the HTML parser.)
+
+The topmost element of the HTML stack contains a (reference to a)
+style which will be used to add the text to the current page. If you
+use a style only for a short while (see Html_tag_open_frame for an
+example), you may use it this way:
+
+ style_attrs = *html->stack[html->stack_top].style;
+ style_attrs.foo = bar;
+ style = a_Dw_style_new (&style_attrs, random_window);
+
+Do not forget to unref it afterwards. A good choice for random_window
+is html->bw->main_window->window.
+
+In many cases, you want to set the style for the content of an element
+(e.g., <A>). Then you must store it in the stack:
+
+ DwStyle style_attrs, *old_style;
+
+ old_style = html->stack[html->stack_top].style;
+ style_attrs = *old_style;
+ style_attrs.foo = bar;
+ html->stack[html->stack_top].style =
+ a_Dw_style_new (&style_attrs, random_window);
+ a_Dw_style_unref (old_style);
+
+The macro HTML_SET_TOP_ATTR can be used for single attributes, for
+changing more attributes, this code should be copied for efficiency.
diff --git a/doc/DwTable.txt b/doc/DwTable.txt
new file mode 100644
index 00000000..07c06180
--- /dev/null
+++ b/doc/DwTable.txt
@@ -0,0 +1,205 @@
+May 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+=======
+DwTable
+=======
+
+A container widget for rendering tables.
+
+
+The DwTable Widget
+==================
+
+DwTable is a container widget for rendering tables. It aligns other
+DwWidgets (normally DwPage), according to the following rules:
+
+ 1. All columns have have the same width W, except:
+
+ - W is less than the minimal column width, or
+ - W is greater than the maximal column width.
+
+ Furthermore, W is
+
+ - less than all minimal widths of columns not having W as
+ width, and
+ - greater than all maximal widths of columns not having W as
+ width.
+
+ 2. The table tries to use exactly the whole available width, except
+ if it is not possible, because the it is less/greater than the
+ minimal/maximal table width.
+
+This is simple to implement for columns with COLSPAN == 1, using
+a_Dw_get_extremes for getting the minimal and maximal widths. For
+arbitrary COLSPAN values, an approach described in "Subtables" is
+used to get optimal results (as described above) in most cases, while
+the rendering remains fast.
+
+
+Subtables
+=========
+
+A table is divided into subtables, which do not (in most cases) share
+spanning cells, until single columns are left. Cells spanning the
+whole width are removed before dividing further. Example:
+
+ +---+-------+---+
+ | A | B | C |
+ +---+-------+---+
+ | D | E |
+ +---+-------+---+
+ | F | G | H |
+ +---+-------+---+
+ ' ' ` `
+ ' ' ` `
+ +---+-------+ +---+
+ | A | B | | C |
+ +---+-------+ +---+
+ removed --> | D | | E |
+ +---+-------+ +---+
+ | F | G | | H |
+ +---+-------+ +---+
+ ' ' ` ` final
+ ' ' ` `
+ +---+ +-------+
+ | A | | B | <-.
+ +---+ +-------+ >- removed
+ | F | | G | <-'
+ +---+ +-------+
+ final ' ' ` `
+ ' ' ` `
+ [empty] [empty]
+ final final
+
+There is a structure, DwTableSub, for holding all the information. It
+is rebuilt when new cells are added. Do not confuse this with nested
+tables, these are represented by the Dw widget hierarchy.
+
+If table cells overlap horizontally, they are (virtually) divided. The
+minimal and maximal widths are apportioned to the other columns
+(resulting in a non optimal layout):
+
+ +-------+---+---+
+ | A | B | C |
+ +---+---+---+---+
+ | D | E |
+ +---+-----------+
+ ' ' ` `
+ ' ' ` `
+ +-------+ +---+---+
+ | A | | B | C |
+ +---+---+ +---+---+
+ | D |1/3| | 2/3 E |
+ | | E | | |
+ +---+---+ +-------+
+
+Example for a non-optimal case
+------------------------------
+The HTML document fragment
+
+ <table>
+ <tr>
+ <td colspan="2">Text
+ <td>LongText
+ <tr>
+ <td>Text
+ <td colspan="2">LongText
+ </table>
+
+will result in:
+
+ | 0 | 1 | 2 |
+
+ +------------+----------+
+ | Text | LongText |
+ +------+-----+----------+
+ | Text | LongText |
+ +------+----------------+
+
+The width of column 1 is determined by the half of the minimal width
+of the LongText. An optimal rendering would be something like:
+
+ ,- 1
+ | 0 || 2 |
+
+ +-------+----------+
+ | Text | LongText |
+ +------++----------+
+ | Text | LongText |
+ +------+-----------+
+
+
+Algorithms
+==========
+
+Calculating extremes
+--------------------
+The extremes of all subtables are calculated by
+Dw_table_sub_get_extremes and stored in DwTableSub:
+
+ minimal/maximal width (sub table) =
+ - for single column: maximum of all minimal/maximal widths
+ - otherwise: maximum of
+ 1. all minimal/maximal widths of cells spanning
+ the whole width, and
+ 2. the sum of the minimal/maximal widths of the
+ sub-subtables
+
+ In step 1, the width argument is used to adjust the maximum
+ and minimum width of the whole subtable and mark it as fixed.
+
+todo: describe percentages.
+
+Calculating column widths
+-------------------------
+The calculation is based on a fixed width, which is, at the top, the
+width set by a_Dw_widget_set_width. This is corrected by the minimal and
+maximal width of the whole table, and, if given, the width attribute
+of the table. At each level, the available width is always between the
+minimal and the maximal width of the subtable.
+
+For single columns, the width is the passed fixed width. Otherwise:
+
+ 1. Calculate relative widths, they effect the minimal and maximal
+ widths. (Temporally, not permanently!)
+
+ 2. The sum of these corrected minima may be greater as the fixed
+ width of the subtable. In this case, decrease them again to
+ match exactly the fixed width, then use them as sub-subtable
+ fixed widths and finish. Otherwise, continue:
+
+ 3. If the extremes of the spanning widths of the subtable are
+ greater than the sum of sub-subtables extremes, adjust the
+ extremes of sub-subtables which are not fixed, i.e., where no
+ width argument (either percentage or fixed) freezes the width.
+
+ 4. Use an iteration on the subtables, to determine the column
+ widths, see Dw_table_sub_calc_col_widths for details.
+
+ 5. After this, apply this recursively on all subtables and pass the
+ subtable width as fixed width.
+
+
+Borders, Paddings, Spacing
+==========================
+
+Currently, DwTable supports only the separated borders model (see CSS
+specification). Borders, paddings, spacing is done by creating DwStyle
+structures with values equivalent to following CSS:
+
+ TABLE {
+ border: outset <table-border>;
+ border-collapse: separate;
+ border-spacing: <table-cellspacing>
+ background-color: <table-bgcolor>
+ }
+
+ TD TH {
+ border: inset <table-border>;
+ padding: <table-cellspacing>
+ background-color: <td/th-bgcolor>
+ }
+
+Here, <foo-bar> refers to the attribute bar of the tag foo. See
+Html_open_table and Html_open_table_cell for more details.
diff --git a/doc/DwWidget.txt b/doc/DwWidget.txt
new file mode 100644
index 00000000..fed0a3be
--- /dev/null
+++ b/doc/DwWidget.txt
@@ -0,0 +1,339 @@
+Jan 2001, S.Geerken@ping.de
+Last update: Dec 2004
+
+========
+DwWidget
+========
+
+The base object for all Dw widgets.
+
+
+Structures
+==========
+
+DwRectangle
+-----------
+A replacement for GdkRectangle, the only difference is the use of 32
+instead of 16 bit integers.
+
+
+DwAllocation, DwRequisition
+---------------------------
+Similar to GtkAllocation and GtkRequisition. Instead of a height, you
+have two members, ascent and descent.
+
+
+DwExtremes
+----------
+A structure containing the minimal and maximal width of a widget. See
+get_extremes below for details.
+
+
+DwWidget
+--------
+Some members you may use:
+
+ parent The parent widget. NULL for toplevel widgets.
+
+ flags See below.
+
+ style The style attached to the widget, this must
+ always be defined, but is not created
+ automatically. Instead, this has to be done
+ immediately after creating the widget
+ (e.g., in a_Web_dispatch_by_type). This style
+ contains attributes and resources for general
+ drawing. See DwStyle.txt for details.
+
+These members should only be used within the "core" (GtkDw*, DwWidget
+and DwEmbedGtk):
+
+ viewport The viewport containing the widget. Defined
+ for all widgets.
+
+ allocation,
+ requisition,
+ extremes,
+ user_requisition These are used to optimize several wrappers,
+ see below.
+
+ anchors_table See notes on achors.
+
+Flags
+-----
+Flags can be set and unset with DW_WIDGET_SET_FLAGS and
+DW_WIDGET_UNSET_FLAGS. For reading flags use the macros DW_WIDGET_...
+
+ DW_NEEDS_RESIZE
+ DW_EXTREMES_CHANGED Denotes that the widget must be resized. Used
+ only internally. See Dw.txt and the source
+ for more details.
+
+ DW_NEEDS_ALLOCATE Set to overide the optimation in
+ a_Dw_widget_size_allocate. Used only
+ internally.
+
+ DW_REALIZED Set when the widget is realized. Should be
+ used to prevent crashes in certain
+ situations.
+
+Following flags describe characteristics of widgets and are typically
+set in the init function:
+
+ DW_USES_HINTS A widget with this flag set has a complex way
+ to deal with sizes, and should
+
+ - implement the functions set_width,
+ set_ascent, set_descent, and
+ get_extremes, and
+ - deal completely with width and height
+ in widget->style.
+
+ Examples are DwPage and DwTable. Other
+ widgets, like DwImage and DwHRuler, are much
+ simpler and don't have to set this flag. For
+ these widgets, much of the size calculation
+ is done by the parent widget.
+
+ This flag is unset by default.
+
+ DW_HAS_CONTENT If this flag is set, more space is reserved
+ for the widget in some circumstances. E.g.,
+ if an image has a width of 100%, it makes
+ sense to use more space within a table cell,
+ as compared to a horizontal ruler, which does
+ not "have a content".
+
+ This flag is set by default.
+
+
+Signal Prototypes
+=================
+
+ - void size_request (DwWidget *widget,
+ DwRequisition *requisition);
+
+ Similar to Gtk.
+
+ void get_extremes (DwWidget *widget,
+ DwExtremes *extremes);
+
+ Return the maximal and minimal width of the widget, equivalent
+ to the requisition width after calling set_width with zero and
+ infinitive, respectively. This is important for fast table
+ rendering. Simple widgets do not have to implement this; the
+ default is the requisition width for both values.
+
+ - void size_allocate (DwWidget *widget,
+ DwAllocation *allocation);
+
+ Similar in Gtk. Note: allocation has world coordinates.
+
+ - void set_width (DwWidget *widget,
+ guint32 width);
+
+ - void set_height (DwWidget *widget,
+ guint32 height);
+
+ These are hints by the caller, which *may* influence the size
+ returned by size_request. The implementation should call
+ Dw_widget_queue_resize if necessary. In most cases, these
+ signals do not have to be implemented. Currently, only the
+ DwPage widget uses this to determine the width for rewrapping
+ text (note that the resulting width returned by
+ Dw_page_size_request may be _bigger_) and relative sizes of the
+ children.
+
+ - void draw (DwWidget *widget,
+ DwRectangle *area,
+ GdkEventExpose *event);
+
+ Draw the widget's content in the specified area. It may either
+ be caused by an expose event, or by an internal drawing request
+ (e.g., followed by resizing of widgets). In the first case, you
+ get the *original* expose event as third argument. In the
+ latter, event is NULL. The area argument has widget
+ coordinates. A DwContainer is responsible for drawing its
+ children.
+
+ (Since DwWidget's are always windowless, there was no need for
+ two signals, "draw" and "expose_event".)
+
+ - void realize (DwWidget *widget);
+
+ Create all necessary X resources. Called when either the
+ viewport (top-level widgets) or, respectively, the parent Dw
+ widget is realized, or an widget is added to an already
+ realized Dw widget/viewport.
+
+ - void unrealize (DwWidget *widget);
+
+ Remove created X resources.
+
+ - gint button_press_event (DwWidget *widget,
+ guint32 x,
+ guint32 y,
+ GdkEventButton *event);
+
+ This signal is emitted when the user presses a mouse button in
+ a DwWidget. x and y are the coordinates relative to the origin
+ of the widget, event is the *original* event, which may, e.g.,
+ be used to determine the number of the pressed button, the state
+ of the shift keys, etc. The implementation of this signal
+ should return TRUE, if the event has been processed, otherwise
+ FALSE.
+
+ A DwContainer is *not* responsible for delivering button press
+ events to its children. Instead, Dw first emits the
+ button_press_event signal for the most inner widgets and
+ continues this for the parents, until TRUE is returned.
+
+ - gint button_release_event (DwWidget *widget,
+ guint32 x,
+ guint32 y,
+ GdkEventButton *event);
+
+ Compare button_press_event.
+
+ - gint motion_notify_event (DwWidget *widget,
+ guint32 x,
+ guint32 y,
+ GdkEventMotion *event);
+
+ Compare button_press_event. event may be NULL when the call was
+ caused by something different than a "real" motion notify event.
+ E.g., either when widgets are moved (not yet implemented), or the
+ viewport.
+
+ - gint enter_notify_event (DwWidget *widget,
+ DwWidget *last_widget,
+ GdkEventMotion *event);
+
+ These "events" are simulated based on motion nofify events.
+ event is the *original* event (may also be NULL in some cases).
+ last_widget is the widget in which the pointer was in before.
+
+ - gint leave_notify_event (DwWidget *widget,
+ DwWidget *next_widget,
+ GdkEventMotion *event);
+
+ Compare enter_notify_event. next_widget is the widget the
+ pointer is now in.
+
+
+Useful Internal Functions and Macros
+====================================
+
+ - gint Dw_widget_intersect (DwWidget *widget,
+ DwRectangle *area,
+ DwRectangle *intersection);
+
+ Calculates the intersection of widget->allocation and area,
+ returned in intersection (in widget coordinates!). Typically
+ used by containers when drawing their children. Returns whether
+ intersection is not empty.
+
+ - gint32 Dw_widget_x_viewport_to_world (DwWidget *widget,
+ gint16 viewport_x);
+
+ - gint32 Dw_widget_y_viewport_to_world (DwWidget *widget,
+ gint16 viewport_y);
+
+ - gint16 Dw_widget_x_world_to_viewport (DwWidget *widget,
+ gint32 world_x);
+
+ - gint16 Dw_widget_y_world_to_viewport (DwWidget *widget,
+ gint32 world_y);
+
+ These functions convert between world and viewport coordinates.
+
+ - void Dw_widget_queue_draw (DwWidget *widget);
+
+ - void Dw_widget_queue_draw_area (DwWidget *widget,
+ gint32 x,
+ gint32 y,
+ guint32 width,
+ guint32 height);
+
+ - void Dw_widget_queue_clear (DwWidget *widget);
+
+ - void Dw_widget_queue_clear_area (DwWidget *widget,
+ gint32 x,
+ gint32 y,
+ guint32 width,
+ guint32 height);
+
+ Equivalents to the Gtk+ functions. They (currently) result in a
+ call of gtk_widget_xxx_area with the viewport as first
+ argument. x and y are widget coordinates.
+
+ - void Dw_widget_queue_resize (DwWidget *widget,
+ gint ref,
+ gboolean extremes_changed);
+
+ Similar to gtk_widget_queue_resize. Call this function when the
+ widget has changed its size. The next call to
+ Dw_xxx_size_request should then return the new size.
+
+ See Dw.txt for explanation on how to use the ref argument,
+ extremes_changed specifies whether the extremes have changed
+ (the latter is often not the case for an implementations of
+ set_{width|ascent|descent}).
+
+ - void Dw_widget_set_anchor (DwWidget *widget,
+ gchar *name,
+ int pos);
+
+ Add an anchor to a widget. The name will not be copied, it has
+ to be stored elsewhere (DwPage e.g. stores it in the DwPageWord
+ structure).
+
+ - void a_Dw_widget_set_cursor (DwWidget *widget,
+ GdkCursor *cursor)
+
+ Set the cursor for a DwWidget. cursor has to be stored
+ elsewhere, it is not copied (and not destroyed). If cursor is
+ NULL, the cursor of the parent widget is used.
+
+ (This will probably be changed in the future and replaced by a
+ common style mechanism.)
+
+ - DW_WIDGET_WINDOW (widget)
+
+ Returns the window a widget should draw into.
+
+
+External Functions
+==================
+
+ - void a_Dw_widget_set_usize (DwWidget *widget,
+ guint32 width,
+ guint32 ascent,
+ guint32 descent);
+
+ Override the "desired" size of a widget. Further calls of
+ a_Dw_widget_request_size will return these values, except those
+ specified as -1. A possible use shows Html_add_widget in
+ html.c.
+
+ (This will probably be removed. Instead DwStyle should be used.)
+
+
+ - void a_Dw_widget_set_bg_color (DwWidget *widget,
+ gint32 color);
+
+ Set the background color of a widget. This works currently only
+ for the top-level widget. In this case, the background color of
+ the GtkDwViewport is changed. In future, background colors for
+ all widgets will be needed, e.g., for table cells (will be
+ DwPage's), this will (probably) be based on filled rectangles.
+
+ - void a_Dw_widget_scroll_to (DwWidget *widget,
+ int pos)
+
+ Scroll viewport to pos (vertical widget coordinate).
+
+There are furthermore wrappers for the signals, in some cases they
+are optimized and/or provide further functionality. In (almost) no
+case should you emit the signals directly. See dw_widget.c for more
+details.
diff --git a/doc/HtmlParser.txt b/doc/HtmlParser.txt
new file mode 100644
index 00000000..ec64164d
--- /dev/null
+++ b/doc/HtmlParser.txt
@@ -0,0 +1,116 @@
+ October 2001, --Jcid
+ Last update: Dec 2004
+
+ ---------------
+ 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,
+ 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 gets
+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 '&lt;' and '&gt;' 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 significative amounts of
+ well written HTML).
+
+
+
+ * WORD --> Html_process_word
+
+ A word is anything that doesn't start with SPACE, and 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:
+
+ struct _DilloHtml {
+ [...]
+ DilloHtmlState *stack;
+ gint stack_top; /* Index to the top of the stack [0 based] */
+ gint stack_max;
+ [...]
+ };
+
+ struct _DilloHtmlState {
+ char *tag;
+ DwStyle *style, *table_cell_style;
+ DilloHtmlParseMode parse_mode;
+ DilloHtmlTableMode table_mode;
+ gint list_level;
+ gint list_number;
+ DwWidget *page, *table;
+ gint32 current_bg_color;
+ };
+
+
+ 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
new file mode 100644
index 00000000..fb691223
--- /dev/null
+++ b/doc/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 <jcid@dillo.org>
+ Horst H. von Brand <vonbrand@inf.utfsm.cl>
+
+
+--------
+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
+<http://www.dillo.org>. 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
new file mode 100644
index 00000000..1f70b0ca
--- /dev/null
+++ b/doc/Images.txt
@@ -0,0 +1,114 @@
+ February 2001, --Jcid
+
+ ------
+ 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 by GdkRGB in a streamed
+way.
+ Note that INDEXED images are also decoded into RGB format.
+
+
+---------------------
+Fetching from the net
+---------------------
+
+* a_Cache_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_image, a_Jpeg_image and a_Png_image.
+
+* 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_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_close
+
+* The functions in image.c make the required a_Dw_image_...
+calls.
+
+
+-------------------------
+Fetching from the dicache
+-------------------------
+
+* a_Cache_open_url tests the cache for the image, and directly
+enqueues a cache client for it, without asking the network for
+the data. When the client queue is processed (a bit later), the
+decoder is selected based on the cache entry Type.
+
+* When the decoder is called, it tests the dicache for the image;
+if the image is found, then it sets a_Dicache_callback as the
+handling function and gets out of the way (no image decoding is
+needed).
+
+* Later on, the DwImage buffer is set to reference the
+dicache-entry's buffer and the rest of the functions calls is
+driven by a_Dicache_callback.
+
+
+-----------
+Misc. notes
+-----------
+
+* Repeated images generate new cache clients, but only one of
+them (the first) is handled with a_Dicache_* functions, the rest
+is done with a_Dicache_callback..
+
+* The cache-client callback is set when the Content-type of the
+image is got. It can be: a_Png_image, a_Gif_image or a_Jpeg_image
+Those are called 'decoders' because their main function is to
+translate the original data into RGB format.
+
+* Later on, the decoder can substitute itself, if it finds the
+image has been already decoded, with a_Dicache_callback function.
+This avoids decoding it twice.
+
+* The dicache-entry and the Image structure hold bit arrays that
+represent which rows had been decoded.
+
+* The image processing can be found in the following sources:
+
+ - image.[ch]
+ - dicache.[ch]
+ - gif.[ch], png.[ch], jpeg.[ch]
+ - dw_image.[ch]
+
+* Bear in mind that there are three data structures for image
+code:
+
+ - DilloImage (image.h)
+ - DwImage (dw_image.h)
+ - DICacheEntry (dicache.h)
+
+
diff --git a/doc/Imgbuf.txt b/doc/Imgbuf.txt
new file mode 100644
index 00000000..1039ff9e
--- /dev/null
+++ b/doc/Imgbuf.txt
@@ -0,0 +1,177 @@
+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
new file mode 100644
index 00000000..9142fa3a
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,19 @@
+EXTRA_DIST = \
+ Cache.txt \
+ Cookies.txt \
+ Dillo.txt \
+ Dw.txt \
+ DwImage.txt \
+ DwPage.txt \
+ DwRender.txt \
+ DwStyle.txt \
+ DwTable.txt \
+ DwWidget.txt \
+ HtmlParser.txt \
+ IO.txt \
+ Images.txt \
+ Imgbuf.txt \
+ NC_design.txt \
+ Selection.txt \
+ Dpid.txt \
+ README
diff --git a/doc/NC_design.txt b/doc/NC_design.txt
new file mode 100644
index 00000000..6932b9cf
--- /dev/null
+++ b/doc/NC_design.txt
@@ -0,0 +1,80 @@
+
+ _________________________________________________________________
+
+ Naming&Coding design
+ _________________________________________________________________
+
+ Dillo's code is divided into modules. For instance: bookmark, cache,
+ dicache, gif.
+
+ Lets 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 it reads better "a_Menu_create" than "d_Menu_create" cause 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).
+
+ Function commenting:
+
+ Every single function of the module should start with a short comment
+ that explains it's 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: and todo: 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;
+ _________________________________________________________________
+
+ 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 for identifying 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
new file mode 100644
index 00000000..3530292d
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,53 @@
+README: Last update Oct 2007 --jcid
+
+ This documents need a review. They were current with dillo1 and
+now, with dillo2, most of them are obsolete, specially Dw*txt, but
+Dw2 is fully documented in html using doxygen.
+
+ The other documents will be reviewed when I have some time. 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 these as doxygen files too!
+If somebody wants to make this convertion, 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
+ DwRendering.txt Dw Rendering Abstraction Current
+ DwWidget.txt The base object of Dw Current
+ DwImage.txt Dillo Widget image handling Incomplete
+ DwPage.txt Dillo Widget page (shortly) Incomplete
+ DwStyle.txt Styles of Dillo Widgets Pending
+ DwTable.txt Tables in dillo 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
+ --------------------------------------------------------------------------
+ [This documents cover dillo's internal working. They're NOT a user manual]
+ --------------------------------------------------------------------------
+
+
+ * Ah!, 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 'diff -pru'.
+
+
+ Happy coding!
+ --Jcid
diff --git a/doc/Selection.txt b/doc/Selection.txt
new file mode 100644
index 00000000..08fe0abc
--- /dev/null
+++ b/doc/Selection.txt
@@ -0,0 +1,149 @@
+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).