aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rw-r--r--.rtfl12
-rw-r--r--ChangeLog9
-rw-r--r--configure.ac4
-rw-r--r--devdoc/dw-fixed-positions.doc63
-rw-r--r--devdoc/dw-grows.doc6
-rw-r--r--devdoc/dw-interrupted-drawing-1.pngbin0 -> 7142 bytes
-rw-r--r--devdoc/dw-interrupted-drawing-2.pngbin0 -> 42606 bytes
-rw-r--r--devdoc/dw-interrupted-drawing-2.svg706
-rw-r--r--devdoc/dw-interrupted-drawing.doc121
-rw-r--r--devdoc/dw-miscellaneous.doc187
-rw-r--r--devdoc/dw-out-of-flow.doc82
-rw-r--r--devdoc/dw-size-request-pos-01.html35
-rw-r--r--devdoc/dw-size-request-pos-01.pngbin0 -> 31630 bytes
-rw-r--r--devdoc/dw-size-request-pos.doc144
-rw-r--r--devdoc/dw-stacking-context.doc114
-rw-r--r--devdoc/dw-widget-sizes.doc18
-rw-r--r--dw/Makefile.am19
-rw-r--r--dw/alignedtablecell.cc17
-rw-r--r--dw/alignedtablecell.hh2
-rw-r--r--dw/bullet.cc7
-rw-r--r--dw/bullet.hh7
-rw-r--r--dw/core.hh2
-rw-r--r--dw/fltkui.cc9
-rw-r--r--dw/fltkui.hh6
-rw-r--r--dw/image.cc38
-rw-r--r--dw/image.hh9
-rw-r--r--dw/iterator.cc8
-rw-r--r--dw/iterator.hh2
-rw-r--r--dw/layout.cc42
-rw-r--r--dw/layout.hh7
-rw-r--r--dw/oofawarewidget.cc592
-rw-r--r--dw/oofawarewidget.hh264
-rw-r--r--dw/oofawarewidget_iterator.cc261
-rw-r--r--dw/ooffloatsmgr.cc2370
-rw-r--r--dw/ooffloatsmgr.hh406
-rw-r--r--dw/oofposabslikemgr.cc427
-rw-r--r--dw/oofposabslikemgr.hh61
-rw-r--r--dw/oofposabsmgr.cc68
-rw-r--r--dw/oofposabsmgr.hh27
-rw-r--r--dw/oofposfixedmgr.cc59
-rw-r--r--dw/oofposfixedmgr.hh27
-rw-r--r--dw/oofpositionedmgr.cc396
-rw-r--r--dw/oofpositionedmgr.hh143
-rw-r--r--dw/oofposrelmgr.cc249
-rw-r--r--dw/oofposrelmgr.hh50
-rw-r--r--dw/outofflowmgr.cc2261
-rw-r--r--dw/outofflowmgr.hh512
-rw-r--r--dw/regardingborder.hh7
-rw-r--r--dw/ruler.cc16
-rw-r--r--dw/ruler.hh12
-rw-r--r--dw/selection.cc102
-rw-r--r--dw/simpletablecell.cc13
-rw-r--r--dw/simpletablecell.hh2
-rw-r--r--dw/stackingcontextmgr.cc195
-rw-r--r--dw/stackingcontextmgr.hh75
-rw-r--r--dw/style.cc4
-rw-r--r--dw/style.hh14
-rw-r--r--dw/table.cc193
-rw-r--r--dw/table.hh25
-rw-r--r--dw/table_iterator.cc115
-rw-r--r--dw/tablecell.cc4
-rw-r--r--dw/tablecell.hh2
-rw-r--r--dw/textblock.cc806
-rw-r--r--dw/textblock.hh154
-rw-r--r--dw/textblock_iterator.cc249
-rw-r--r--dw/textblock_linebreaking.cc350
-rw-r--r--dw/tools.cc132
-rw-r--r--dw/tools.hh56
-rw-r--r--dw/types.hh65
-rw-r--r--dw/ui.cc12
-rw-r--r--dw/ui.hh8
-rw-r--r--dw/widget.cc326
-rw-r--r--dw/widget.hh101
-rw-r--r--lout/debug.hh354
-rw-r--r--lout/debug_rtfl.hh410
-rw-r--r--lout/misc.hh6
-rw-r--r--src/cssparser.cc28
-rw-r--r--src/dillo.cc14
-rw-r--r--src/html.cc6
-rw-r--r--src/styleengine.cc6
-rw-r--r--test/Makefile.am4
-rw-r--r--test/dw_simple_container.cc15
-rw-r--r--test/dw_simple_container.hh7
-rw-r--r--test/identity.cc55
85 files changed, 9579 insertions, 4214 deletions
diff --git a/.hgignore b/.hgignore
index f3e9fd41..4d2c186c 100644
--- a/.hgignore
+++ b/.hgignore
@@ -41,6 +41,7 @@
^test/dw-table$
^test/dw-table-aligned$
^test/dw-ui-test$
+^test/identity$
^test/liang$
^test/notsosimplevector$
^test/shapes$
diff --git a/.rtfl b/.rtfl
new file mode 100644
index 00000000..3ac79d33
--- /dev/null
+++ b/.rtfl
@@ -0,0 +1,12 @@
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:*:#c0ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:fltk\:\:*:#c0c0ff
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:core\:\:*:#ffa0a0
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:core\:\:style\:\:*:#ffe0a0
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:core\:\:SizeParams:#e0e0a0
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:Image:#80ffa0
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:Textblock:#f0ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:OutOfFlowMgr:#d0ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:AlignedTextblock:#e0ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:ListItem:#b0ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:TableCell:#80ff80
+[rtfl-obj-1.0]:0:0:class-color:dw\:\:Table:#80ffc0
diff --git a/ChangeLog b/ChangeLog
index 7d19c82e..a7fada22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,15 @@ Here we list changes that are relatively significant and/or visible to the
user. For a history of changes in full detail, see our Mercurial repository
at http://hg.dillo.org/dillo
+dillo_grows repository [to be merged]
+
++- Absolutely and relatively positioned elements.
+ - Fixedly positioned elements (incomplete: referring to the canvas instead to
+ the viewport).
+ - "Z-index", stacking contexts.
+ Patches: Sebastian Geerken
+
+-----------------------------------------------------------------------------
dillo-3.1 [not released yet]
diff --git a/configure.ac b/configure.ac
index be9c9c42..63f0f40e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,8 @@
dnl Process this file with aclocal, autoconf and automake.
-AC_INIT([dillo], [3.1-dev])
+# "grows2" (for second phase of GROWS) to distinguish this version
+# from version 3.1-dev. Remember to remove this again after merging.
+AC_INIT([dillo], [3.1-dev_grows2])
dnl Detect the canonical target build environment
AC_CANONICAL_TARGET
diff --git a/devdoc/dw-fixed-positions.doc b/devdoc/dw-fixed-positions.doc
new file mode 100644
index 00000000..d62565ff
--- /dev/null
+++ b/devdoc/dw-fixed-positions.doc
@@ -0,0 +1,63 @@
+/** \page dw-fixed-positions Fixed positions
+
+In some cases, widgets or widget content must be positioned relative
+to the viewport. As in the CSS specification, these positions will be
+called "fixed positions". This must not be confused with "fixedly
+positioned elements" (see \ref dw-out-of-flow), which are a special
+case of fixed positions.
+
+
+Applications
+============
+
+As defined by CSS
+-----------------
+
+- "position: fixed"; see \ref dw-out-of-flow.
+- "background-attachment: fixed"; see \ref dw-images-and-backgrounds.
+
+Idea for tables
+---------------
+
+Often, tables have a header, which contains informations necessary to
+interpret the columns in the table body. For this, HTML defines the elements
+<thead> and <tbody>
+<sup><a href="#note-table-footer" id="ref-table-footer">[1]</a></sup>.
+
+For large tables, the problem occurs that the table header gets out of
+the reader's view. In paged media, where a large table covers multiple
+pages, this is often solved by *repeating* the table header on each
+page occupied by the table. When using a viewport, a table larger than
+the vieport could be displayed like this:
+
+1. If the top of the table is within the viewport, show the table
+ header at the usual position.
+2. As soon as top of the table gets above the top border of the
+ viewport, keep the table header at the viewport top, so that it is
+ still visible (this means, it moves down, relative to the
+ *canvas*). This way, the header is still visible, so our objective
+ is achieved.
+3. When scrolling further down, at some point the table body gets out
+ of the viewport again, and so should the table header.
+
+(Some images would be nice.)
+
+These ideas should be considered when developing a design for fixed
+positions.
+
+
+Design sketch
+==============
+
+[...]
+
+
+----------------------------------------------------------------------
+
+<sup><a href="#ref-table-footer" id="note-table-footer">[1]</a></sup>
+... and also &lt;tfoot&gt;, which is not discussed here, for reasons
+of simplicity. However, it is obvious that &lt;tfoot&gt; should be
+dealt with in an analogue way as &lt;thead&gt;.
+
+
+*/ \ No newline at end of file
diff --git a/devdoc/dw-grows.doc b/devdoc/dw-grows.doc
index a0304ef9..c255419f 100644
--- a/devdoc/dw-grows.doc
+++ b/devdoc/dw-grows.doc
@@ -1,5 +1,11 @@
/** \page dw-grows GROWS - Grand Redesign Of Widget Sizes
+<div style="border: 2px solid #ffff00; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #ffffe0">The complex "widget
+ sizes" is currently divided into three documents: \ref
+ dw-widget-sizes, **Grand Redesign Of Widget Sizes** (this document),
+ and \ref dw-size-request-pos. </div>
+
This paper describes (will describe) some design changes to
calculating widget sizes. Goals are:
diff --git a/devdoc/dw-interrupted-drawing-1.png b/devdoc/dw-interrupted-drawing-1.png
new file mode 100644
index 00000000..58289490
--- /dev/null
+++ b/devdoc/dw-interrupted-drawing-1.png
Binary files differ
diff --git a/devdoc/dw-interrupted-drawing-2.png b/devdoc/dw-interrupted-drawing-2.png
new file mode 100644
index 00000000..8ec54035
--- /dev/null
+++ b/devdoc/dw-interrupted-drawing-2.png
Binary files differ
diff --git a/devdoc/dw-interrupted-drawing-2.svg b/devdoc/dw-interrupted-drawing-2.svg
new file mode 100644
index 00000000..6dbc6aca
--- /dev/null
+++ b/devdoc/dw-interrupted-drawing-2.svg
@@ -0,0 +1,706 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="210mm"
+ height="297mm"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="dw-interrupted-drawing-2.svg"
+ inkscape:export-filename="/home/sg/dev/dillo/dillo-grows-work-intdraw/doc/dw-interrupted-drawing-2.png"
+ inkscape:export-xdpi="69.620003"
+ inkscape:export-ydpi="69.620003">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path4042"
+ style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-2"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-4"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-8"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-0"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-24"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-2"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-29"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-1"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-5"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-41"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-23"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-19"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-7"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-9"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-0"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-97"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-0-4"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-97-1"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-0-7"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-97-5"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-0-8"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-97-8"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-0-3"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-97-2"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-1"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4042-7"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker5604"
+ style="overflow:visible">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5606"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.35355339"
+ inkscape:cx="437.30872"
+ inkscape:cy="337.60168"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1600"
+ inkscape:window-height="900"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2985" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g3977"
+ transform="translate(2.992126e-6,177.16535)">
+ <rect
+ y="24.803127"
+ x="17.716536"
+ height="70.866142"
+ width="141.73228"
+ id="rect2997"
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <flowRoot
+ transform="translate(20.094709,-2.1798012)"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ id="flowRoot3786"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3788"><rect
+ y="48.270561"
+ x="46.467018"
+ height="28.284271"
+ width="75.256363"
+ id="rect3790" /></flowRegion><flowPara
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="flowPara3792">body</flowPara></flowRoot> </g>
+ <g
+ id="g3984"
+ transform="translate(2.992126e-6,177.16535)">
+ <rect
+ y="24.803127"
+ x="194.8819"
+ height="70.866142"
+ width="141.73228"
+ id="rect3767"
+ style="fill:#ffe0e0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3832"
+ y="67.096199"
+ x="243.2318"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="67.096199"
+ x="243.2318"
+ id="tspan3834"
+ sodipodi:role="line">#sc-1</tspan></text>
+ </g>
+ <g
+ id="g3989"
+ transform="translate(176.96508,177.13197)">
+ <rect
+ y="24.803127"
+ x="372.04724"
+ height="70.866142"
+ width="141.73228"
+ id="rect3767-6"
+ style="fill:#b0ffb0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3836"
+ y="67.356201"
+ x="425.39713"
+ style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="67.356201"
+ x="425.39713"
+ id="tspan3838"
+ sodipodi:role="line"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L">#fl-1</tspan></text>
+ </g>
+ <g
+ id="g3994"
+ transform="translate(-177.81225,177.39197)">
+ <rect
+ y="24.803127"
+ x="549.21259"
+ height="70.866142"
+ width="141.73228"
+ id="rect3767-2"
+ style="fill:#f0f0ff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3840"
+ y="67.096199"
+ x="595.92249"
+ style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="67.096199"
+ x="595.92249"
+ id="tspan3842"
+ sodipodi:role="line"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L">#sc-2</tspan></text>
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 88.582679,272.83462 -2e-6,531.49607"
+ id="path3890"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 265.74803,272.83462 0,531.49607"
+ id="path3890-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 442.91339,272.83462 0,531.49607"
+ id="path3890-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 620.07874,272.83462 0,531.49607"
+ id="path3890-29"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:#ffffa0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3931"
+ width="35.433071"
+ height="460.62991"
+ x="70.866142"
+ y="308.2677" />
+ <rect
+ style="fill:#ffffa0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect3933"
+ width="35.433071"
+ height="354.33069"
+ x="248.03149"
+ y="343.70078" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3935"
+ style="font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ transform="translate(2.992126e-6,177.16535)"><flowRegion
+ id="flowRegion3937"><rect
+ id="rect3939"
+ width="835.71429"
+ height="147.14285"
+ x="-1.4285715"
+ y="-40.494953" /></flowRegion><flowPara
+ id="flowPara3941"></flowPara></flowRoot> <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+ d="m 106.29921,343.70076 141.73229,0"
+ id="path3890-29-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:#ffffa0;fill-opacity:1;stroke:#000000;stroke-width:3.00000191;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect4643"
+ width="35.433094"
+ height="70.866158"
+ x="602.36218"
+ y="414.56689" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+ d="m 283.46457,414.56691 318.89763,0"
+ id="path3890-29-5-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 6;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)"
+ d="m 602.36221,485.43305 -318.89764,0"
+ id="path3890-29-5-2-0-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 6;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)"
+ d="m 248.0315,698.03147 -141.73229,0"
+ id="path3890-29-5-2-0-0-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:#ffffa0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect4767"
+ width="35.433071"
+ height="35.433071"
+ x="602.36218"
+ y="733.46454" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+ d="m 106.29921,733.46454 496.06299,10e-6"
+ id="path3890-29-5-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+ d="m 17.716536,308.26769 53.149608,0"
+ id="path3890-29-5-27"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 6;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)"
+ d="m 70.866142,768.89762 -53.149613,0"
+ id="path3890-29-5-2-0-0-8-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 354.33071,715.74801 318.89763,53.14961 0,0 0,0 0,0"
+ id="path4865"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 354.3307,768.89762 318.89764,-53.14961 0,0 0,0"
+ id="path4865-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend-0)"
+ d="m 88.582677,201.96848 c 17.716533,-88.58268 141.732283,-88.58268 159.448823,0"
+ id="path4914"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend-0)"
+ d="m 283.46456,201.96848 c 17.71654,-88.58268 141.73229,-88.58268 159.44883,0"
+ id="path4914-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend-0)"
+ d="m 88.582677,201.96848 c 35.433073,-212.598421 513.779523,-212.598423 549.212603,0"
+ id="path4914-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0;marker-end:url(#Arrow2Lend-0)"
+ d="m 265.74802,201.96848 c 35.43308,-159.448817 301.18111,-159.448817 336.61418,0"
+ id="path4914-8-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:2,4;stroke-dashoffset:0"
+ d="m 318.89764,361.4173 c -17.71654,0 -35.43307,0 -35.43307,0 l 0,0"
+ id="path5443"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Nimbus Mono L;-inkscape-font-specification:Nimbus Mono L"
+ x="414.18863"
+ y="362.88965"
+ id="text5445"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan5447"
+ x="414.18863"
+ y="362.88965" /></text>
+ <g
+ id="g5586">
+ <rect
+ rx="0"
+ ry="17.716547"
+ y="325.98422"
+ x="318.89764"
+ height="70.866142"
+ width="194.8819"
+ id="rect5453"
+ style="fill:#ffffe0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5455"
+ y="354.7933"
+ x="418.09937"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Nimbus Mono L;-inkscape-font-specification:Nimbus Mono L"
+ xml:space="preserve"><tspan
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="354.7933"
+ x="418.09937"
+ id="tspan5457"
+ sodipodi:role="line">#sc-1 detects that #fl-1</tspan><tspan
+ id="tspan5459"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="377.2933"
+ x="418.09937"
+ sodipodi:role="line">interrupts the drawing</tspan></text>
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0"
+ d="m 673.22836,450.00001 c -17.71654,0 -35.43307,0 -35.43307,0 l 0,0"
+ id="path5443-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <g
+ id="g5531"
+ transform="translate(-88.582663,106.29923)">
+ <rect
+ rx="0"
+ ry="17.716547"
+ y="414.56689"
+ x="673.22833"
+ height="70.866142"
+ width="194.8819"
+ id="rect5453-7"
+ style="fill:#ffffe0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5455-9"
+ y="443.37598"
+ x="770.91229"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Nimbus Mono L;-inkscape-font-specification:Nimbus Mono L"
+ xml:space="preserve"><tspan
+ id="tspan5517"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="443.37598"
+ x="770.91229"
+ sodipodi:role="line">#fl-1 is drawn as</tspan><tspan
+ id="tspan5521"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="465.87598"
+ x="770.91229"
+ sodipodi:role="line">an interruption</tspan></text>
+ </g>
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot5523"
+ style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Nimbus Mono L;font-style:normal;font-weight:normal;font-size:20px;line-height:125%;letter-spacing:0px;word-spacing:0px;-inkscape-font-specification:Nimbus Mono L;font-stretch:normal;font-variant:normal"><flowRegion
+ id="flowRegion5525"><rect
+ id="rect5527"
+ width="230.37166"
+ height="100.60158"
+ x="662.54175"
+ y="400.53543" /></flowRegion><flowPara
+ id="flowPara5529"></flowPara></flowRoot> <g
+ id="g5699">
+ <rect
+ rx="0"
+ ry="17.716547"
+ y="502.68695"
+ x="318.90851"
+ height="70.866142"
+ width="194.8819"
+ id="rect5453-70"
+ style="fill:#ffffe0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5455-7"
+ y="531.49603"
+ x="418.11023"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Nimbus Mono L;-inkscape-font-specification:Nimbus Mono L"
+ xml:space="preserve"><tspan
+ id="tspan5459-7"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="531.49603"
+ x="418.11023"
+ sodipodi:role="line">drawing of #sc-1</tspan><tspan
+ id="tspan5584"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="553.99603"
+ x="418.11023"
+ sodipodi:role="line">is continued</tspan></text>
+ </g>
+ <rect
+ style="fill:#ffffa0;fill-opacity:1;stroke:#000000;stroke-width:3.00000191;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect4643-9"
+ width="35.433094"
+ height="70.866158"
+ x="425.19681"
+ y="591.73224" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Lend)"
+ d="m 283.46457,591.73226 141.73227,10e-6"
+ id="path3890-29-5-2-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 6;stroke-dashoffset:0;marker-end:url(#Arrow2Lend)"
+ d="m 425.19685,662.59841 -141.73228,-10e-6"
+ id="path3890-29-5-2-0-0-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0"
+ d="m 673.22835,751.18108 c -17.71654,0 -35.43307,0 -35.43307,0 l 0,0"
+ id="path5443-8-2"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g5713"
+ transform="translate(-88.571786,105.83661)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5443-8"
+ d="m 726.37796,786.61415 c -17.71654,0 -35.43307,0 -35.43307,0 l 0,0"
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0" />
+ <rect
+ rx="0"
+ ry="17.716547"
+ y="715.74799"
+ x="673.22833"
+ height="70.866142"
+ width="194.8819"
+ id="rect5453-70-2"
+ style="fill:#ffffe0;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text5455-7-4"
+ y="744.55707"
+ x="772.43005"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Nimbus Mono L;-inkscape-font-specification:Nimbus Mono L"
+ xml:space="preserve"><tspan
+ id="tspan5707"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="744.55707"
+ x="772.43005"
+ sodipodi:role="line">no need anymore</tspan><tspan
+ id="tspan5711"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ y="767.05707"
+ x="772.43005"
+ sodipodi:role="line">to draw #fl-1</tspan></text>
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0"
+ d="m 318.89764,538.58266 c -17.71654,0 -35.43307,0 -35.43307,0 l 0,0"
+ id="path5443-9-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0"
+ d="m 673.22835,449.99998 0,0"
+ id="path5443-9-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:2,4;stroke-dashoffset:0"
+ d="m 673.22835,520.86612 c 0,-70.86614 0,-70.86614 0,-70.86614"
+ id="path5738"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0"
+ d="m 673.22835,822.04722 c 0,-70.86614 0,-70.86614 0,-70.86614"
+ id="path5738-7"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/devdoc/dw-interrupted-drawing.doc b/devdoc/dw-interrupted-drawing.doc
new file mode 100644
index 00000000..c7037666
--- /dev/null
+++ b/devdoc/dw-interrupted-drawing.doc
@@ -0,0 +1,121 @@
+/** \page dw-interrupted-drawing Interrupted drawing
+
+Describing the problem
+======================
+
+Without interrupting drawing (which is described below), a widget can
+define the order in which its parts (background, non-widget content,
+child widgets, etc.) are drawn, but it must be drawn as a whole. There
+are situations when this is not possible.
+
+Consider the following simple HTML document:
+
+ <head>
+ <style>
+ #sc-1 { position: relative; z-index: 1; background: #ffe0e0; }
+ #fl-1 { float: right; background: #b0ffb0; }
+ #sc-2 { position: relative; z-index: 1; background: #f0f0ff; }
+ </style>
+ </head>
+ <body>
+ <div id="sc-1">
+ <div id="fl-1">
+ Float, line 1/3<br/>
+ Float, line 2/3<br/>
+ Float, line 3/3
+ </div>
+ Stacking Context 1
+ <div id="sc-2">Stacking Context 2</div>
+ </div>
+ </body>
+
+The rendering will look like this:
+
+\image html dw-interrupted-drawing-1.png
+
+Note the missing "Float, line 2/3" of element #fl-1, which is covered
+by element #sc-2.
+
+As described in \ref dw-out-of-flow, it has to be distinguished
+between the *container* hierarchy (equivalent to the hierarchy of
+dw::core::Widget.) and the the *generator* hierarchy. In the following
+diagram, the former is represented by solid lines, the latter by
+dotted lines:
+
+\dot
+digraph G {
+ node [shape=rect, fontname=Helvetica, fontsize=10];
+ edge [arrowhead="vee"];
+
+ "#sc-1" [fillcolor="#ffe0e0", style="filled"];
+ "#fl-1" [fillcolor="#b0ffb0", style="filled"];
+ "#sc-2" [fillcolor="#f0f0ff", style="filled"];
+
+ "body" -> "#sc-1";
+ "body" -> "#fl-1";
+ { rank=same; "#sc-1" -> "#fl-1" [style=dotted]; }
+ "#sc-1" -> "#sc-2";
+}
+\enddot
+
+
+The drawing order of the four elements (represented by widgets) is:
+
+- body,
+- #sc-1,
+- #fl-1,
+- #sc-2.
+
+Since
+
+1. #sc-2 is a child of #sc-1, but
+2. #fl-1 is a child of the body, and
+3. a widget can only draw its descendants (not neccessary children,
+ but drawing siblings is not allowed),
+
+#sc-1 cannot be drawn as a whole; instead drawing is **interrupted**
+by #fl-1. This means:
+
+1. the background and text of #sc-1 is drawn;
+2. drawing of #sc-1 is **interrupted** by #fl-1 (see below for details),
+3. drawing of #sc-1 is **continued**, by drawing #sc-2.
+
+The exact control flow is described in this sequence diagram:
+
+\image html dw-interrupted-drawing-2.png
+
+
+When is drawing interrupted?
+============================
+
+A widget out of flow is regarded as part of the stacking context (see
+\ref dw-stacking-context) of its *generator* (in the example above:
+#fl-1 is part of the stacking context stablished by #sc-1, not the one
+established by body). For this reason, a widget out of flow must, in
+some cases, drawn while the *gerator* is drawn, as an
+interruption. The exact rule:
+
+A widget out of flow must be drawn as an interruption (while the
+*generator* is drawn) if the stacking context of the generator (to
+which this widget belongs) is in front of the stacking context of the
+container (the parent widget).
+
+See dw::oof::OOFAwareWidget::doesWidgetOOFInterruptDrawing.
+
+
+How does interruption of drawing work?
+======================================
+
+When a widget detects that an other widget should be drawn as
+interruption (see above), it calls dw::core::Widget::drawInterruption,
+which
+
+1. draws the widget within another "context" (area and reference
+ widget); for this the original drawing area
+ (dw::core::DrawingContext::getToplevelArea) is used.
+2. Using dw::core::DrawingContext::addWidgetDrawnAsInterruption, and
+ checking later with
+ dw::core::DrawingContext::hasWidgetBeenDrawnAsInterruption prevents
+ these widgets from being drawn twice.
+
+*/
diff --git a/devdoc/dw-miscellaneous.doc b/devdoc/dw-miscellaneous.doc
new file mode 100644
index 00000000..d6b3cae3
--- /dev/null
+++ b/devdoc/dw-miscellaneous.doc
@@ -0,0 +1,187 @@
+/** \page dw-miscellaneous Miscellaneous Notes on Dw
+
+This is a barely sorted list of issues which I consider noteworthy,
+but have yet to be moved to other parts of the documentation (which is
+partly to be created).
+
+General
+=======
+
+Widget allocation outside of parent allocation
+----------------------------------------------
+A widget allocation outside of the allocation of the parent is
+allowed, but the part outside is not visible.
+
+Which widgets may be drawn?
+-------------------
+
+All drawing starts with the toplevel widget
+(cf. dw::core::Widget::queueDrawArea, dw::core::Layout::queueDraw, and
+dw::core::Layout::expose), and a widget has to draw its children, in a
+way consistent with their stacking order.
+
+There are two exceptions:
+
+1. Direct descendants, which are not children, may be drawn, if the
+ parent can distinguish them and so omit drawing them a second
+ time. See dw::core::StackingContextMgr and \ref dw-stacking-context.
+ Parents should not draw children in flow for which
+ dw::core::StackingContextMgr::handledByStackingContextMgr returns
+ true.
+2. Interrupted drawing: via dw::core::Widget::drawInterruption; see
+ \ref dw-interrupted-drawing.
+
+Similar rules apply to handling mouse events
+(dw::core::Widget::getWidgetAtPoint).
+
+Interrupted drawing
+-------------------
+→ \ref dw-interrupted-drawing.
+
+Similar rules apply to handling mouse events
+(dw::core::Widget::getWidgetAtPoint).
+
+
+Floats
+======
+
+Handling collisions
+-------------------
+The CSS specification allows two strategies to deal with colliding
+floats: placing the second float beside or below the first one. Many
+other browsers implement the first approach, while dillo implements
+the second one, which may cause problems when the author assumes the
+first. Example: the "tabs" at the top of every page at Wikipedia
+("Article", "Talk", ...).
+
+Float containers in flow
+------------------------
+Consider the following HTML snippet:
+
+ <body>
+ <img src="....jpg" style="float:right">
+ <p style="overflow:hidden">Text</p>
+ </body>
+
+Interestingly, dillo shows "Text" always *below* the image, even if
+there is enough space left of it. An investigation shows that the
+paragraph (&lt;p&gt;) is regarded as own floats container (because of
+*overflow:hidden*), so the floats container above (&lt;body&gt;)
+regards this block as widget which must be fit between the floats
+(dw::Textblock::mustBorderBeRegarded &gt;
+dw::Textblock::getWidgetRegardingBorderForLine). However, since a
+textblock in flow always covers (at least) the whole available width,
+which is defined *without* considering floats, the space left of the
+float will always be to narrow, so that the paragraph is moved below
+the float, by inserting an empty line before.
+
+When searching for a solution, several difficulties show up:
+
+1. The available width, which is used for the width of the textblock,
+ is defined independent of floats. Aside from problems when changing
+ this definition, a dependance on floats would be difficult to
+ implement, since *sizeRequest* is independent of a position. (See
+ also \ref dw-out-of-flow.)
+2. I must admit that I do not rembember the exact rationale and the
+ test case behind adding the exception in
+ dw::Textblock::getWidgetRegardingBorderForLine (see above), but
+ simply removing this exception will result in a possible
+ overlapping of floats from both containers, since no collisions are
+ tested for.
+3. On the other hand, mixing the float containers (interaction of two
+ or more instances of dw::oof::OOFFloatsMgr), e.&nbsp;g. for
+ collision tests, would become too complex and possibly result in
+ performance problems.
+
+Instead, this approach is focussed:
+
+- Goal: the paragraph is narrowed so it fits, *as a whole*, between
+ the floats.
+- The approach is to remove the exception in
+ dw::Textblock::getWidgetRegardingBorderForLine. A textblock, which
+ is a float container in flow (as this paragraph), is returned by
+ this method and so dw::Textblock::mustBorderBeRegarded returns
+ *true*. This will put this paragraph again at the correct position.
+- To avoid overlappings, the linebreaking width of this paragraph
+ (which is also used for positioning of floats) is the available
+ width, minus the maximal float width on either side. (This is an
+ approach similar to the one dw::Ruler will use soon). Most likely,
+ some new methods will have to be added to calculate this.
+- For paragraphs like this, dw::Textblock::borderChanged must rewrap
+ all lines; *y* is irrelevant in this case.
+- Since the textblock will tend to become taller when getting
+ narrower, and so possibly cover more (wider) floats, and so become
+ narrower again etc., there may be multible solutions for calculating
+ the size. Generally, a smaller height (and so larger width) is
+ preferred.
+- There remains a problem: what if a word is too large? Should a
+ textblock of this kind then reard the floats in detail, to insert
+ empty lines when needed?
+
+**Real-world cases:** *Overflow:hidden* is set for headings in
+Wikipedia, and so this case occurs when there is a float (thumb image)
+before a heading. See e.&nbsp;g.
+<a href="http://de.wikipedia.org/wiki/Emmerich_am_Rhein#Ans.C3.A4ssige_Unternehmen">this page</a>
+and scroll a bit up; the company logos should be right of this section.
+
+**Priority:** Since this is not a regression, compared to not
+supporting floats at all, a fix is not urgent for a new release.
+
+Positioned elements
+===================
+
+General
+-------
+(See also *relative positions* below.)
+
+What about negative positions?
+
+dw::oof::OutOfFlowMgr::tellPosition1 and
+dw::oof::OutOfFlowMgr::tellPosition2 could be combined again, and
+called in the respective circumstance, depending on
+dw::oof::OutOfFlowMgr::mayAffectBordersAtAll.
+
+Relative positions
+------------------
+**General Overview:** At the original position, a space as large as
+the positioned element is left. This is implemented by assigning a
+size to the widget *reference*. For this there are two new methods:
+dw::oof::OutOfFlowMgr::calcWidgetRefSize and
+dw::oof::OOFAwareWidget::widgetRefSizeChanged.
+
+**Bug:** Since the size of a relatively positioned element should be
+calculated as if it was in flow, the available width should be
+delegated to the *generator*; however, since
+dw::oof::OOFPosRelMgr::dealingWithSizeOfChild returns *false* in all
+cases, it is delegated to the *container*. **Idea for fix:**
+dw::oof::OOFPosRelMgr::dealingWithSizeOfChild should return *false* if
+and only if the generator of the child is the container (to prevent an
+endless recursion). In other cases,
+dw::oof::OOFPosRelMgr::getAvailWidthOfChild and
+dw::oof::OOFPosRelMgr::getAvailHeightOfChild should directly call the
+respective methods of the *generator*, which must be made public then.
+
+**Performance:** In many cases, the first call of
+dw::oof::OOFPosRelMgr::sizeAllocateEnd will queue again the resize
+idle, since some elements are not considered in
+dw::oof::OOFPosRelMgr::getSize. One case could be removed: if a
+positioned element has *left* = *top* = 0, and its total size (the
+requisition) is equal to the space left at the original position, the
+size of the widget *reference*
+(dw::oof::OOFAwareWidget::getRequisitionWithoutOOF, see
+dw::oof::OOFPosRelMgr::calcWidgetRefSize).
+
+**Documentation:** Describe why the latter is not covered by
+dw::oof::OOFPositionedMgr::doChildrenExceedContainer. (Is this really
+the case?)
+
+**Open:** Stacking order? Furthermore: a relatively positioned element
+does not always constitute a containing block (see CSS specification).
+
+Fixed positions
+---------------
+Currently, fixedly positioned elements are positioned relative to the
+canvas, not to the viewport. For a complete implementation, see \ref
+dw-fixed-positions.
+
+*/
diff --git a/devdoc/dw-out-of-flow.doc b/devdoc/dw-out-of-flow.doc
index ea4a52bc..eda6994a 100644
--- a/devdoc/dw-out-of-flow.doc
+++ b/devdoc/dw-out-of-flow.doc
@@ -1,9 +1,39 @@
/** \page dw-out-of-flow Handling Elements Out Of Flow
-
-<div style="border: 2px solid #ffff00; margin-bottom: 0.5em;
+<div style="border: 2px solid #ff4040; margin-bottom: 0.5em;
+padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+Not up to date; incorporate these two changes: (i) there are different
+containing blocks for floats and absolutely (furthermore also fixedly)
+positioned elements; (ii) dw::oof::OutOfFlowMgr is now only the base
+class; floats and absolutely positioned elements are seperated:
+\dot
+digraph G {
+ node [shape=record, fontname=Helvetica, fontsize=10];
+ edge [arrowhead="none", arrowtail="empty", dir="both"];
+ fontname=Helvetica; fontsize=8;
+
+ OutOfFlowMgr [URL="\ref dw::oof::OutOfFlowMgr"; color="#a0a0a0"];
+ OOFFloatsMgr [URL="\ref dw::oof::OOFFloatsMgr"];
+ OOFPositionedMgr [URL="\ref dw::oof::OOFPositionedMgr"; color="#a0a0a0"];
+ OOFPosAbsLikeMgr [URL="\ref dw::oof::OOFPosAbsLikeMgr"; color="#a0a0a0"];
+ OOFPosAbsMgr [URL="\ref dw::oof::OOFPosAbsMgr"];
+ OOFPosFixedMgr [URL="\ref dw::oof::OOFPosFixedMgr"];
+ OOFPosRelMgr [URL="\ref dw::oof::OOFPosRelMgr"];
+
+ OutOfFlowMgr -> OOFFloatsMgr;
+ OutOfFlowMgr -> OOFPositionedMgr;
+ OOFPositionedMgr -> OOFPosAbsLikeMgr;
+ OOFPosAbsLikeMgr -> OOFPosAbsMgr;
+ OOFPosAbsLikeMgr -> OOFPosFixedMgr;
+ OOFPositionedMgr -> OOFPosRelMgr;
+}
+\enddot
+</div>
+
+<div style="border: 2px solid #ffff00; margin: 1em 0;
padding: 0.5em 1em; background-color: #ffffe0"><b>Info:</b>
-Should be incorporated into dw::Textblock.</div>
+A simplification is ongoing, see \ref dw-size-request-pos.
+</div>
Introduction
============
@@ -82,16 +112,16 @@ dw::Textblock::containingBlock appropriately, (according to rules
which should be defined in this document).
Handling widgets out of flow is partly the task of the new class
-dw::OutOfFlowMgr, which is stored by dw::Textblock::outOfFlowMgr, but
-only for containing blocks. Generating blocks should refer to
-*containingBlock->outOfFlowMgr*. (Perhaps dw::OutOfFlowMgr may become
-independent of dw::Textblock.)
+dw::oof::OutOfFlowMgr, which is stored by dw::Textblock::outOfFlowMgr,
+but only for containing blocks. Generating blocks should refer to
+*containingBlock->outOfFlowMgr*. (Perhaps dw::oof::OutOfFlowMgr may
+become independent of dw::Textblock.)
dw::Textblock::addWidget is extended, so that floats and absolutely
positioned elements can be added. Notice that not *this* widget, but
the containing block becomes the parent of the newly added child, if
it is out of flow. dw::Textblock::addWidget decides this by calling
-dw::OutOfFlowMgr::isOutOfFlow. (See new content types above.)
+dw::oof::OutOfFlowMgr::isOutOfFlow. (See new content types above.)
dw::core::Widget::parentRef has become a new representation. Before,
it represented the line numer. Now (least signifant bit left):
@@ -112,11 +142,11 @@ it represented the line numer. Now (least signifant bit left):
| absolutely positioned index | 1 | 1 |
+---+ - - - +---+---+- - - - - -+---+---+---+---+
-Details are hidden by static inline methods of dw::OutOfFlowMgr.
+Details are hidden by static inline methods of dw::oof::OutOfFlowMgr.
The sizeRequest/sizeAllocate problem
-========================================
+====================================
*See also:* \ref dw-widget-sizes, especially the section *Rules for
Methods Related to Resizing*.
@@ -136,7 +166,7 @@ steps:
Especially for floats, this model becomes a bit difficult, for reasons
described below. For the solutions, much is centralized at the level
of the containing block, which delegates most to an instance of
-dw::OutOfFlowMgr (details below).
+dw::oof::OutOfFlowMgr (details below).
**The size of a widget depends on the size not only of the children.**
In the example above, the last list item (green, following the
@@ -149,7 +179,8 @@ section *Rules for Methods Related to Resizing*): *sizeRequest* can be
called within *sizeRequestImpl* for other widgets that children (with
some caution). Namely, dw::Textblock::sizeRequestImpl calls
dw::core::Widget::sizeRequest for the float, via
-dw::OutOfFlowMgr::getBorder and dw::OutOfFlowMgr::ensureFloatSize.
+dw::oof::OutOfFlowMgr::getBorder and
+dw::oof::OutOfFlowMgr::ensureFloatSize.
**The size of a widget depends on the allocation of another widget.**
In the example above, both list items (blue and green) must know the
@@ -167,17 +198,18 @@ dw::core::Widget::queueResize, so that all border calculations are
repeated. See below (*hasRelationChanged*) for details.
Generally, this pattern (distinguishing between GB and CB) can be
-found everywhere in dw::OutOfFlowMgr.
+found everywhere in dw::oof::OutOfFlowMgr.
For details see:
-- dw::OutOfFlowMgr::getLeftBorder, dw::OutOfFlowMgr::getRightBorder,
- dw::OutOfFlowMgr::getBorder (called by the first two), and
- especially, dw::OutOfFlowMgr::getFloatsListForTextblock (called by
- the latter), where these three cases are distinguished;
-- dw::OutOfFlowMgr::sizeAllocateStart,
- dw::OutOfFlowMgr::sizeAllocateEnd which are called by the containing
- block.
+- dw::oof::OutOfFlowMgr::getLeftBorder,
+ dw::oof::OutOfFlowMgr::getRightBorder,
+ dw::oof::OutOfFlowMgr::getBorder (called by the first two), and
+ especially, dw::oof::OutOfFlowMgr::getFloatsListForTextblock (called
+ by the latter), where these three cases are distinguished;
+- dw::oof::OutOfFlowMgr::sizeAllocateStart,
+ dw::oof::OutOfFlowMgr::sizeAllocateEnd which are called by the
+ containing block.
(This could be solved in a more simple, elegant way, when
*sizeRequest* would depend on the position. This is, however, only a
@@ -209,6 +241,12 @@ Integration of line breaking and floats
Absolute and fixed positiones
=============================
-See <http://flpsed.org/hgweb/dillo_grows>.
+To be documented.
+
+
+See also
+========
+
+→ \ref dw-miscellaneous.
-*/ \ No newline at end of file
+*/
diff --git a/devdoc/dw-size-request-pos-01.html b/devdoc/dw-size-request-pos-01.html
new file mode 100644
index 00000000..104b8c57
--- /dev/null
+++ b/devdoc/dw-size-request-pos-01.html
@@ -0,0 +1,35 @@
+<p style="margin-bottom: 5em"><i>This is the source of the image
+<a href="dw-size-request-pos-01.png">dw-size-request-pos-01.png</a>.</i></p>
+
+<table lang="en">
+ <td style="width: 220px">
+ <p>
+ <div style="float:right">
+ <img src="xhttps://www.gnu.org/graphics/heckert_gnu.small.png">
+ <p style="text-align: center"><i>A GNU</i></p>
+ </div>
+ Short.
+ </p>
+ <p>A longer paragraph, into which a float extends, which has been
+ defined in the previous paragraph. </p>
+ </td>
+ <td style="vertical-align: middle">
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://upload.wikimedia.org/wikipedia/commons/8/80/CorrespMtl5.png" style="width: 80px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td style="width: 220px">
+ <p>
+ <div style="float:right">
+ <img src="https://www.gnu.org/graphics/heckert_gnu.small.png">
+ <p style="text-align: center"><i>A GNU</i></p>
+ </div>
+ Short.
+ </p>
+ <p>A longer paragraph, into which a float extends, which has been
+ defined in the previous paragraph. </p>
+ </td>
+</table>
diff --git a/devdoc/dw-size-request-pos-01.png b/devdoc/dw-size-request-pos-01.png
new file mode 100644
index 00000000..ba32e243
--- /dev/null
+++ b/devdoc/dw-size-request-pos-01.png
Binary files differ
diff --git a/devdoc/dw-size-request-pos.doc b/devdoc/dw-size-request-pos.doc
new file mode 100644
index 00000000..32cc3089
--- /dev/null
+++ b/devdoc/dw-size-request-pos.doc
@@ -0,0 +1,144 @@
+/** \page dw-size-request-pos Size requisitions depending on positions
+
+<div style="border: 2px solid #ffff00; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #ffffe0">The complex "widget
+ sizes" is currently divided into three documents: \ref
+ dw-widget-sizes, \ref dw-grows, and **Size requisitions depending on
+ positions** (this document). </div>
+
+<div style="border: 2px solid #ff4040; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+ May not be up to date, needs a review.</div>
+
+Motivation
+==========
+
+As described in \ref dw-out-of-flow (*The sizeRequest/sizeAllocate
+problem*), the principle that the size of a widget depends only on the
+sizes of its children causes some problems with floats; the current
+solution is a frequent correction by calling
+dw::core::Widget::queueResize. In this document, an alternative
+approach is presented.
+
+
+General Idea
+============
+
+A widget size may depend on the position relative to an anchestor
+widget. If a widget wants to get the size of a child widget, it should
+
+1. call the new methods dw::core::Widget::numSizeRequestReferences and
+ dw::core::Widget::sizeRequestReference, which return all widgets
+ relative to which the child's position must be calculated;
+2. call dw::core::Widget::sizeRequest with the positions relative to
+ these widgets.
+
+All positions passed to dw::core::Widget::sizeRequest must costitute
+the position at which this child will be allocated.
+
+There are situations where the parent widget is unable to determine
+these positions before the size is known. An example: a textblock
+widget cannot determine the positions of an inline widget (like an
+image, or an inline block) before the line is finished; on the other
+hand, finishing the line depends on knowing the sizes of the inline
+widgets.
+
+This may result in a conflict, when the size of an inline widget
+depends on positions. Generally, the only widget whose size depends on
+positions is dw::Textblock (the size will depend on the positions
+within its oof container, see \ref dw-out-of-flow), so this conflict
+occurs with inline blocks.
+
+This conflict is handled in different ways:
+
+1. Fortunately, this case is irrelevat for floats: an inline blocks
+ constitute its own floats container, so that there is no dependance
+ on a position within another widget.
+
+2. For positioned elements, this case is relevant, since an inline
+ block is in most cases not a container for positioned element. In
+ this case, a generator will call the methods
+ dw::oof::OutOfFlowMgr::tellIncompletePosition1 and
+ dw::oof::OutOfFlowMgr::tellIncompletePosition2, instead of
+ dw::oof::OutOfFlowMgr::tellPosition and
+ dw::oof::OutOfFlowMgr::tellPosition2, respectively. (Since this
+ case is irrelevant for floats,
+ dw::oof::OOFFloatsMgr::tellIncompletePosition1 and
+ dw::oof::OOFFloatsMgr::tellIncompletePosition2 are not implemented but
+ simply abort.)
+
+(This is not (yet) considered for borders: borders are only relevant
+for floats, but conflicts do not occur for floats.)
+
+
+Extremes
+--------
+Extremes may depend on the position in an analogue way, see:
+
+- dw::core::Widget::numGetExtremesReferences,
+- dw::core::Widget::getExtremesReference, and
+- dw::core::Widget::getExtremes.
+
+Resizing
+--------
+Currently, the size of a widget has to be recalculated, when
+
+1. it has called dw::core::Widget::queueResize, or
+2. the size of a child widget has to be recalculated.
+
+Since for this new approach, the size does not only depend on the size
+of the children, the second condition must be modified. However,
+regarding changes of the position is not sufficient. Consider this
+example, where a float size changes as soon as the image is loaded:
+
+\image html dw-size-request-pos-01.png
+
+The second paragraph ("A longer paragraph" ...) stays at the same
+position, both absolute and relative to the float container, but has
+to be rewrapped because of the float.
+
+(TODO: A detailed design is yet to de developed.)
+
+
+Plan
+====
+
+1. General design (dw::core::Widget::sizeRequestReference, changes to
+ dw::core::Widget::sizeRequest). **COMPLETED.**
+
+2. Implementation for dw::Textblock. **COMPLETED** (except for some bugs).
+
+3. Change interface of dw::oof::OutOfFlowMgr (this affects mostly
+ only comments). **COMPLETED.**
+
+ Affects methods dw::oof::OutOfFlowMgr::tellPosition1,
+ dw::oof::OutOfFlowMgr::tellPosition2,
+ dw::oof::OutOfFlowMgr::getLeftBorder,
+ dw::oof::OutOfFlowMgr::getRightBorder,
+ dw::oof::OutOfFlowMgr::hasFloatLeft,
+ dw::oof::OutOfFlowMgr::hasFloatRight,
+ dw::oof::OutOfFlowMgr::getLeftFloatHeight, and
+ dw::oof::OutOfFlowMgr::getRightFloatHeight.
+
+4. Apply step 3 to calls within dw::Textblock. **COMPLETED.**
+
+ <b>Attention:</b> After this step, and before completing the next
+ steps, the code is inconsistend and so incorrect.
+
+5. Implement step 3 for floats (affects dw::oof:OOFFloatsMgr).
+ *INCOMPLETE.*
+
+6. Implement step 3 for positioned elements (affects only
+ dw::oof:OOFPositionedMgr). *INCOMPLETE.*
+
+
+Issues
+======
+
+- Since the signature of dw::core::Widget::sizeRequestImpl changes
+ quite often during the development of *size requisitions depending
+ on positions*, a simpler option dw::core::Widget::sizeRequestSimpl
+ has been added. May be removed again, after the design is stable.
+
+
+*/
diff --git a/devdoc/dw-stacking-context.doc b/devdoc/dw-stacking-context.doc
new file mode 100644
index 00000000..6138ca5d
--- /dev/null
+++ b/devdoc/dw-stacking-context.doc
@@ -0,0 +1,114 @@
+/** \page dw-stacking-context Handling stacking contexts
+
+Stacking Context and dw::core::StackingContextMgr
+=================================================
+
+For the definition of stacking contexts, see CSS 2.1 specification,
+
+- <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section
+ 9.9.1: Specifying the stack level: the 'z-index' property</a> and
+- <a href="http://www.w3.org/TR/CSS2/zindex.html">appendix E</a>.
+
+A widget establishes a stacking context when it is positioned and its
+style value of *z-index* is different from *auto* (see
+dw::core::StackingContextMgr::isEstablishingStackingContext). In this
+case, it is assigned an instance of dw::core::StackingContextMgr,
+which has also access to the widgets establishing the child contexts.
+
+
+Stacking Order
+==============
+
+The stacking order influences
+
+1. the order in which child widgets are drawn (dw::core::Widget::draw),
+ and
+2. the order in which mouse events are dispatched to child widgets
+ (dw::core::Widget::getWidgetAtPoint).
+
+The first is done from bottom to top, the latter from top to bottom.
+
+I'm here referring to the simplified description in
+<a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section
+9.9.1</a>. The table shows a recommended order for the implementations
+of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint
+(for the latter, read from bottom to top):
+
+<table>
+<tr>
+<th> CSS specification <th> Drawing <th> Mouse events
+<tr>
+<td> *1. the background and borders of the element forming the
+ stacking context.*
+<td> dw::core::Widget::drawBox
+<td> Nothing necessary.
+<tr>
+<td> *2. the child stacking contexts with negative stack levels (most
+ negative first).*
+<td> dw::core::StackingContextMgr::drawBottom (when defined)
+<td> dw::core::StackingContextMgr::getBottomWidgetAtPoint (when defined)
+<tr>
+<td> *3. the in-flow, non-inline-level, non-positioned descendants.*
+
+<td rowspan="4"> When (i) widget specific content is drawn, then (ii)
+ dw::oof::OOFAwareWidget::drawOOF is called, this will
+ have this effect:
+
+ 1. all in-flow elements are drawn,
+ 2. floats are drawn and
+ 3. positioned elements with *z-index: auto* are drawn
+ (latter two done by
+ dw::oof::OOFAwareWidget::drawOOF, in this order).
+
+ This order differs from the specified order, but
+ since floats and in-flow elements do not overlap,
+ this difference has no effect.
+
+ Drawing in-line elements, floats and positioned
+ elements with *z-index: auto* and should avoid
+ duplicate calls: Widgets drawn by
+ dw::core::StackingContextMgr::drawBottom and by
+ dw::core::StackingContextMgr::drawTop should be
+ excluded here. This can be tested with
+ dw::core::StackingContextMgr::handledByStackingContextMgr.
+
+<td rowspan="4"> Likewise, the implementation should (i) test
+ dw::oof::OOFAwareWidget::getWidgetOOFAtPoint, and
+ (ii) search through the chilren. Also, duplicate
+ calls should be avoided using
+ dw::core::StackingContextMgr::handledByStackingContextMgr.
+
+ There are already the implementations
+ dw::core::Widget::getWidgetAtPoint (ignoring
+ dw::oof::OutOfFlowMgr) and
+ dw::oof::OOFAwareWidget::getWidgetAtPoint (including
+ dw::oof::OutOfFlowMgr).
+
+<tr>
+<td> *4. the non-positioned floats.*
+<tr>
+<td> *5. the in-flow, inline-level, non-positioned descendants,
+ including inline tables and inline blocks.*
+<tr>
+<td> (What about positioned elements with *z-index: auto*? Seems to be
+ missing in
+ <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section
+ 9.9.1</a>, but mentioned in
+ <a href="http://www.w3.org/TR/CSS2/zindex.html">appendix E</a>,
+ item 8.
+<tr>
+<td> *6. the child stacking contexts with stack level 0 and the
+ positioned descendants with stack level 0.*
+<td rowspan="2"> dw::core::StackingContextMgr::drawTop (when defined)
+<td rowspan="2"> dw::core::StackingContextMgr::getTopWidgetAtPoint
+ (when defined)
+<tr>
+<td> *7. the child stacking contexts with positive stack levels (least
+ positive first).*
+</table>
+
+Note: This is not quite in conformance with the specification: this
+description refers to any widget, not only widgets establishing a
+stacking context. Does this make a difference?
+
+*/ \ No newline at end of file
diff --git a/devdoc/dw-widget-sizes.doc b/devdoc/dw-widget-sizes.doc
index a82d3b99..ffc7fb5d 100644
--- a/devdoc/dw-widget-sizes.doc
+++ b/devdoc/dw-widget-sizes.doc
@@ -1,8 +1,14 @@
/** \page dw-widget-sizes Sizes of Dillo Widgets
-<div style="border: 2px solid #ff4040; margin-bottom: 0.5em;
-padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
-Not up to date, see \ref dw-grows.</div>
+<div style="border: 2px solid #ffff00; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #ffffe0">The complex "widget
+ sizes" is currently divided into three documents: **Sizes of Dillo
+ Widgets** (this document), \ref dw-grows, and \ref
+ dw-size-request-pos. </div>
+
+<div style="border: 2px solid #ff4040; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+ Not up to date, see other documents.</div>
Allocation
==========
@@ -268,10 +274,4 @@ This could be done furthermore:
- Is it possible to define exacter rules, along with a proof that no
problems (like endless recursion) can occur?
-
-See also
-========
-
-- \ref dw-grows
-
*/
diff --git a/dw/Makefile.am b/dw/Makefile.am
index 68410805..ee779254 100644
--- a/dw/Makefile.am
+++ b/dw/Makefile.am
@@ -23,8 +23,12 @@ libDw_core_a_SOURCES = \
platform.hh \
selection.hh \
selection.cc \
+ stackingcontextmgr.hh \
+ stackingcontextmgr.cc \
style.cc \
style.hh \
+ tools.cc \
+ tools.hh \
types.cc \
types.hh \
ui.cc \
@@ -69,6 +73,21 @@ libDw_widgets_a_SOURCES = \
image.hh \
listitem.cc \
listitem.hh \
+ oofawarewidget.cc \
+ oofawarewidget_iterator.cc \
+ oofawarewidget.hh \
+ ooffloatsmgr.cc \
+ ooffloatsmgr.hh \
+ oofposabslikemgr.cc \
+ oofposabslikemgr.hh \
+ oofposabsmgr.cc \
+ oofposabsmgr.hh \
+ oofposfixedmgr.cc \
+ oofposfixedmgr.hh \
+ oofpositionedmgr.cc \
+ oofpositionedmgr.hh \
+ oofposrelmgr.cc \
+ oofposrelmgr.hh \
outofflowmgr.cc \
outofflowmgr.hh \
regardingborder.cc \
diff --git a/dw/alignedtablecell.cc b/dw/alignedtablecell.cc
index e65bbf2c..b5e321b7 100644
--- a/dw/alignedtablecell.cc
+++ b/dw/alignedtablecell.cc
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-
#include "alignedtablecell.hh"
#include "table.hh"
#include "tablecell.hh"
@@ -65,7 +63,7 @@ bool AlignedTableCell::mustBeWidenedToAvailWidth ()
int AlignedTableCell::getAvailWidthOfChild (Widget *child, bool forceValue)
{
- DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell/getAvailWidthOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell::getAvailWidthOfChild",
"%p, %s", child, forceValue ? "true" : "false");
int width = tablecell::correctAvailWidthOfChild
@@ -78,7 +76,7 @@ int AlignedTableCell::getAvailWidthOfChild (Widget *child, bool forceValue)
int AlignedTableCell::getAvailHeightOfChild (Widget *child, bool forceValue)
{
- DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell/getAvailHeightOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell::getAvailHeightOfChild",
"%p, %s", child, forceValue ? "true" : "false");
int height = tablecell::correctAvailHeightOfChild
@@ -96,7 +94,7 @@ void AlignedTableCell::correctRequisitionOfChild (Widget *child,
int*,
int*))
{
- DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell/correctRequisitionOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell::correctRequisitionOfChild",
"%p, %d * (%d + %d), ...", child, requisition->width,
requisition->ascent, requisition->descent);
@@ -112,7 +110,7 @@ void AlignedTableCell::correctExtremesOfChild (Widget *child,
core::Extremes *extremes,
bool useAdjustmentWidth)
{
- DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell/correctExtremesOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "AlignedTableCell::correctExtremesOfChild",
"%p, %d (%d) / %d (%d)",
child, extremes->minWidth, extremes->minWidthIntrinsic,
extremes->maxWidth, extremes->maxWidthIntrinsic);
@@ -137,6 +135,11 @@ int AlignedTableCell::applyPerHeight (int containerHeight,
return tablecell::applyPerHeight (this, containerHeight, perHeight);
}
+bool AlignedTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF ()
+{
+ return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+}
+
int AlignedTableCell::wordWrap(int wordIndex, bool wrapAll)
{
Textblock::Word *word;
@@ -199,7 +202,7 @@ int AlignedTableCell::getValue ()
void AlignedTableCell::setMaxValue (int maxValue, int value)
{
line1Offset = maxValue - value;
- queueResize (OutOfFlowMgr::createRefNormalFlow (0), true);
+ queueResize (makeParentRefInFlow (0), true);
}
} // namespace dw
diff --git a/dw/alignedtablecell.hh b/dw/alignedtablecell.hh
index b4203047..56196e6d 100644
--- a/dw/alignedtablecell.hh
+++ b/dw/alignedtablecell.hh
@@ -23,6 +23,8 @@ protected:
bool getAdjustMinWidth ();
+ bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
int wordWrap (int wordIndex, bool wrapAll);
int getValue ();
diff --git a/dw/bullet.cc b/dw/bullet.cc
index 40c197e6..98feb556 100644
--- a/dw/bullet.cc
+++ b/dw/bullet.cc
@@ -35,14 +35,14 @@ Bullet::~Bullet ()
DBG_OBJ_DELETE ();
}
-void Bullet::sizeRequestImpl (core::Requisition *requisition)
+void Bullet::sizeRequestSimpl (core::Requisition *requisition)
{
requisition->width = lout::misc::max (getStyle()->font->xHeight * 4 / 5, 1);
requisition->ascent = lout::misc::max (getStyle()->font->xHeight, 1);
requisition->descent = 0;
}
-void Bullet::getExtremesImpl (core::Extremes *extremes)
+void Bullet::getExtremesSimpl (core::Extremes *extremes)
{
extremes->minWidth = extremes->maxWidth = extremes->adjustmentWidth =
extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic =
@@ -56,7 +56,8 @@ void Bullet::containerSizeChangedForChildren ()
DBG_OBJ_LEAVE ();
}
-void Bullet::draw (core::View *view, core::Rectangle *area)
+void Bullet::draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context)
{
int x, y, l;
bool filled = true;
diff --git a/dw/bullet.hh b/dw/bullet.hh
index 004187cd..ac94738e 100644
--- a/dw/bullet.hh
+++ b/dw/bullet.hh
@@ -14,10 +14,11 @@ namespace dw {
class Bullet: public core::Widget
{
protected:
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void sizeRequestSimpl (core::Requisition *requisition);
+ void getExtremesSimpl (core::Extremes *extremes);
void containerSizeChangedForChildren ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
public:
diff --git a/dw/core.hh b/dw/core.hh
index 022574b1..9463df2b 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -25,6 +25,7 @@ class Layout;
class View;
class Widget;
class Iterator;
+class StackingContextMgr;
// Nothing yet to free.
inline void freeall () { }
@@ -53,6 +54,7 @@ class ResourceFactory;
#include "selection.hh"
#include "layout.hh"
#include "widget.hh"
+#include "stackingcontextmgr.hh"
#include "ui.hh"
#undef __INCLUDED_FROM_DW_CORE_HH__
diff --git a/dw/fltkui.cc b/dw/fltkui.cc
index 51523b95..09965ea7 100644
--- a/dw/fltkui.cc
+++ b/dw/fltkui.cc
@@ -476,7 +476,8 @@ void FltkResource::sizeAllocate (core::Allocation *allocation)
DBG_OBJ_LEAVE ();
}
-void FltkResource::draw (core::View *view, core::Rectangle *area)
+void FltkResource::draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context)
{
FltkView *fltkView = (FltkView*)view;
if (fltkView->usesFltkWidgets () && this->view == fltkView) {
@@ -577,9 +578,11 @@ template <class I> void FltkSpecificResource<I>::sizeAllocate (core::Allocation
}
template <class I> void FltkSpecificResource<I>::draw (core::View *view,
- core::Rectangle *area)
+ core::Rectangle *area,
+ core::DrawingContext
+ *context)
{
- FltkResource::draw (view, area);
+ FltkResource::draw (view, area, context);
}
template <class I> void FltkSpecificResource<I>::setStyle (core::style::Style
diff --git a/dw/fltkui.hh b/dw/fltkui.hh
index 09cdc978..ff6331d1 100644
--- a/dw/fltkui.hh
+++ b/dw/fltkui.hh
@@ -211,7 +211,8 @@ public:
virtual void detachView (FltkView *view);
void sizeAllocate (core::Allocation *allocation);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
void setStyle (core::style::Style *style);
@@ -227,7 +228,8 @@ public:
~FltkSpecificResource ();
void sizeAllocate (core::Allocation *allocation);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
void setStyle (core::style::Style *style);
bool isEnabled ();
diff --git a/dw/image.cc b/dw/image.cc
index fd959695..519b82bb 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -172,7 +172,7 @@ Image::~Image()
DBG_OBJ_DELETE ();
}
-void Image::sizeRequestImpl (core::Requisition *requisition)
+void Image::sizeRequestSimpl (core::Requisition *requisition)
{
DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl");
@@ -237,7 +237,7 @@ void Image::sizeRequestImpl (core::Requisition *requisition)
DBG_OBJ_LEAVE ();
}
-void Image::getExtremesImpl (core::Extremes *extremes)
+void Image::getExtremesSimpl (core::Extremes *extremes)
{
int contentWidth;
if (buffer)
@@ -337,7 +337,7 @@ void Image::leaveNotifyImpl (core::EventCrossing *event)
*/
int Image::contentX (core::MousePositionEvent *event)
{
- int ret = event->xWidget - getStyle()->boxOffsetX();
+ int ret = event->xWidget - boxOffsetX();
ret = misc::min(getContentWidth(), misc::max(ret, 0));
return ret;
@@ -345,7 +345,7 @@ int Image::contentX (core::MousePositionEvent *event)
int Image::contentY (core::MousePositionEvent *event)
{
- int ret = event->yWidget - getStyle()->boxOffsetY();
+ int ret = event->yWidget - boxOffsetY();
ret = misc::min(getContentHeight(), misc::max(ret, 0));
return ret;
@@ -407,7 +407,8 @@ bool Image::buttonReleaseImpl (core::EventButton *event)
return false;
}
-void Image::draw (core::View *view, core::Rectangle *area)
+void Image::draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context)
{
int dx, dy;
core::Rectangle content, intersection;
@@ -415,8 +416,8 @@ void Image::draw (core::View *view, core::Rectangle *area)
drawWidgetBox (view, area, false);
if (buffer) {
- dx = getStyle()->boxOffsetX ();
- dy = getStyle()->boxOffsetY ();
+ dx = boxOffsetX ();
+ dy = boxOffsetY ();
content.x = dx;
content.y = dy;
content.width = getContentWidth ();
@@ -443,31 +444,29 @@ void Image::draw (core::View *view, core::Rectangle *area)
(getContentHeight() <
getStyle()->font->ascent + getStyle()->font->descent)) {
clippingView = usedView =
- view->getClippingView (allocation.x + getStyle()->boxOffsetX (),
- allocation.y + getStyle()->boxOffsetY (),
+ view->getClippingView (allocation.x + boxOffsetX (),
+ allocation.y + boxOffsetY (),
getContentWidth(),
getContentHeight());
}
usedView->drawSimpleWrappedText (getStyle()->font, getStyle()->color,
core::style::Color::SHADING_NORMAL,
- allocation.x + getStyle()->boxOffsetX (),
- allocation.y + getStyle()->boxOffsetY (),
+ allocation.x + boxOffsetX (),
+ allocation.y + boxOffsetY (),
getContentWidth(), getContentHeight(), altText);
if (clippingView)
view->mergeClippingView (clippingView);
}
if (mapKey) {
- clippingView = view->getClippingView (allocation.x +
- getStyle()->boxOffsetX (),
- allocation.y +
- getStyle()->boxOffsetY (),
+ clippingView = view->getClippingView (allocation.x + boxOffsetX (),
+ allocation.y + boxOffsetY (),
getContentWidth(),
getContentHeight());
mapList->drawMap(mapKey, clippingView, getStyle(),
- allocation.x + getStyle()->boxOffsetX (),
- allocation.y + getStyle()->boxOffsetY ());
+ allocation.x + boxOffsetX (),
+ allocation.y + boxOffsetY ());
view->mergeClippingView (clippingView);
}
}
@@ -518,9 +517,8 @@ void Image::drawRow (int row)
buffer->getRowArea (row, &area);
if (area.width && area.height)
- queueDrawArea (area.x + getStyle()->boxOffsetX (),
- area.y + getStyle()->boxOffsetY (),
- area.width, area.height);
+ queueDrawArea (area.x + boxOffsetX (), area.y + boxOffsetY (), area.width,
+ area.height);
}
void Image::finish ()
diff --git a/dw/image.hh b/dw/image.hh
index b94f647d..ae47f307 100644
--- a/dw/image.hh
+++ b/dw/image.hh
@@ -130,12 +130,13 @@ private:
bool isMap;
protected:
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void sizeRequestSimpl (core::Requisition *requisition);
+ void getExtremesSimpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
void containerSizeChangedForChildren ();
-
- void draw (core::View *view, core::Rectangle *area);
+
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
diff --git a/dw/iterator.cc b/dw/iterator.cc
index 0edb580b..dbb779f6 100644
--- a/dw/iterator.cc
+++ b/dw/iterator.cc
@@ -204,14 +204,6 @@ void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end,
}
}
-
-void Iterator::print ()
-{
- misc::StringBuffer sb;
- intoStringBuffer (&sb);
- printf ("%s", sb.getChars ());
-}
-
// -------------------
// EmptyIterator
// -------------------
diff --git a/dw/iterator.hh b/dw/iterator.hh
index abf31d0b..9460adc4 100644
--- a/dw/iterator.hh
+++ b/dw/iterator.hh
@@ -86,8 +86,6 @@ public:
static void scrollTo (Iterator *it1, Iterator *it2, int start, int end,
HPosition hpos, VPosition vpos);
-
- virtual void print ();
};
diff --git a/dw/layout.cc b/dw/layout.cc
index c2a53d08..d18bc486 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -374,6 +374,14 @@ void Layout::addWidget (Widget *widget)
return;
}
+ // The toplevel widget always establishes a stacking context. It could
+ // already be set in Widget::setStyle().
+ if (widget->stackingContextMgr == NULL) {
+ widget->stackingContextMgr = new StackingContextMgr (widget);
+ DBG_OBJ_ASSOC (widget, widget->stackingContextMgr);
+ widget->stackingContextWidget = widget;
+ }
+
topLevel = widget;
widget->layout = this;
widget->container = NULL;
@@ -654,6 +662,9 @@ bool Layout::calcScrollInto (int requestedValue, int requestedSize,
void Layout::draw (View *view, Rectangle *area)
{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
Rectangle widgetArea, intersection, widgetDrawArea;
// First of all, draw background image. (Unlike background *color*,
@@ -693,11 +704,14 @@ void Layout::draw (View *view, Rectangle *area)
widgetDrawArea.width = intersection.width;
widgetDrawArea.height = intersection.height;
- topLevel->draw (view, &widgetDrawArea);
+ DrawingContext context (&widgetArea);
+ topLevel->draw (view, &widgetDrawArea, &context);
view->finishDrawing (&intersection);
}
}
+
+ DBG_OBJ_LEAVE ();
}
int Layout::currHScrollbarThickness()
@@ -1093,12 +1107,18 @@ void Layout::leaveNotify (View *view, ButtonState state)
*/
Widget *Layout::getWidgetAtPoint (int x, int y)
{
- _MSG ("------------------------------------------------------------\n");
- _MSG ("widget at (%d, %d)\n", x, y);
- if (topLevel && topLevel->wasAllocated ())
- return topLevel->getWidgetAtPoint (x, y, 0);
- else
- return NULL;
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *widget;
+
+ if (topLevel && topLevel->wasAllocated ()) {
+ GettingWidgetAtPointContext context;
+ widget = topLevel->getWidgetAtPoint (x, y, &context);
+ } else
+ widget = NULL;
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
}
@@ -1108,12 +1128,16 @@ Widget *Layout::getWidgetAtPoint (int x, int y)
*/
void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
{
+ DBG_OBJ_ENTER ("events", 0, "moveToWidget", "%p, %d",
+ newWidgetAtPoint, state);
+
Widget *ancestor, *w;
Widget **track;
int trackLen, i, i_a;
EventCrossing crossingEvent;
- _MSG("moveToWidget: wap=%p nwap=%p\n",widgetAtPoint,newWidgetAtPoint);
+ DBG_OBJ_MSGF ("events", 1, "(old) widgetAtPoint = %p", widgetAtPoint);
+
if (newWidgetAtPoint != widgetAtPoint) {
// The mouse pointer has been moved into another widget.
if (newWidgetAtPoint && widgetAtPoint)
@@ -1183,6 +1207,8 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
widgetAtPoint = newWidgetAtPoint;
updateCursor ();
}
+
+ DBG_OBJ_LEAVE ();
}
/**
diff --git a/dw/layout.hh b/dw/layout.hh
index 32b9a134..16d19979 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -314,7 +314,12 @@ public:
/* View */
- inline void expose (View *view, Rectangle *area) { draw (view, area); }
+ inline void expose (View *view, Rectangle *area) {
+ DBG_OBJ_ENTER ("draw", 0, "expose", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ draw (view, area);
+ DBG_OBJ_LEAVE ();
+ }
/**
* \brief This function is called by a view, to delegate a button press
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
new file mode 100644
index 00000000..c1398a64
--- /dev/null
+++ b/dw/oofawarewidget.cc
@@ -0,0 +1,592 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofawarewidget.hh"
+#include "ooffloatsmgr.hh"
+#include "oofposabsmgr.hh"
+#include "oofposrelmgr.hh"
+#include "oofposfixedmgr.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::object;
+using namespace lout::misc;
+using namespace lout::container::typed;
+
+namespace dw {
+
+namespace oof {
+
+const char *OOFAwareWidget::OOFM_NAME[NUM_OOFM] = {
+ "FLOATS", "ABSOLUTE", "RELATIVE", "FIXED"
+};
+
+int OOFAwareWidget::CLASS_ID = -1;
+
+OOFAwareWidget::OOFAwareWidget ()
+{
+ DBG_OBJ_CREATE ("dw::oof::OOFAwareWidget");
+ registerName ("dw::oof::OOFAwareWidget", &CLASS_ID);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oofContainer[i] = NULL;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ outOfFlowMgr[i] = NULL;
+ }
+}
+
+OOFAwareWidget::~OOFAwareWidget ()
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if(outOfFlowMgr[i]) {
+ // I feel more comfortable by letting the OOF aware widget delete
+ // these widgets, instead of doing this in ~OutOfFlowMgr.
+ for (int j = 0; j < outOfFlowMgr[i]->getNumWidgets (); j++)
+ delete outOfFlowMgr[i]->getWidget (j);
+
+ delete outOfFlowMgr[i];
+ }
+ }
+
+ DBG_OBJ_DELETE ();
+}
+
+const char *OOFAwareWidget::stackingLevelText (int level)
+{
+ switch (level) {
+ case SL_START: return "START";
+ case SL_BACKGROUND: return "BACKGROUND";
+ case SL_SC_BOTTOM: return "SC_BOTTOM";
+ case SL_IN_FLOW: return "IN_FLOW";
+ case SL_OOF_REF: return "OOF_REF";
+ case SL_OOF_CONT: return "OOF_CONT";
+ case SL_SC_TOP: return "SC_TOP";
+ case SL_END: return "END";
+ default: return "???";
+ }
+}
+
+void OOFAwareWidget::notifySetAsTopLevel ()
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oofContainer[i] = this;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ }
+}
+
+int OOFAwareWidget::getOOFMIndex (Widget *widget)
+{
+ DBG_OBJ_ENTER_O ("construct", 0, NULL, "getOOFMIndex", "%p", widget);
+ DBG_OBJ_MSGF_O ("construct", 1, NULL, "position = %s, float = %s",
+ widget->getStyle()->position
+ == style::POSITION_STATIC ? "static" :
+ (widget->getStyle()->position
+ == style::POSITION_RELATIVE ? "relative" :
+ (widget->getStyle()->position
+ == style::POSITION_ABSOLUTE ? "absolute" :
+ (widget->getStyle()->position
+ == style::POSITION_FIXED ? "fixed" : "???"))),
+ widget->getStyle()->vloat == style::FLOAT_NONE ? "none" :
+ (widget->getStyle()->vloat == style::FLOAT_LEFT ? "left" :
+ (widget->getStyle()->vloat == style::FLOAT_RIGHT ?
+ "right" : "???")));
+
+ int index = -1;
+ if (testWidgetFloat (widget))
+ index = OOFM_FLOATS;
+ else if (testWidgetAbsolutelyPositioned (widget))
+ index = OOFM_ABSOLUTE;
+ else if (testWidgetRelativelyPositioned (widget))
+ index = OOFM_RELATIVE;
+ else if (testWidgetFixedlyPositioned (widget))
+ index = OOFM_FIXED;
+ else
+ lout::misc::assertNotReached ();
+
+ DBG_OBJ_LEAVE_VAL_O (NULL, "%d (%s)", index, OOFM_NAME[index]);
+ return index;
+}
+
+bool OOFAwareWidget::isOOFContainer (Widget *widget, int oofmIndex)
+{
+ // TODO The methods isPossibleContainer() and isPossibleContainerParent()
+ // are only used in few cases. Does not matter currently, however.
+
+ switch (oofmIndex) {
+ case OOFM_FLOATS:
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (// For floats, only some OOF aware widgets are considered as
+ // containers.
+ ((OOFAwareWidget*)widget)->isPossibleContainer (OOFM_FLOATS) &&
+ // The second condition: that this block is "out of flow", in a
+ // wider sense.
+ (// The toplevel widget is "out of flow", since there is no
+ // parent, and so no context.
+ widget->getParent() == NULL ||
+ // A similar reasoning applies to a widget with an
+ // unsuitable parent (typical example: a table cell (this
+ // is also a text block, so possible float container)
+ // within a table widget, which is not a suitable float
+ // container parent).
+ !(widget->getParent()->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ ((OOFAwareWidget*)widget->getParent())
+ ->isPossibleContainerParent (OOFM_FLOATS)) ||
+ // Inline blocks are containing blocks, too.
+ widget->getStyle()->display == DISPLAY_INLINE_BLOCK ||
+ // Same for blocks with 'overview' set to another value than
+ // (the default value) 'visible'.
+ widget->getStyle()->overflow != OVERFLOW_VISIBLE ||
+ // Finally, "out of flow" in a narrower sense: floats;
+ // absolutely and fixedly positioned elements. (No
+ // relatively positioned elements; since the latters
+ // constitute a stacking context, drawing of floats gets
+ // somewhat more complicated; see "interrupting the drawing
+ // process" in "dw-stacking-context.doc".
+ testWidgetOutOfFlow (widget)));
+
+ case OOFM_RELATIVE:
+ case OOFM_ABSOLUTE:
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (widget->getParent() == NULL ||
+ OOFAwareWidget::testWidgetPositioned (widget));
+
+
+ case OOFM_FIXED:
+ // The single container for fixedly positioned elements is the
+ // toplevel (canvas; actually the viewport). (The toplevel
+ // widget should always be a textblock; at least this is the
+ // case in dillo.)
+ return widget->getParent() == NULL;
+
+ default:
+ // compiler happiness
+ lout::misc::assertNotReached ();
+ return false;
+ }
+}
+
+void OOFAwareWidget::notifySetParent ()
+{
+ // Search for containing blocks.
+ for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
+ oofContainer[oofmIndex] = NULL;
+
+ for (Widget *widget = this;
+ widget != NULL && oofContainer[oofmIndex] == NULL;
+ widget = widget->getParent ())
+ if (isOOFContainer (widget, oofmIndex)) {
+ assert (widget->instanceOf (OOFAwareWidget::CLASS_ID));
+ oofContainer[oofmIndex] = (OOFAwareWidget*)widget;
+ }
+
+ DBG_OBJ_ARRSET_PTR ("oofContainer", oofmIndex, oofContainer[oofmIndex]);
+
+ assert (oofContainer[oofmIndex] != NULL);
+ }
+}
+
+void OOFAwareWidget::initOutOfFlowMgrs ()
+{
+ if (oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] == NULL) {
+ oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] =
+ new OOFFloatsMgr (oofContainer[OOFM_FLOATS]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_FLOATS],
+ oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS]);
+ }
+
+ if (oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] == NULL) {
+ oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] =
+ new OOFPosAbsMgr (oofContainer[OOFM_ABSOLUTE]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_ABSOLUTE],
+ oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE]);
+ }
+
+ if (oofContainer[OOFM_RELATIVE]->outOfFlowMgr[OOFM_RELATIVE] == NULL) {
+ oofContainer[OOFM_RELATIVE]->outOfFlowMgr[OOFM_RELATIVE] =
+ new OOFPosRelMgr (oofContainer[OOFM_RELATIVE]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_RELATIVE],
+ oofContainer[OOFM_RELATIVE]->outOfFlowMgr[OOFM_RELATIVE]);
+ }
+
+ if (oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] == NULL) {
+ oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] =
+ new OOFPosFixedMgr (oofContainer[OOFM_FIXED]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_FIXED],
+ oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED]);
+ }
+}
+
+void OOFAwareWidget::correctRequisitionByOOF (Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisitionByOOF", "%d * (%d + %d), ...",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+
+ requisitionWithoutOOF = *requisition;
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofWidth, oofHeight;
+
+ outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * %d", oofWidth, oofHeight);
+
+ if (oofWidth > requisition->width) {
+ if (outOfFlowMgr[i]->containerMustAdjustExtraSpace () &&
+ adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) {
+ extraSpace.right = max (extraSpace.right,
+ oofWidth - requisition->width);
+ DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right);
+ }
+
+ requisition->width = oofWidth;
+ }
+
+ if (oofHeight > requisition->ascent + requisition->descent) {
+ if (outOfFlowMgr[i]->containerMustAdjustExtraSpace () &&
+ adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) {
+ extraSpace.bottom = max (extraSpace.bottom,
+ oofHeight - (requisition->ascent +
+ requisition->descent));
+ DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom);
+ }
+
+ splitHeightFun (oofHeight,
+ &requisition->ascent, &requisition->descent);
+ }
+
+ if (!adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) {
+ requisitionWithoutOOF.width = max (requisitionWithoutOOF.width,
+ oofWidth);
+ if (oofHeight >
+ requisitionWithoutOOF.ascent + requisitionWithoutOOF.descent)
+ splitHeightFun (oofHeight, &requisitionWithoutOOF.ascent,
+ &requisitionWithoutOOF.descent);
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_SET_NUM ("requisitionWithoutOOF.width", requisitionWithoutOOF.width);
+ DBG_OBJ_SET_NUM ("requisitionWithoutOOF.ascent",
+ requisitionWithoutOOF.ascent);
+ DBG_OBJ_SET_NUM ("requisitionWithoutOOF.descent",
+ requisitionWithoutOOF.descent);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::correctExtremesByOOF (Extremes *extremes)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremesByOOF", "%d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d / %d",
+ oofMinWidth, oofMaxWidth);
+
+ extremes->minWidth = max (extremes->minWidth, oofMinWidth);
+ extremes->minWidthIntrinsic = max (extremes->minWidthIntrinsic,
+ oofMinWidth);
+ extremes->maxWidth = max (extremes->maxWidth, oofMaxWidth);
+ extremes->maxWidthIntrinsic = max (extremes->maxWidthIntrinsic,
+ oofMinWidth);
+ extremes->adjustmentWidth = max (extremes->adjustmentWidth,
+ oofMinWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::sizeAllocateStart (Allocation *allocation)
+{
+
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (oofContainer[i]->outOfFlowMgr[i])
+ oofContainer[i]->outOfFlowMgr[i]->sizeAllocateStart (this, allocation);
+}
+
+void OOFAwareWidget::sizeAllocateEnd ()
+{
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (oofContainer[i]->outOfFlowMgr[i])
+ oofContainer[i]->outOfFlowMgr[i]->sizeAllocateEnd (this);
+}
+
+void OOFAwareWidget::containerSizeChangedForChildrenOOF ()
+{
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (outOfFlowMgr[i])
+ outOfFlowMgr[i]->containerSizeChangedForChildren ();
+}
+
+bool OOFAwareWidget::doesWidgetOOFInterruptDrawing (Widget *widget)
+{
+ DBG_OBJ_ENTER ("draw", 0, "doesWidgetOOFInterruptDrawing", "%p", widget);
+
+ // This is the generator of the widget.
+ int oofmIndex = getOOFMIndex (widget);
+ DBG_OBJ_MSGF ("draw", 1, "oofmIndex = %d", oofmIndex);
+
+ int cl = oofContainer[oofmIndex]->stackingContextWidget->getLevel (),
+ gl = stackingContextWidget->getLevel ();
+
+ DBG_OBJ_MSGF ("draw", 1,"%d < %d => %s", cl, gl, cl < gl ? "true" : "false");
+
+ DBG_OBJ_LEAVE ();
+ return cl < gl;
+}
+
+void OOFAwareWidget::draw (View *view, Rectangle *area, DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ for (int level = SL_START + 1; level < SL_END; level++)
+ drawLevel (view, area, level, context);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::drawLevel (View *view, Rectangle *area, int level,
+ DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "OOFAwareWidget::drawLevel",
+ "(%d, %d, %d * %d), %s",
+ area->x, area->y, area->width, area->height,
+ stackingLevelText (level));
+
+ switch (level) {
+ case SL_START:
+ break;
+
+ case SL_BACKGROUND:
+ drawWidgetBox (view, area, false);
+ break;
+
+ case SL_SC_BOTTOM:
+ if (stackingContextMgr)
+ stackingContextMgr->drawBottom (view, area, context);
+ break;
+
+ case SL_IN_FLOW:
+ // Should be implemented in the sub class.
+ break;
+
+ case SL_OOF_REF:
+ // Should be implemented in the sub class (when references are hold).
+ break;
+
+ case SL_OOF_CONT:
+ drawOOF (view, area, context);
+ break;
+
+ case SL_SC_TOP:
+ if (stackingContextMgr)
+ stackingContextMgr->drawTop (view, area, context);
+ break;
+
+ case SL_END:
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::drawOOF (View *view, Rectangle *area,
+ DrawingContext *context)
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if(outOfFlowMgr[i])
+ outOfFlowMgr[i]->draw (view, area, context);
+ }
+}
+
+Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *widgetAtPoint = NULL;
+
+ if (inAllocation (x, y)) {
+ for (int level = SL_END - 1; widgetAtPoint == NULL && level > SL_START;
+ level--)
+ widgetAtPoint = getWidgetAtPointLevel (x, y, level, context);
+ }
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+Widget *OOFAwareWidget::getWidgetAtPointLevel (int x, int y, int level,
+ GettingWidgetAtPointContext
+ *context)
+{
+ DBG_OBJ_ENTER ("events", 0, "OOFAwareWidget::getWidgetAtPointLevel",
+ "%d, %d, %s", x, y, stackingLevelText (level));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (level) {
+ case SL_BACKGROUND:
+ if (inAllocation (x, y))
+ widgetAtPoint = this;
+ break;
+
+ case SL_SC_BOTTOM:
+ if (stackingContextMgr)
+ widgetAtPoint =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y, context);
+ break;
+
+ case SL_IN_FLOW:
+ // Should be implemented in the sub class.
+ assertNotReached ();
+ break;
+
+ case SL_OOF_REF:
+ // Should be implemented in the sub class (when references are hold).
+ break;
+
+ case SL_OOF_CONT:
+ widgetAtPoint = getWidgetOOFAtPoint (x, y, context);
+ break;
+
+ case SL_SC_TOP:
+ if (stackingContextMgr)
+ widgetAtPoint =
+ stackingContextMgr->getTopWidgetAtPoint (x, y, context);
+ break;
+
+ default:
+ assertNotReached ();
+ }
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y,
+ GettingWidgetAtPointContext
+ *context)
+{
+ Widget *widgetAtPoint = NULL;
+
+ for (int i = NUM_OOFM -1; widgetAtPoint == NULL && i >= 0; i--) {
+ if(outOfFlowMgr[i])
+ widgetAtPoint = outOfFlowMgr[i]->getWidgetAtPoint (x, y, context);
+ }
+
+ return widgetAtPoint;
+}
+
+void OOFAwareWidget::removeChild (Widget *child)
+{
+ // Sub classes should implement this method (and Textblock and
+ // Table do so), so this point is only reached from
+ // ~OOFAwareWidget, which removes widgets out of flow.
+ assert (isWidgetOOF (child));
+}
+
+bool OOFAwareWidget::mustBeWidenedToAvailWidth ()
+{
+ // Only used for floats.
+ assertNotReached ();
+ return false;
+}
+
+void OOFAwareWidget::borderChanged (int y, Widget *vloat)
+{
+ assertNotReached ();
+}
+
+void OOFAwareWidget::widgetRefSizeChanged (int externalIndex)
+{
+ assertNotReached ();
+}
+
+void OOFAwareWidget::clearPositionChanged ()
+{
+ assertNotReached ();
+}
+
+void OOFAwareWidget::oofSizeChanged (bool extremesChanged)
+{
+ DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s",
+ extremesChanged ? "true" : "false");
+ queueResize (-1, extremesChanged);
+
+ // Extremes changes may become also relevant for the children.
+ if (extremesChanged)
+ containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+int OOFAwareWidget::getLineBreakWidth ()
+{
+ assertNotReached ();
+ return 0;
+}
+
+bool OOFAwareWidget::isPossibleContainer (int oofmIndex)
+{
+ return oofmIndex != OOFM_FLOATS;
+}
+
+bool OOFAwareWidget::isPossibleContainerParent (int oofmIndex)
+{
+ return oofmIndex != OOFM_FLOATS;
+}
+
+bool OOFAwareWidget::adjustExtraSpaceWhenCorrectingRequisitionByOOF ()
+{
+ return true;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh
new file mode 100644
index 00000000..3946c72b
--- /dev/null
+++ b/dw/oofawarewidget.hh
@@ -0,0 +1,264 @@
+#ifndef __DW_OOFAWAREWIDGET_HH__
+#define __DW_OOFAWAREWIDGET_HH__
+
+#include "core.hh"
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+/**
+ * \brief Base class for widgets which can act as container and
+ * generator for widgets out of flow.
+ *
+ * (Perhaps it should be diffenciated between the two roles, container
+ * and generator, but this would make multiple inheritance necessary.)
+ *
+ * See \ref dw-out-of-flow for an overview.
+ *
+ * Requirements for sub classes (in most cases refer to dw::Textblock
+ * as a good example):
+ *
+ * - A sub class should at least take care to call these methods at the
+ * respective points:
+ *
+ * - dw::oof::OOFAwareWidget::correctRequisitionByOOF (from
+ * dw::core::Widget::getExtremesImpl)
+ * - dw::oof::OOFAwareWidget::correctExtremesByOOF (from
+ * dw::core::Widget::sizeRequestImpl)
+ * - dw::oof::OOFAwareWidget::sizeAllocateStart
+ * - dw::oof::OOFAwareWidget::sizeAllocateEnd (latter two from
+ * dw::core::Widget::sizeAllocateImpl)
+ * - dw::oof::OOFAwareWidget::containerSizeChangedForChildrenOOF
+ * (from dw::core::Widget::containerSizeChangedForChildren)
+ * - dw::oof::OOFAwareWidget::drawOOF (from dw::core::Widget::draw)
+ * - dw::oof::OOFAwareWidget::getWidgetOOFAtPoint (from
+ * dw::core::Widget::getWidgetAtPoint)
+ *
+ * - Implementations of dw::core::Widget::getAvailWidthOfChild and
+ * dw::core::Widget::getAvailHeightOfChild have to distinguish
+ * between widgets in flow and out of flow; general pattern:
+ *
+ * \code
+ * if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
+ * getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ * width =
+ * getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
+ * else {
+ * // ... specific implementation ...
+ * \endcode
+ *
+ * See also implementations of dw::Textblock and dw::Table. (Open
+ * issue: What about dw::core::Widget::correctRequisitionOfChild and
+ * dw::core::Widget::correctExtremesOfChild? Currently, all widgets
+ * are used the default implementation.)
+ *
+ * - Iterators have to consider widgets out of flow;
+ * dw::oof::OOFAwareWidget::OOFAwareWidgetIterator is recommended as
+ * base class.
+ *
+ * - dw::core::Widget::parentRef has to be set for widgets in flow; if
+ * not used further, a simple *makeParentRefInFlow(0)* is sufficient
+ * (as dw::Table::addCell does). Widgets which are only containers,
+ * but not generators, do not have to care about widgets out of
+ * flow in this regard.
+ *
+ * For both generators and containers of floats (which is only
+ * implemented by dw::Textblock) it gets a bit more complicated.
+ *
+ * \todo Currently, on the level of dw::oof::OOFAwareWidget, nothing
+ * is done about dw::core::Widget::markSizeChange and
+ * dw::core::Widget::markExtremesChange. This does not matter, though:
+ * dw::Textblock takes care of these, and dw::Table is only connected
+ * to subclasses of dw::oof::OOFPositionedMgr, which do care about
+ * these. However, this should be considered for completeness.
+ */
+class OOFAwareWidget: public core::Widget
+{
+protected:
+ enum { OOFM_FLOATS, OOFM_ABSOLUTE, OOFM_RELATIVE, OOFM_FIXED, NUM_OOFM };
+ static const char *OOFM_NAME[NUM_OOFM];
+ enum { PARENT_REF_OOFM_BITS = 3,
+ PARENT_REF_OOFM_MASK = (1 << PARENT_REF_OOFM_BITS) - 1 };
+
+ class OOFAwareWidgetIterator: public core::Iterator
+ {
+ private:
+ enum { NUM_SECTIONS = NUM_OOFM + 1 };
+ int sectionIndex; // 0 means in flow, otherwise OOFM index + 1
+ int index;
+
+ int numParts (int sectionIndex, int numContentsInFlow = -1);
+ void getPart (int sectionIndex, int index, core::Content *content);
+
+ protected:
+ virtual int numContentsInFlow () = 0;
+ virtual void getContentInFlow (int index, core::Content *content) = 0;
+
+ void setValues (int sectionIndex, int index);
+ inline void cloneValues (OOFAwareWidgetIterator *other)
+ { other->setValues (sectionIndex, index); }
+
+ inline bool inFlow () { return sectionIndex == 0; }
+ inline int getInFlowIndex () { assert (inFlow ()); return index; }
+ void highlightOOF (int start, int end, core::HighlightLayer layer);
+ void unhighlightOOF (int direction, core::HighlightLayer layer);
+ void getAllocationOOF (int start, int end, core::Allocation *allocation);
+
+ public:
+ OOFAwareWidgetIterator (OOFAwareWidget *widget, core::Content::Type mask,
+ bool atEnd, int numContentsInFlow);
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+ int compareTo(lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ };
+
+ inline bool isParentRefOOF (int parentRef)
+ { return parentRef != -1 && (parentRef & PARENT_REF_OOFM_MASK); }
+
+ inline int makeParentRefInFlow (int inFlowSubRef)
+ { return (inFlowSubRef << PARENT_REF_OOFM_BITS); }
+ inline int getParentRefInFlowSubRef (int parentRef)
+ { assert (!isParentRefOOF (parentRef));
+ return parentRef >> PARENT_REF_OOFM_BITS; }
+
+ inline int makeParentRefOOF (int oofmIndex, int oofmSubRef)
+ { return (oofmSubRef << PARENT_REF_OOFM_BITS) | (oofmIndex + 1); }
+ inline int getParentRefOOFSubRef (int parentRef)
+ { assert (isParentRefOOF (parentRef));
+ return parentRef >> PARENT_REF_OOFM_BITS; }
+ inline int getParentRefOOFIndex (int parentRef)
+ { assert (isParentRefOOF (parentRef));
+ return (parentRef & PARENT_REF_OOFM_MASK) - 1; }
+ inline oof::OutOfFlowMgr *getParentRefOutOfFlowMgr (int parentRef)
+ { return outOfFlowMgr[getParentRefOOFIndex (parentRef)]; }
+
+ inline bool isWidgetOOF (Widget *widget)
+ { return isParentRefOOF (widget->parentRef); }
+
+ inline int getWidgetInFlowSubRef (Widget *widget)
+ { return getParentRefInFlowSubRef (widget->parentRef); }
+
+ inline int getWidgetOOFSubRef (Widget *widget)
+ { return getParentRefOOFSubRef (widget->parentRef); }
+ inline int getWidgetOOFIndex (Widget *widget)
+ { return getParentRefOOFIndex (widget->parentRef); }
+ inline oof::OutOfFlowMgr *getWidgetOutOfFlowMgr (Widget *widget)
+ { return getParentRefOutOfFlowMgr (widget->parentRef); }
+
+ OOFAwareWidget *oofContainer[NUM_OOFM];
+ OutOfFlowMgr *outOfFlowMgr[NUM_OOFM];
+ core::Requisition requisitionWithoutOOF;
+
+ inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex)
+ { return oofContainer[oofmIndex] ?
+ oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; }
+
+ static int getOOFMIndex (Widget *widget);
+
+ void initOutOfFlowMgrs ();
+ void correctRequisitionByOOF (core::Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremesByOOF (core::Extremes *extremes);
+ void sizeAllocateStart (core::Allocation *allocation);
+ void sizeAllocateEnd ();
+ void containerSizeChangedForChildrenOOF ();
+
+ virtual void drawLevel (core::View *view, core::Rectangle *area, int level,
+ core::DrawingContext *context);
+ void drawOOF (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
+
+ Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *context);
+ virtual Widget *getWidgetAtPointLevel (int x, int y, int level,
+ core::GettingWidgetAtPointContext
+ *context);
+ Widget *getWidgetOOFAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *context);
+
+ static bool isOOFContainer (Widget *widget, int oofmIndex);
+
+ void notifySetAsTopLevel();
+ void notifySetParent();
+
+ void removeChild (Widget *child);
+
+public:
+ enum {
+ SL_START, SL_BACKGROUND, SL_SC_BOTTOM, SL_IN_FLOW, SL_OOF_REF,
+ SL_OOF_CONT, SL_SC_TOP, SL_END };
+
+ static int CLASS_ID;
+
+ OOFAwareWidget ();
+ ~OOFAwareWidget ();
+
+ static const char *stackingLevelText (int level);
+
+ static inline bool testStyleFloat (core::style::Style *style)
+ { return style->vloat != core::style::FLOAT_NONE; }
+
+ static inline bool testStyleAbsolutelyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_ABSOLUTE; }
+ static inline bool testStyleFixedlyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_FIXED; }
+ static inline bool testStyleRelativelyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_RELATIVE; }
+
+ static inline bool testStylePositioned (core::style::Style *style)
+ { return testStyleAbsolutelyPositioned (style) ||
+ testStyleRelativelyPositioned (style) ||
+ testStyleFixedlyPositioned (style); }
+
+ static inline bool testStyleOutOfFlow (core::style::Style *style)
+ { // Second part is equivalent to testStylePositioned(), but we still keep
+ // the two seperately.
+ return testStyleFloat (style) || testStyleAbsolutelyPositioned (style)
+ || testStyleRelativelyPositioned (style)
+ || testStyleFixedlyPositioned (style); }
+
+ static inline bool testWidgetFloat (Widget *widget)
+ { return testStyleFloat (widget->getStyle ()); }
+
+ static inline bool testWidgetAbsolutelyPositioned (Widget *widget)
+ { return testStyleAbsolutelyPositioned (widget->getStyle ()); }
+ static inline bool testWidgetFixedlyPositioned (Widget *widget)
+ { return testStyleFixedlyPositioned (widget->getStyle ()); }
+ static inline bool testWidgetRelativelyPositioned (Widget *widget)
+ { return testStyleRelativelyPositioned (widget->getStyle ()); }
+
+ static inline bool testWidgetPositioned (Widget *widget)
+ { return testStylePositioned (widget->getStyle ()); }
+
+ static inline bool testWidgetOutOfFlow (Widget *widget)
+ { return testStyleOutOfFlow (widget->getStyle ()); }
+
+ inline core::Requisition *getRequisitionWithoutOOF ()
+ { return &requisitionWithoutOOF; }
+
+ bool doesWidgetOOFInterruptDrawing (Widget *widget);
+
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
+
+ virtual bool mustBeWidenedToAvailWidth ();
+ virtual void borderChanged (int y, core::Widget *vloat);
+ virtual void widgetRefSizeChanged (int externalIndex);
+ virtual void clearPositionChanged ();
+ virtual void oofSizeChanged (bool extremesChanged);
+ virtual int getLineBreakWidth (); // Should perhaps be renamed.
+ virtual bool isPossibleContainer (int oofmIndex);
+ virtual bool isPossibleContainerParent (int oofmIndex);
+ virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFAWAREWIDGET_HH__
diff --git a/dw/oofawarewidget_iterator.cc b/dw/oofawarewidget_iterator.cc
new file mode 100644
index 00000000..afafb5d5
--- /dev/null
+++ b/dw/oofawarewidget_iterator.cc
@@ -0,0 +1,261 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofawarewidget.hh"
+#include "ooffloatsmgr.hh"
+#include "oofposabsmgr.hh"
+#include "oofposfixedmgr.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace lout::misc;
+using namespace lout::object;
+
+namespace dw {
+
+namespace oof {
+
+// "numContentsInFlow" is passed here to avoid indirectly callin the (virtual)
+// method numContentsInFlow() from the constructor.
+OOFAwareWidget::OOFAwareWidgetIterator::OOFAwareWidgetIterator
+ (OOFAwareWidget *widget, Content::Type mask, bool atEnd,
+ int numContentsInFlow) :
+ Iterator (widget, mask, atEnd)
+{
+ if (atEnd) {
+ sectionIndex = NUM_SECTIONS - 1;
+ while (sectionIndex >= 0 &&
+ numParts (sectionIndex, numContentsInFlow) == 0)
+ sectionIndex--;
+ index = numParts (sectionIndex, numContentsInFlow);
+ } else {
+ sectionIndex = 0;
+ index = -1;
+ }
+
+ content.type = atEnd ? core::Content::END : core::Content::START;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::setValues (int sectionIndex,
+ int index)
+{
+ this->sectionIndex = sectionIndex;
+ this->index = index;
+
+ if (sectionIndex == 0 && index < 0)
+ content.type = core::Content::START;
+ else if (sectionIndex == NUM_SECTIONS - 1 &&
+ index >= numParts (sectionIndex))
+ content.type = core::Content::END;
+ else
+ getPart (sectionIndex, index, &content);
+}
+
+int OOFAwareWidget::OOFAwareWidgetIterator::numParts (int sectionIndex,
+ int numContentsInFlow)
+{
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget(), "numParts", "%d, %d",
+ sectionIndex, numContentsInFlow);
+
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+ int result;
+
+ if (sectionIndex == 0)
+ result = numContentsInFlow == -1 ?
+ this->numContentsInFlow () : numContentsInFlow;
+ else
+ result = widget->outOfFlowMgr[sectionIndex - 1] ?
+ widget->outOfFlowMgr[sectionIndex - 1]->getNumWidgets () : 0;
+
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget(), "=> %d", result);
+ DBG_OBJ_LEAVE_O (getWidget());
+ return result;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::getPart (int sectionIndex,
+ int index,
+ Content *content)
+{
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+
+ if (sectionIndex == 0)
+ getContentInFlow (index, content);
+ else {
+ content->type = Content::WIDGET_OOF_CONT;
+ content->widget =
+ widget->outOfFlowMgr[sectionIndex - 1]->getWidget (index);
+ }
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::intoStringBuffer (StringBuffer *sb)
+{
+ Iterator::intoStringBuffer (sb);
+ sb->append (", sectionIndex = ");
+ sb->appendInt (sectionIndex);
+ sb->append (", index = ");
+ sb->appendInt (index);
+}
+
+int OOFAwareWidget::OOFAwareWidgetIterator::compareTo (Comparable *other)
+{
+ OOFAwareWidgetIterator *otherTI = (OOFAwareWidgetIterator*)other;
+
+ if (sectionIndex != otherTI->sectionIndex)
+ return sectionIndex - otherTI->sectionIndex;
+ else
+ return index - otherTI->index;
+}
+
+bool OOFAwareWidget::OOFAwareWidgetIterator::next ()
+{
+ DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (),
+ "OOFAwareWidgetIterator/next");
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s",
+ sb.getChars ());
+ }
+
+ bool r;
+
+ if (content.type == Content::END)
+ r = false;
+ else {
+ r = true;
+ bool cancel = false;
+
+ do {
+ index++;
+
+ if (index < numParts(sectionIndex))
+ getPart (sectionIndex, index, &content);
+ else {
+ sectionIndex++;
+ while (sectionIndex < NUM_SECTIONS && numParts (sectionIndex) == 0)
+ sectionIndex++;
+
+ if (sectionIndex == NUM_SECTIONS) {
+ content.type = Content::END;
+ r = false;
+ cancel = true;
+ } else {
+ index = 0;
+ getPart (sectionIndex, index, &content);
+ }
+ }
+ } while (!cancel && (content.type & getMask()) == 0);
+ }
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s",
+ sb.getChars ());
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s",
+ r ? "true" : "false");
+ }
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+ return r;
+}
+
+bool OOFAwareWidget::OOFAwareWidgetIterator::prev ()
+{
+ DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (),
+ "OOFAwareWidgetIterator/prev");
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s",
+ sb.getChars ());
+ }
+
+ bool r;
+
+ if (content.type == Content::START)
+ r = false;
+ else {
+ r = true;
+ bool cancel = false;
+
+ do {
+ index--;
+
+ if (index >= 0)
+ getPart (sectionIndex, index, &content);
+ else {
+ sectionIndex--;
+ while (sectionIndex >= 0 && numParts (sectionIndex) == 0)
+ sectionIndex--;
+
+ if (sectionIndex < 0) {
+ content.type = Content::START;
+ r = false;
+ cancel = true;
+ } else {
+ index = numParts (sectionIndex) - 1;
+ getPart (sectionIndex, index, &content);
+ }
+ }
+ } while (!cancel && (content.type & getMask()) == 0);
+ }
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s",
+ sb.getChars ());
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s",
+ r ? "true" : "false");
+ }
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+ return r;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::highlightOOF (int start, int end,
+ HighlightLayer layer)
+{
+ // TODO What about OOF widgets?
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::unhighlightOOF (int direction,
+ HighlightLayer
+ layer)
+{
+ // TODO What about OOF widgets?
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::getAllocationOOF (int start,
+ int end,
+ Allocation
+ *allocation)
+{
+ // TODO Consider start and end?
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+ *allocation = *(widget->outOfFlowMgr[sectionIndex - 1]
+ ->getWidget(index)->getAllocation());
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc
new file mode 100644
index 00000000..e804138c
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,2370 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ooffloatsmgr.hh"
+#include "oofawarewidget.hh"
+#include "../lout/debug.hh"
+
+#include <limits.h>
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace dw {
+
+namespace oof {
+
+OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget)
+{
+ this->oofm = oofm;
+ this->widget = widget;
+ wasAllocated = false;
+ xCB = yCB = width = height = -1;
+}
+
+void OOFFloatsMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
+ int width, int height)
+{
+ DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
+ wasAllocated ? "true" : "false", xCB, yCB, width, height);
+
+ this->wasAllocated = wasAllocated;
+ this->xCB = xCB;
+ this->yCB = yCB;
+ this->width = width;
+ this->height = height;
+
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
+
+ DBG_OBJ_LEAVE_O (widget);
+}
+
+// ----------------------------------------------------------------------
+
+OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex)
+ : WidgetInfo (oofm, widget)
+{
+ this->generatingBlock = generatingBlock;
+ this->externalIndex = externalIndex;
+
+ yReq = yReal = size.width = size.ascent = size.descent = 0;
+ dirty = sizeChangedSinceLastAllocation = true;
+ indexGBList = indexCBList = -1;
+
+ // Sometimes a float with widget = NULL is created as a key; this
+ // is not interesting for RTFL.
+ if (widget) {
+ DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
+ sizeChangedSinceLastAllocation);
+ }
+}
+
+void OOFFloatsMgr::Float::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ sb->appendPointer (getWidget ());
+
+ if (getWidget ()) {
+ sb->append (" (");
+ sb->append (getWidget()->getClassName ());
+ sb->append (")");
+ }
+
+ sb->append (", indexGBList = ");
+ sb->appendInt (indexGBList);
+ sb->append (", indexCBList = ");
+ sb->appendInt (indexCBList);
+ sb->append (", sideSpanningIndex = ");
+ sb->appendInt (sideSpanningIndex);
+ sb->append (", generatingBlock = ");
+ sb->appendPointer (generatingBlock);
+ sb->append (", yReq = ");
+ sb->appendInt (yReq);
+ sb->append (", yReal = ");
+ sb->appendInt (yReal);
+ sb->append (", size = { ");
+ sb->appendInt (size.width);
+ sb->append (" * ");
+ sb->appendInt (size.ascent);
+ sb->append (" + ");
+ sb->appendInt (size.descent);
+ sb->append (" }, dirty = ");
+ sb->appendBool (dirty);
+ sb->append (", sizeChangedSinceLastAllocation = ");
+ sb->appendBool (sizeChangedSinceLastAllocation);
+ sb->append (" }");
+}
+
+bool OOFFloatsMgr::Float::covers (OOFAwareWidget *textblock, int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%p, %d, %d [vloat: %p]",
+ textblock, y, h, getWidget ());
+
+ bool b;
+
+ if (textblock == generatingBlock) {
+ int reqyGB = y;
+ int flyGB = yReal;
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ int flh = size.ascent + size.descent;
+ b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "for generator: reqyGB = %d, flyGB = %d, "
+ "flh = %d + %d = %d => %s",
+ reqyGB, flyGB, size.ascent, size.descent, flh,
+ b ? "true" : "false");
+ } else {
+ // (If the textblock were not allocated, the GB list would have
+ // been choosen instead of the CB list, and so this else-branch
+ // would not have been not executed.)
+ assert (getOOFFloatsMgr()->wasAllocated (textblock));
+
+ if (!getWidget()->wasAllocated ()) {
+ DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (not allocated) => false");
+ b = false;
+ } else {
+ Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock),
+ *fla = getWidget()->getAllocation ();
+ int reqyCanv = tba->y + y;
+ int flyCanv = fla->y;
+ int flh = fla->ascent + fla->descent;
+ b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (allocated): reqyCanv = %d + %d = %d, "
+ "flyCanv = %d, flh = %d + %d = %d => %s",
+ tba->y, y, reqyCanv, flyCanv,
+ fla->ascent, fla->descent, flh, b ? "true" : "false");
+ }
+ }
+
+ DBG_OBJ_LEAVE_O (getOOFFloatsMgr ());
+
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
+ int r;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm,
+ "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
+ fl1->getIndex (type), fl2->getIndex (type), refTB);
+
+ if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
+ r = fl1->yReal - fl2->yReal;
+ } else {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
+ fl1->generatingBlock, fl2->generatingBlock);
+
+ // (i) Floats may not yet been allocated. Non-allocated floats
+ // do not have an effect yet, they are considered "at the end"
+ // of the list.
+
+ // (ii) Float::widget is NULL for the key used for binary
+ // search. In this case, Float::yReal is used instead (which is
+ // set in SortedFloatsVector::find, too). The generator is the
+ // textblock, and should be allocated. (If not, the GB list
+ // would have been choosen instead of the CB list, and so this
+ // else-branch would not have been not executed.)
+
+ bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
+ bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
+ fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
+ a2 ? "yes" : "no");
+
+ if (a1 && a2) {
+ int fly1, fly2;
+
+ if (fl1->getWidget()) {
+ fly1 = fl1->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
+ } else {
+ assert (oofm->wasAllocated (fl1->generatingBlock));
+ fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
+ oofm->getAllocation(fl1->generatingBlock)->y,
+ fl1->yReal, fly1);
+ }
+
+ if (fl2->getWidget()) {
+ fly2 = fl2->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
+ } else {
+ assert (oofm->wasAllocated (fl2->generatingBlock));
+ fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
+ oofm->getAllocation(fl2->generatingBlock)->y,
+ fl2->yReal, fly2);
+ }
+
+ r = fly1 - fly2;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
+ } else if (a1 && !a2)
+ r = -1;
+ else if (!a1 && a2)
+ r = +1;
+ else // if (!a1 && !a2)
+ return 0;
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
+ Object *o2)
+{
+ return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
+}
+
+int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
+{
+ Float *f1 = (Float*)o1, *f2 = (Float*)o2;
+ int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex::compare",
+ "#%d -> %p/%d, #%d -> %p/#%d",
+ f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
+ f2->getIndex (type), f2->generatingBlock,
+ f2->externalIndex);
+
+ if (f1->generatingBlock == f2->generatingBlock) {
+ r = f1->externalIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(a) generating blocks equal => %d - %d = %d",
+ f1->externalIndex, f2->externalIndex, r);
+ } else {
+ TBInfo *t1 = oofm->getOOFAwareWidget (f1->generatingBlock),
+ *t2 = oofm->getOOFAwareWidget (f2->generatingBlock);
+ bool rdef = false;
+
+ for (TBInfo *t = t1; t != NULL; t = t->parent)
+ if (t->parent == t2) {
+ rdef = true;
+ r = t->parentExtIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(b) %p is an achestor of %p; direct child is "
+ "%p (%d) => %d - %d = %d\n",
+ t2->getOOFAwareWidget (), t1->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ t->parentExtIndex, f2->externalIndex, r);
+ }
+
+ for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
+ if (t->parent == t1) {
+ r = f1->externalIndex - t->parentExtIndex;
+ rdef = true;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(c) %p is an achestor of %p; direct child is %p "
+ "(%d) => %d - %d = %d\n",
+ t1->getOOFAwareWidget (), t2->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ f1->externalIndex, t->parentExtIndex, r);
+ }
+
+ if (!rdef) {
+ r = t1->index - t2->index;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
+ t1->index, t2->index, r);
+ }
+ }
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
+ lastGB, lastExtIndex);
+
+ Float key (oofm, NULL, lastGB, lastExtIndex);
+ key.setIndex (type, -1); // for debugging
+ Float::CompareGBAndExtIndex comparator (oofm, type);
+ int i = bsearch (&key, false, &comparator);
+
+ // At position i is the next larger element, so element i should
+ // not included, but i - 1 returned; except if the exact element is
+ // found: then include it and so return i.
+ int r;
+ if (i == size())
+ r = i - 1;
+ else {
+ Float *f = get (i);
+ if (comparator.compare (f, &key) == 0)
+ r = i;
+ else
+ r = i - 1;
+ }
+
+ //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
+ // "in %s list %p on the %s side\n",
+ // oofm->container, lastGB, lastExtIndex, i, r, size (),
+ // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
+
+ //for (int i = 0; i < size (); i++) {
+ // Float *f = get(i);
+ // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock);
+ // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
+ // t->index, t->parent ? t->parent->textblock : NULL,
+ // get(i)->externalIndex);
+ //}
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::find (OOFAwareWidget *textblock, int y,
+ int start, int end)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d",
+ textblock, y, start, end);
+
+ Float key (oofm, NULL, NULL, 0);
+ key.generatingBlock = textblock;
+ key.yReal = y;
+ key.setIndex (type, -1); // for debugging
+ Float::ComparePosition comparator (oofm, textblock, type);
+ int result = bsearch (&key, false, start, end, &comparator);
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFirst (OOFAwareWidget *textblock,
+ int y, int h,
+ OOFAwareWidget *lastGB,
+ int lastExtIndex,
+ int *lastReturn)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d",
+ textblock, y, h, lastGB, lastExtIndex);
+
+ DBG_IF_RTFL {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ for (int i = 0; i < size(); i++) {
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), "
+ "%s, %s, ext = %d, GB = %p); widget at (%d, %d)",
+ i, get(i)->getWidget (), get(i)->getIndex (type),
+ get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal,
+ get(i)->size.width, get(i)->size.ascent,
+ get(i)->size.descent,
+ get(i)->dirty ? "dirty" : "clean",
+ get(i)->sizeChangedSinceLastAllocation ? "scsla"
+ : "sNcsla",
+ get(i)->externalIndex, get(i)->generatingBlock,
+ get(i)->getWidget()->getAllocation()->x,
+ get(i)->getWidget()->getAllocation()->y);
+ }
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ int last = findFloatIndex (lastGB, lastExtIndex);
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last);
+ assert (last < size());
+
+ // If the caller wants to reuse this value:
+ if (lastReturn)
+ *lastReturn = last;
+
+ int i = find (textblock, y, 0, last), result;
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i);
+
+ // Note: The smallest value of "i" is 0, which means that "y" is before or
+ // equal to the first float. The largest value is "last + 1", which means
+ // that "y" is after the last float. In both cases, the first or last,
+ // respectively, float is a candidate. Generally, both floats, before and
+ // at the search position, are candidates.
+
+ if (i > 0 && get(i - 1)->covers (textblock, y, h))
+ result = i - 1;
+ else if (i <= last && get(i)->covers (textblock, y, h))
+ result = i;
+ else
+ result = -1;
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex
+ (int sideSpanningIndex)
+{
+ OOFFloatsMgr::Float::CompareSideSpanningIndex comparator;
+ Float key (NULL, NULL, NULL, 0);
+ key.sideSpanningIndex = sideSpanningIndex;
+ return bsearch (&key, false, &comparator) - 1;
+}
+
+void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat)
+{
+ lout::container::typed::Vector<Float>::put (vloat);
+ vloat->setIndex (type, size() - 1);
+}
+
+OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex) :
+ WidgetInfo (oofm, textblock)
+{
+ this->parent = parent;
+ this->parentExtIndex = parentExtIndex;
+
+ leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB);
+ rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB);
+
+ wasAllocated = getWidget()->wasAllocated ();
+ allocation = *(getWidget()->getAllocation ());
+ clearPosition = 0;
+}
+
+OOFFloatsMgr::TBInfo::~TBInfo ()
+{
+ delete leftFloatsGB;
+ delete rightFloatsGB;
+}
+
+void OOFFloatsMgr::TBInfo::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container)
+{
+ DBG_OBJ_CREATE ("dw::OOFFloatsMgr");
+
+ this->container = (OOFAwareWidget*)container;
+
+ leftFloatsCB = new SortedFloatsVector (this, LEFT, CB);
+ rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB);
+
+ DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
+ DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
+
+ leftFloatsAll = new Vector<Float> (1, true);
+ rightFloatsAll = new Vector<Float> (1, true);
+
+ DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+
+ floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
+
+ tbInfos = new Vector<TBInfo> (1, false);
+ tbInfosByOOFAwareWidget =
+ new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true);
+
+ leftFloatsMark = rightFloatsMark = 0;
+ lastLeftTBIndex = lastRightTBIndex = 0;
+
+ containerWasAllocated = container->wasAllocated ();
+ containerAllocation = *(container->getAllocation());
+
+ addWidgetInFlow (this->container, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ //printf ("OOFFloatsMgr::~OOFFloatsMgr\n");
+
+ delete leftFloatsCB;
+ delete rightFloatsCB;
+
+ // Order is important: tbInfosByOOFAwareWidget is owner of the instances
+ // of TBInfo.tbInfosByOOFAwareWidget
+ delete tbInfos;
+ delete tbInfosByOOFAwareWidget;
+
+ delete floatsByWidget;
+
+ // Order is important, since the instances of Float are owned by
+ // leftFloatsAll and rightFloatsAll, so these should be deleted
+ // last.
+ delete leftFloatsAll;
+ delete rightFloatsAll;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ // Some callers are not registered, especially tables. (Where the
+ // floats manager is actually empty?)
+ TBInfo *oofAWInfo = getOOFAwareWidgetWhenRegistered (caller);
+ if (oofAWInfo) {
+ oofAWInfo->allocation = *allocation;
+ oofAWInfo->wasAllocated = true;
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *first* OOFM method
+ // called is sizeAllocateStart, with the containing block as an
+ // argument. So this is the correct point to initialize size
+ // allocation.
+
+ containerWasAllocated = true;
+ containerAllocation = *allocation;
+
+ // Move floats from GB lists to the one CB list.
+ moveFromGBToCB (LEFT);
+ moveFromGBToCB (RIGHT);
+
+ // These attributes are used to keep track which floats have
+ // been allocated (referring to leftFloatsCB and rightFloatsCB).
+ lastAllocatedLeftFloat = lastAllocatedRightFloat = -1;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (isOOFAwareWidgetRegistered (caller)) {
+ if (caller != container) {
+ // Allocate all floats "before" this textblock.
+ sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
+ sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
+ }
+
+ // The checks below do not cover "clear position" in all cases,
+ // so this is done here separately. This position is stored in
+ // TBInfo and calculated at this points; changes will be noticed
+ // to the textblock.
+ TBInfo *tbInfo = getOOFAwareWidget (caller);
+ int newClearPosition = calcClearPosition (caller);
+ if (newClearPosition != tbInfo->clearPosition) {
+ tbInfo->clearPosition = newClearPosition;
+ caller->clearPositionChanged ();
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *last* OOFM method called
+ // is sizeAllocateEnd, with the containing block as an
+ // argument. So this is the correct point to finish size
+ // allocation.
+
+ // Allocate all remaining floats.
+ sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1);
+ sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1);
+
+ // Check changes of both textblocks and floats allocation. (All
+ // is checked by hasRelationChanged (...).)
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ int minFloatPos;
+ Widget *minFloat;
+ if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
+ tb->borderChanged (minFloatPos, minFloat);
+ }
+
+ checkAllocatedFloatCollisions (LEFT);
+ checkAllocatedFloatCollisions (RIGHT);
+
+ // Store some information for later use.
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ tbInfo->updateAllocation ();
+ tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
+ }
+
+ // There are cases where some allocated floats exceed the CB size.
+ bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT);
+
+ // Similar for extremes.
+ bool extremesChanged =
+ haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT);
+
+ for (int i = 0; i < leftFloatsCB->size(); i++)
+ leftFloatsCB->get(i)->updateAllocation ();
+
+ for (int i = 0; i < rightFloatsCB->size(); i++)
+ rightFloatsCB->get(i)->updateAllocation ();
+
+ if (sizeChanged || extremesChanged)
+ container->oofSizeChanged (extremesChanged);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < leftFloatsAll->size (); i++)
+ leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloatsAll->size (); i++)
+ rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
+ Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, ...", tbInfo->getWidget ());
+
+ int leftMinPos, rightMinPos;
+ Widget *leftMinFloat, *rightMinFloat;
+ bool c1 =
+ hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
+ bool c2 =
+ hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
+ if (c1 || c2) {
+ if (!c1) {
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ } else if (!c2) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else {
+ if (leftMinPos < rightMinPos) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else{
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ }
+ }
+ }
+
+ if (c1 || c2)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "has changed: minFloatPos = %d, minFloat = %p",
+ *minFloatPos, *minFloat);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+ return c1 || c2;
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
+ int *minFloatPos, Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, %s, ...",
+ tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size(); i++) {
+ // TODO binary search?
+ Float *vloat = list->get(i);
+ int floatPos;
+
+ if (tbInfo->getOOFAwareWidget () == vloat->generatingBlock)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "not checking (generating!) textblock %p against float "
+ "%p", tbInfo->getWidget (), vloat->getWidget ());
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+
+ int newFlx = calcFloatX (vloat, side,
+ gba->x - containerAllocation.x,
+ getGBWidthForAllocation (vloat));
+ int newFly = vloat->generatingBlock->getAllocation()->y
+ - containerAllocation.y + vloat->yReal;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "checking textblock %p against float %p",
+ tbInfo->getWidget (), vloat->getWidget ());
+ DBG_OBJ_MSG_START ();
+
+ if (hasRelationChanged (tbInfo->wasThenAllocated (),
+ tbInfo->getOldXCB (), tbInfo->getOldYCB (),
+ tbInfo->getNewWidth (),
+ tbInfo->getNewHeight (),
+ tbInfo->getNewXCB (), tbInfo->getNewYCB (),
+ tbInfo->getNewWidth (),
+ tbInfo->getNewHeight (),
+ vloat->wasThenAllocated (),
+ // When not allocated before, these values
+ // are undefined, but this does not matter,
+ // since they are neither used.
+ vloat->getOldXCB (), vloat->getOldYCB (),
+ vloat->getOldWidth (), vloat->getOldHeight (),
+ newFlx, newFly, vloat->size.width,
+ vloat->size.ascent + vloat->size.descent,
+ side, &floatPos)) {
+ if (!changed || floatPos < *minFloatPos) {
+ *minFloatPos = floatPos;
+ *minFloat = vloat->getWidget ();
+ }
+ changed = true;
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 0, "No.");
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ // All floarts are searched, to find the minimum. TODO: Are
+ // floats sorted, so this can be shortened? (The first is the
+ // minimum?)
+ }
+
+ if (changed)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "has changed: minFloatPos = %d, minFloat = %p",
+ *minFloatPos, *minFloat);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+ return changed;
+}
+
+/**
+ * \brief ...
+ *
+ * All coordinates are given relative to the CB. *floatPos is relative
+ * to the TB, and may be negative.
+ */
+bool OOFFloatsMgr::hasRelationChanged (bool oldTBAlloc,
+ int oldTBx, int oldTBy, int oldTBw,
+ int oldTBh, int newTBx, int newTBy,
+ int newTBw, int newTBh,
+ bool oldFlAlloc,
+ int oldFlx, int oldFly, int oldFlw,
+ int oldFlh, int newFlx, int newFly,
+ int newFlw, int newFlh,
+ Side side, int *floatPos)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT");
+
+ if (oldTBAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d",
+ oldTBx, oldTBy, oldTBw, oldTBh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d",
+ newTBx, newTBy, newTBw, newTBh);
+
+ if (oldFlAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d",
+ oldFlx, oldFly, oldFlw, oldFlh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d",
+ newFlx, newFly, newFlw, newFlh);
+
+ bool result;
+ if (oldTBAlloc && oldFlAlloc) {
+ bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh;
+ bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.",
+ oldCov ? "yes" : "no", newCov ? "yes" : "no");
+ DBG_OBJ_MSG_START ();
+
+ if (oldCov && newCov) {
+ int yOld = oldFly - oldTBy, yNew = newFly - newTBy;
+ if (yOld == yNew) {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d) and new (%d - %d) position equal: %d",
+ oldFly, oldTBy, newFly, newTBy, yOld);
+
+ // Float position has not changed, but perhaps the amout
+ // how far the float reaches into the TB. (TODO:
+ // Generally, not only here, it could be tested whether
+ // the float reaches into the TB at all.)
+ int wOld, wNew;
+ if (side == LEFT) {
+ wOld = oldFlx + oldFlw - oldTBx;
+ wNew = newFlx + newFlw - newTBx;
+ } else {
+ wOld = oldTBx + oldTBw - oldFlx;
+ wNew = newTBx + newTBw - newFlx;
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n",
+ wOld, wNew);
+
+ if (wOld == wNew) {
+ if (oldFlh == newFlh)
+ result = false;
+ else {
+ // Only heights of floats changed. Relevant only
+ // from bottoms of float.
+ *floatPos = min (yOld + oldFlh, yNew + newFlh);
+ result = true;
+ }
+ } else {
+ *floatPos = yOld;
+ result = true;
+ }
+ } else {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d = %d) and new (%d - %d = %d) position "
+ "different",
+ oldFly, oldTBy, yOld, newFly, newTBy, yNew);
+ *floatPos = min (yOld, yNew);
+ result = true;
+ }
+ } else if (oldCov) {
+ *floatPos = oldFly - oldTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning old position: %d - %d = %d", oldFly, oldTBy,
+ *floatPos);
+ } else if (newCov) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning new position: %d - %d = %d", newFly, newTBy,
+ *floatPos);
+ } else
+ result = false;
+
+ DBG_OBJ_MSG_END ();
+ } else {
+ // Not allocated before: ignore all old values, only check whether
+ // TB is covered by Float.
+ if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ } else
+ result = false;
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d",
+ *floatPos);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+
+ return result;
+}
+
+void OOFFloatsMgr::checkAllocatedFloatCollisions (Side side)
+{
+ // In some cases, the collision detection in tellPosition() is
+ // based on the wrong allocations. Here (just after all Floats have
+ // been allocated), we correct this.
+
+ // TODO In some cases this approach is rather slow, causing a too
+ // long queueResize() cascade.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB;
+
+ // While iterating through the list of floats to be checked, we
+ // iterate equally through the list of the opposite floats, using
+ // this index:
+ int oppIndex = 0;
+
+ for (int index = 0; index < list->size (); index++) {
+ Float *vloat = list->get(index);
+ bool needsChange = false;
+ int yRealNew = INT_MAX;
+
+ // Same side.
+ if (index >= 1) {
+ Float *other = list->get(index - 1);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same side: checking %p (#%d, GB: %p) against "
+ "%p (#%d, GB: %p)",
+ vloat->getWidget (), index, vloat->generatingBlock,
+ other->getWidget (), index - 1, other->generatingBlock);
+
+ if (vloat->generatingBlock != other->generatingBlock) {
+ int yRealNewSame;
+ if (collidesV (vloat, other, CB, &yRealNewSame, true)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides, new yReal = %d (old: %d)",
+ yRealNewSame, vloat->yReal);
+ if (vloat->yReal != yRealNewSame) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewSame);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
+ }
+ }
+
+ if (oppList->size () > 0) {
+ // Other side. Iterate to next float on the other side,
+ // before this float.
+ while (oppIndex + 1 < oppList->size () &&
+ oppList->get(oppIndex + 1)->sideSpanningIndex
+ < vloat->sideSpanningIndex)
+ oppIndex++;
+
+ if (oppList->get(oppIndex)->sideSpanningIndex
+ < vloat->sideSpanningIndex) {
+ int oppIndexTmp = oppIndex, yRealNewOpp;
+
+ // Aproach is similar to tellPosition(); see comments
+ // there. Again, loop as long as the vertical dimensions test
+ // is positive (and, of course, there are floats), ...
+ for (bool foundColl = false;
+ !foundColl && oppIndexTmp >= 0 &&
+ collidesV (vloat, oppList->get (oppIndexTmp), CB,
+ &yRealNewOpp, true);
+ oppIndexTmp--) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "opposite side (after collision (v) test): "
+ "checking %p (#%d/%d, GB: %p) against "
+ "%p (#%d/%d, GB: %p)",
+ vloat->getWidget (), index,
+ vloat->sideSpanningIndex,
+ vloat->generatingBlock,
+ oppList->get(oppIndexTmp)->getWidget (),
+ oppList->get(oppIndexTmp)->getIndex (CB),
+ oppList->get(oppIndexTmp)->sideSpanningIndex,
+ oppList->get(oppIndexTmp)->generatingBlock);
+
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides (h), new yReal = %d (old: %d)",
+ yRealNewOpp, vloat->yReal);
+ foundColl = true;
+ if (vloat->yReal != yRealNewOpp) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewOpp);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
+ }
+ }
+ }
+
+ if (needsChange)
+ vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
+ vloat->getWidget ());
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::doFloatsExceedCB (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This method is called to determine whether the *requisition* of
+ // the CB must be recalculated. So, we check the float allocations
+ // against the *requisition* of the CB, which may (e. g. within
+ // tables) differ from the new allocation. (Generally, a widget may
+ // allocated at a different size.)
+ core::Requisition cbReq;
+ container->sizeRequest (&cbReq);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool exceeds = false;
+
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < list->size () && !exceeds; i++) {
+ Float *vloat = list->get (i);
+ if (vloat->getWidget()->wasAllocated ()) {
+ Allocation *fla = vloat->getWidget()->getAllocation ();
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "Does FlA = (%d, %d, %d * %d) exceed CB req+alloc = "
+ "(%d, %d, %d * %d)?",
+ fla->x, fla->y, fla->width, fla->ascent + fla->descent,
+ containerAllocation.x, containerAllocation.y,
+ cbReq.width, cbReq.ascent + cbReq.descent);
+ if (fla->x + fla->width > containerAllocation.x + cbReq.width ||
+ fla->y + fla->ascent + fla->descent
+ > containerAllocation.y + cbReq.ascent + cbReq.descent) {
+ exceeds = true;
+ DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 2, "No.");
+ }
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return exceeds;
+}
+
+bool OOFFloatsMgr::haveExtremesChanged (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This is quite different from doFloatsExceedCB, since there is no
+ // counterpart to getExtremes, as sizeAllocate is a counterpart to
+ // sizeRequest. So we have to determine whether the allocation has
+ // changed the extremes, which is done by examining the part of the
+ // allocation which is part of the extremes calculation (see
+ // getFloatsExtremes). Changes of the extremes are handled by the
+ // normal queueResize mechanism.
+
+ // (This may refer to the old implementation of doFloatsExceedCB,
+ // which checked the container *allocation*, not the *requisition*.
+ //
+ // TODO: (i) Correct the comment. (ii) Is this implementation still
+ // correct, considering the reasoning behind the change of
+ // doFloatsExceedCB?
+ //
+ // See also OOFPositionedMgr::haveExtremesChanged.)
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size () && !changed; i++) {
+ Float *vloat = list->get (i);
+ // When the GB is the CB, an allocation change does not play a
+ // role here.
+ if (vloat->generatingBlock != container) {
+ if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
+ changed = true;
+ else {
+ // This method is called within sizeAllocateEnd, where
+ // containinBlock->getAllocation() (old value) and
+ // containinBlockAllocation (new value) are different.
+
+ Allocation *oldCBA = container->getAllocation ();
+ Allocation *newCBA = &containerAllocation;
+
+ // Compare also to getFloatsExtremes. The box difference
+ // of the GB (from style) has not changed in this context,
+ // so it is ignored.
+
+ int oldDiffLeft = vloat->getOldXCB ();
+ int newDiffLeft = vloat->getNewXCB ();
+ int oldDiffRight =
+ oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
+ int newDiffRight =
+ newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
+
+ if (// regarding minimum
+ (side == LEFT && oldDiffLeft != newDiffLeft) ||
+ (side == RIGHT && oldDiffRight != newDiffRight) ||
+ // regarding maximum
+ oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
+ changed = true;
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return changed;
+}
+
+void OOFFloatsMgr::moveFromGBToCB (Side side)
+{
+ DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
+
+ for (int mark = 0; mark <= *floatsMark; mark++)
+ for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
+ it.hasNext (); ) {
+ TBInfo *tbInfo = it.getNext ();
+ SortedFloatsVector *src =
+ side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ for (int i = 0; i < src->size (); i++) {
+ Float *vloat = src->get (i);
+ // "vloat->indexCBList == -1": prevent copying the vloat twice.
+ if (vloat->indexCBList == -1 && vloat->mark == mark) {
+ dest->put (vloat);
+ DBG_OBJ_MSGF ("oofm.resize", 1,
+ "moving float %p (mark %d) to CB list\n",
+ vloat->getWidget (), vloat->mark);
+ DBG_OBJ_SET_NUM (side == LEFT ?
+ "leftFloatsCB.size" : "rightFloatsCB.size",
+ dest->size());
+ DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
+ "leftFloatsCB" : "rightFloatsCB",
+ dest->size() - 1, "widget",
+ vloat->getWidget ());
+
+ }
+ }
+ }
+
+ *floatsMark = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
+{
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *lastAllocatedFloat =
+ side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
+ "%s, [%d ->] %d [size = %d]",
+ side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
+ newLastAllocatedFloat, list->size ());
+
+ Allocation *cba = &containerAllocation;
+
+ for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
+ Float *vloat = list->get(i);
+ ensureFloatSize (vloat);
+
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+
+ Allocation childAllocation;
+ childAllocation.x = cba->x + calcFloatX (vloat, side, gba->x - cba->x,
+ getGBWidthForAllocation (vloat));
+ childAllocation.y = gba->y + vloat->yReal;
+ childAllocation.width = vloat->size.width;
+ childAllocation.ascent = vloat->size.ascent;
+ childAllocation.descent = vloat->size.descent;
+
+ vloat->getWidget()->sizeAllocate (&childAllocation);
+ }
+
+ *lastAllocatedFloat = newLastAllocatedFloat;
+
+ DBG_OBJ_LEAVE ();
+}
+
+// Used as argument "gbWidth" for calcFloatX(), in the context of allocation.
+int OOFFloatsMgr::getGBWidthForAllocation (Float *vloat)
+{
+ // See comments in getFloatsSize() for a detailed rationale ...
+ if (container->mustBeWidenedToAvailWidth ())
+ return vloat->generatingBlock->getLineBreakWidth ();
+ else
+ // ... but notice this difference: not GB width + float width is
+ // used, but only GB width, since the float width has already
+ // been included in getFloatsSize().
+ return min (getAllocation(vloat->generatingBlock)->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+}
+
+/**
+ * \brief ...
+ *
+ * gbX is given relative to the CB, as is the return value.
+ */
+int OOFFloatsMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth)
+{
+ DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d",
+ vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
+ gbWidth);
+ int x;
+
+ switch (side) {
+ case LEFT:
+ // Left floats are always aligned on the left side of the
+ // generator (content, not allocation) ...
+ x = gbX + vloat->generatingBlock->getStyle()->boxOffsetX();
+ DBG_OBJ_MSGF ("resize.common", 1, "left: x = %d + %d = %d",
+ gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x);
+ // ... but when the float exceeds the line break width of the
+ // container, it is corrected (but not left of the container).
+ // This way, we save space and, especially within tables, avoid
+ // some problems.
+ if (wasAllocated (container) &&
+ x + vloat->size.width > container->getLineBreakWidth ()) {
+ x = max (0, container->getLineBreakWidth () - vloat->size.width);
+ DBG_OBJ_MSGF ("resize.common", 1,
+ "corrected to: max (0, %d - %d) = %d",
+ container->getLineBreakWidth (), vloat->size.width, x);
+ }
+ break;
+
+ case RIGHT:
+ // Similar for right floats, but in this case, floats are
+ // shifted to the right when they are too big (instead of
+ // shifting the generator to the right).
+
+ x = max (gbX + gbWidth - vloat->size.width
+ - vloat->generatingBlock->getStyle()->boxRestWidth(),
+ // Do not exceed CB allocation:
+ 0);
+ DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d",
+ gbX, gbWidth, vloat->size.width,
+ vloat->generatingBlock->getStyle()->boxRestWidth(), x);
+ break;
+
+ default:
+ assertNotReached ();
+ x = 0;
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return x;
+}
+
+void OOFFloatsMgr::draw (View *view, Rectangle *area, DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawFloats (leftFloatsCB, view, area, context);
+ drawFloats (rightFloatsCB, view, area, context);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view,
+ Rectangle *area, DrawingContext *context)
+{
+ // This could be improved, since the list is sorted: search the
+ // first float fitting into the area, and iterate until one is
+ // found below the area.
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ Widget *childWidget = vloat->getWidget ();
+
+ Rectangle childArea;
+ if (!context->hasWidgetBeenProcessedAsInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->intersects (container, area, &childArea))
+ childWidget->draw (view, &childArea, context);
+ }
+}
+
+void OOFFloatsMgr::addWidgetInFlow (OOFAwareWidget *textblock,
+ OOFAwareWidget *parentBlock,
+ int externalIndex)
+{
+ //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
+ // container, textblock, parentBlock, externalIndex);
+
+ TBInfo *tbInfo =
+ new TBInfo (this, textblock,
+ parentBlock ? getOOFAwareWidget (parentBlock) : NULL,
+ externalIndex);
+ tbInfo->index = tbInfos->size();
+
+ tbInfos->put (tbInfo);
+ tbInfosByOOFAwareWidget->put (new TypedPointer<OOFAwareWidget> (textblock),
+ tbInfo);
+}
+
+int OOFFloatsMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generatingBlock,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generatingBlock, externalIndex);
+
+ int subRef;
+
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
+
+ // Note: Putting the float first in the GB list, and then, possibly
+ // into the CB list (in that order) will trigger setting
+ // Float::inCBList to the right value.
+
+ switch (widget->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ leftFloatsAll->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
+ subRef = createSubRefLeftFloat (leftFloatsAll->size() - 1);
+ tbInfo->leftFloatsGB->put (vloat);
+
+ if (wasAllocated (generatingBlock)) {
+ leftFloatsCB->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1,
+ "widget", vloat->getWidget ());
+ } else {
+ if (tbInfo->index < lastLeftTBIndex)
+ leftFloatsMark++;
+
+ vloat->mark = leftFloatsMark;
+ lastLeftTBIndex = tbInfo->index;
+ }
+ break;
+
+ case FLOAT_RIGHT:
+ rightFloatsAll->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
+ subRef = createSubRefRightFloat (rightFloatsAll->size() - 1);
+ tbInfo->rightFloatsGB->put (vloat);
+
+ if (wasAllocated (generatingBlock)) {
+ rightFloatsCB->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1,
+ "widget", vloat->getWidget ());
+ } else {
+ if (tbInfo->index < lastRightTBIndex)
+ rightFloatsMark++;
+
+ vloat->mark = rightFloatsMark;
+ lastRightTBIndex = tbInfo->index;
+ }
+
+ break;
+
+ default:
+ assertNotReached();
+ }
+
+ // "sideSpanningIndex" is only compared, so this simple assignment
+ // is sufficient; differenciation between GB and CB lists is not
+ // neccessary. TODO: Can this also be applied to "index", to
+ // simplify the current code? Check: where is "index" used.
+ vloat->sideSpanningIndex =
+ leftFloatsAll->size() + rightFloatsAll->size() - 1;
+
+ floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
+
+ DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef);
+ DBG_OBJ_LEAVE ();
+ return subRef;
+}
+
+void OOFFloatsMgr::calcWidgetRefSize (Widget *widget, Requisition *size)
+{
+ size->width = size->ascent = size->descent = 0;
+}
+
+void OOFFloatsMgr::moveExternalIndices (OOFAwareWidget *generatingBlock,
+ int oldStartIndex, int diff)
+{
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff);
+ moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff);
+}
+
+void OOFFloatsMgr::moveExternalIndices (SortedFloatsVector *list,
+ int oldStartIndex, int diff)
+{
+ // Could be faster with binary search, but the GB (not CB!) lists
+ // should be rather small.
+ for (int i = 0; i < list->size (); i++) {
+ Float *vloat = list->get (i);
+ if (vloat->externalIndex >= oldStartIndex) {
+ vloat->externalIndex += diff;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
+ vloat->externalIndex);
+ }
+ }
+}
+
+OOFFloatsMgr::Float *OOFFloatsMgr::findFloatByWidget (Widget *widget)
+{
+ TypedPointer <Widget> key (widget);
+ Float *vloat = floatsByWidget->get (&key);
+ assert (vloat != NULL);
+ return vloat;
+}
+
+void OOFFloatsMgr::markSizeChange (int ref)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
+
+ Float *vloat;
+
+ if (isSubRefLeftFloat (ref))
+ vloat = leftFloatsAll->get (getFloatIndexFromSubRef (ref));
+ else if (isSubRefRightFloat (ref))
+ vloat = rightFloatsAll->get (getFloatIndexFromSubRef (ref));
+ else {
+ assertNotReached();
+ vloat = NULL; // compiler happiness
+ }
+
+ vloat->dirty = vloat->sizeChangedSinceLastAllocation = true;
+
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (),
+ "<Float>.sizeChangedSinceLastAllocation",
+ vloat->sizeChangedSinceLastAllocation);
+
+ // The generating block is told directly about this. (Others later, in
+ // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which
+ // differentiates many special cases), but the size is not known yet,
+ vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ());
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFFloatsMgr::markExtremesChange (int ref)
+{
+ // Nothing to do here.
+}
+
+Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context)
+{
+ Widget *widgetAtPoint = NULL;
+
+ widgetAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, context);
+ if (widgetAtPoint == NULL)
+ widgetAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, context);
+
+ return widgetAtPoint;
+}
+
+Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x,
+ int y,
+ GettingWidgetAtPointContext
+ *context)
+{
+ // Could use binary search to be faster (similar to drawing).
+ Widget *widgetAtPoint = NULL;
+
+ for (int i = list->size() - 1; widgetAtPoint == NULL && i >= 0; i--) {
+ Widget *childWidget = list->get(i)->getWidget ();
+ if (!context->hasWidgetBeenProcessedAsInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget))
+ widgetAtPoint = childWidget->getWidgetAtPoint (x, y, context);
+ }
+
+ return widgetAtPoint;
+}
+
+void OOFFloatsMgr::tellPosition1 (Widget *widget, int x, int y)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition1", "%p, %d, %d",
+ widget, x, y);
+
+ assert (y >= 0);
+
+ Float *vloat = findFloatByWidget(widget);
+
+ SortedFloatsVector *listSame, *listOpp;
+ Side side;
+ getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
+ ensureFloatSize (vloat);
+
+ // "yReal" may change due to collisions (see below).
+ vloat->yReq = vloat->yReal = y;
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+
+ // Test collisions (on this side). Although there are (rare) cases
+ // where it could make sense, the horizontal dimensions are not
+ // tested; especially since searching and border calculation would
+ // be confused. For this reaspn, only the previous float is
+ // relevant. (Cf. below, collisions on the other side.)
+ int index = vloat->getIndex (listSame->type), yRealNew;
+ if (index >= 1 &&
+ collidesV (vloat, listSame->get (index - 1), listSame->type,
+ &yRealNew, false)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ }
+
+ // Test collisions (on the opposite side). There are cases when
+ // more than one float has to be tested. Consider the following
+ // HTML snippet ("id" attribute only used for simple reference
+ // below, as #f1, #f2, and #f3):
+ //
+ // <div style="float:left" id="f1">
+ // Left left left left left left left left left left.
+ // </div>
+ // <div style="float:left" id="f2">Also left.</div>
+ // <div style="float:right" id="f3">Right.</div>
+ //
+ // When displayed with a suitable window width (only slightly wider
+ // than the text within #f1), this should look like this:
+ //
+ // ---------------------------------------------------------
+ // | Left left left left left left left left left left. |
+ // | Also left. Right. |
+ // ---------------------------------------------------------
+ //
+ // Consider float #f3: a collision test with #f2, considering
+ // vertical dimensions, is positive, but not the test with
+ // horizontal dimensions (because #f2 and #f3 are too
+ // narrow). However, a collision has to be tested with #f1;
+ // otherwise #f3 and #f1 would overlap.
+
+ int oppFloatIndex =
+ listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
+ // Generally, the rules are simple: loop as long as the vertical
+ // dimensions test is positive (and, of course, there are floats),
+ // ...
+ for (bool foundColl = false;
+ !foundColl && oppFloatIndex >= 0 &&
+ collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
+ &yRealNew, false);
+ oppFloatIndex--) {
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ foundColl = true;
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
+ vloat->yReq, vloat->yReal);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::tellPosition2 (Widget *widget, int x, int y)
+{
+ // Nothing to do.
+}
+
+void OOFFloatsMgr::tellIncompletePosition1 (Widget *generator, Widget *widget,
+ int x, int y)
+{
+ assertNotReached ();
+}
+
+void OOFFloatsMgr::tellIncompletePosition2 (Widget *generator, Widget *widget,
+ int x, int y)
+{
+ assertNotReached ();
+}
+
+bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, SFVType type,
+ int *yReal, bool useAllocation)
+{
+ // Only checks vertical (possible) collisions, and only refers to
+ // vloat->yReal; never to vloat->allocation->y, even when the GBs are
+ // different. Used only in tellPosition.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
+ vloat->getIndex (type), vloat->getWidget (),
+ other->getIndex (type), other->getWidget ());
+
+ bool result;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
+
+ if (vloat->generatingBlock == other->generatingBlock) {
+ ensureFloatSize (other);
+ int otherBottomGB =
+ other->yReal + other->size.ascent + other->size.descent;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same generators: otherBottomGB = %d + (%d + %d) = %d",
+ other->yReal, other->size.ascent, other->size.descent,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ } else {
+ // If the other float is not allocated, there is no collision. The
+ // allocation of this float (vloat) is not used at all.
+ if (!other->getWidget()->wasAllocated ())
+ result = false;
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ Allocation *gba = getAllocation (vloat->generatingBlock),
+ *flaOther = other->getWidget()->getAllocation ();
+
+ // We distinguish two cases (by different values of useAllocation):
+ // (i) within tellPosition, GB allocation + yReal is used for the
+ // y position of the other float, while (ii) in checkAllocatedFloat-
+ // Collisions, the float allocation is used. The latter is necessary
+ // by the definition of this method, the former increases performance,
+ // as compared to using the float allocation, in some cases, as in
+ // this:
+ //
+ // When '<div><div style="float:left">[Some text]</div></div>' is
+ // repeated n times, the resize idle function (Layout::resizeIdle)
+ // would be repeated roughly n times, when also in case (i) the float
+ // allocation is used, since for the collision test of float n with
+ // float n - 1, the allocation of float n - 1 does not yet reflect the
+ // collision test between n - 1 and n - 2, but yReal does for n - 1.
+ //
+ // On the other hand, the GB allocations will most likely more stable
+ // than the float allocations.
+ //
+ // Cases where this is incorrect will hopefully be rare, and, in any
+ // case, corrected in sizeAllocateEnd, either because hasRelation-
+ // Changed returns true, or in checkAllocatedFloatCollisions.
+
+ int otherFloatY = useAllocation ? flaOther->y :
+ getAllocation(other->generatingBlock)->y + other->yReal;
+ int otherBottomGB =
+ otherFloatY + flaOther->ascent + flaOther->descent - gba->y;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "different generators: "
+ "otherBottomGB = %d + (%d + %d) - %d = %d",
+ otherFloatY, flaOther->ascent, flaOther->descent, gba->y,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ }
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
+
+ DBG_OBJ_LEAVE ();
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other, SFVType type)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generatingBlock == other->generatingBlock)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generatingBlock->boxDiffWidth()
+ > vloat->generatingBlock->getLineBreakWidth();
+ else {
+ // Again, if the other float is not allocated, there is no
+ // collision. Compare to collidesV. (But vloat->size is used
+ // here.)
+ if (!other->getWidget()->wasAllocated ())
+ collidesH = false;
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ int vloatX =
+ calcFloatX (vloat,
+ vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
+ LEFT : RIGHT,
+ gba->x, getGBWidthForAllocation (vloat));
+
+ // Generally: right border of the left float > left border of
+ // the right float (all in canvas coordinates).
+ if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
+ // "vloat" is left, "other" is right
+ collidesH = vloatX + vloat->size.width
+ > other->getWidget()->getAllocation()->x;
+ else
+ // "other" is left, "vloat" is right
+ collidesH = other->getWidget()->getAllocation()->x
+ + other->getWidget()->getAllocation()->width
+ > vloatX;
+ }
+ }
+
+ return collidesH;
+}
+
+void OOFFloatsMgr::getFloatsListsAndSide (Float *vloat,
+ SortedFloatsVector **listSame,
+ SortedFloatsVector **listOpp,
+ Side *side)
+{
+ TBInfo *tbInfo = getOOFAwareWidget (vloat->generatingBlock);
+
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ if (wasAllocated (vloat->generatingBlock)) {
+ if (listSame) *listSame = leftFloatsCB;
+ if (listOpp) *listOpp = rightFloatsCB;
+ } else {
+ if (listSame) *listSame = tbInfo->leftFloatsGB;
+ if (listOpp) *listOpp = tbInfo->rightFloatsGB;
+ }
+ if (side) *side = LEFT;
+ break;
+
+ case FLOAT_RIGHT:
+ if (wasAllocated (vloat->generatingBlock)) {
+ if (listSame) *listSame = rightFloatsCB;
+ if (listOpp) *listOpp = leftFloatsCB;
+ } else {
+ if (listSame) *listSame = tbInfo->rightFloatsGB;
+ if (listOpp) *listOpp = tbInfo->leftFloatsGB;
+ }
+ if (side) *side = RIGHT;
+ break;
+
+ default:
+ assertNotReached();
+ }
+}
+
+void OOFFloatsMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight)
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
+
+ int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
+ getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
+ getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
+
+ // Floats must be within the *content* area of the containing
+ // block, not its *margin* area (which is equivalent to the
+ // requisition / allocation). For this reason, boxRestWidth() and
+ // boxRestHeight() are added here.
+
+ *oofWidth =
+ max (oofWidthtLeft, oofWidthRight) + container->boxRestWidth ();
+ *oofHeight =
+ max (oofHeightLeft, oofHeightRight) + container->boxRestHeight ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)",
+ oofWidthtLeft, oofWidthRight, *oofWidth, oofHeightLeft,
+ oofHeightRight, *oofHeight);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
+ int *height)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
+ cbReq->width, cbReq->ascent, cbReq->descent,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side);
+
+ *width = *height = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p has generator %p (container is %p)",
+ vloat->getWidget (), vloat->generatingBlock, container);
+
+ if (vloat->generatingBlock == container ||
+ wasAllocated (vloat->generatingBlock)) {
+ ensureFloatSize (vloat);
+ int x, y;
+
+ int effWidth;
+ if (container->mustBeWidenedToAvailWidth ())
+ // For most textblocks, the line break width is used for
+ // calculating the x position. (This changed for GROWS,
+ // where the width of a textblock is often smaller that
+ // the line break.)
+ effWidth = vloat->generatingBlock->getLineBreakWidth ();
+ else
+ // For some textblocks, like inline blocks, the line break
+ // width would be too large for right floats in some
+ // cases.
+ //
+ // (i) Consider a small inline block with only a few words
+ // in one line, narrower that line break width minus
+ // float width. In this case, the sum should be used.
+ //
+ // (ii) If there is more than one line, the line break
+ // will already be exceeded, and so be smaller that
+ // GB width + float width.
+ effWidth = min (cbReq->width + vloat->size.width,
+ vloat->generatingBlock->getLineBreakWidth ());
+
+ if (vloat->generatingBlock == container) {
+ x = calcFloatX (vloat, side, 0, effWidth);
+ y = vloat->yReal;
+ } else {
+ Allocation *gba = getAllocation(vloat->generatingBlock);
+ x = calcFloatX (vloat, side, gba->x - containerAllocation.x,
+ effWidth);
+ y = gba->y - containerAllocation.y + vloat->yReal;
+ }
+
+ *width = max (*width, x + vloat->size.width);
+ *height = max (*height, y + vloat->size.ascent + vloat->size.descent);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: (%d + %d) * "
+ "(%d + (%d + %d)) => %d * %d",
+ vloat->getWidget (), vloat->generatingBlock,
+ x, vloat->size.width,
+ y, vloat->size.ascent, vloat->size.descent,
+ *width, *height);
+ } else
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: not allocated",
+ vloat->getWidget (), vloat->generatingBlock);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::containerMustAdjustExtraSpace ()
+{
+ return false;
+}
+
+void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ cbExtr->minWidth, cbExtr->maxWidth);
+
+ int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
+ getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
+ getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
+
+ *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
+ *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
+ oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
+ oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
+ int *minWidth, int *maxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
+ cbExtr->minWidth, cbExtr->maxWidth,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ *minWidth = *maxWidth = 0;
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p has generator %p (container is %p)",
+ vloat->getWidget (), vloat->generatingBlock,
+ container);
+
+ if (vloat->generatingBlock == container ||
+ wasAllocated (vloat->generatingBlock)) {
+ Extremes extr;
+ vloat->getWidget()->getExtremes (&extr);
+
+ // The calculation of extremes must be kept consistent with
+ // getFloatsSize(). Especially this means for the *minimal* width:
+ //
+ // - The right border (difference between float and
+ // container) does not have to be considered (see
+ // getFloatsSize()).
+ //
+ // - This is also the case for the left border, as seen in
+ // calcFloatX() ("... but when the float exceeds the line
+ // break width" ...).
+
+ *minWidth = max (*minWidth, extr.minWidth);
+
+ // For the maximal width, borders must be considered.
+
+ if (vloat->generatingBlock == container)
+ *maxWidth =
+ max (*maxWidth,
+ extr.maxWidth
+ + vloat->generatingBlock->getStyle()->boxDiffWidth());
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ *maxWidth =
+ max (*maxWidth,
+ extr.maxWidth
+ + vloat->generatingBlock->getStyle()->boxDiffWidth()
+ + max (containerAllocation.width - gba->width, 0));
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d / %d => %d / %d",
+ extr.minWidth, extr.maxWidth, *minWidth, *maxWidth);
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "not allocated");
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidgetWhenRegistered
+ (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidgetWhenRegistered", "%p",
+ widget);
+ TypedPointer<OOFAwareWidget> key (widget);
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (&key);
+ DBG_OBJ_MSGF ("oofm.common", 1, "found? %s", tbInfo ? "yes" : "no");
+ DBG_OBJ_LEAVE ();
+ return tbInfo;
+}
+
+OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidget (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidget", "%p", widget);
+ TBInfo *tbInfo = getOOFAwareWidgetWhenRegistered (widget);
+ assert (tbInfo);
+ DBG_OBJ_LEAVE ();
+ return tbInfo;
+}
+
+int OOFFloatsMgr::getLeftBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d",
+ textblock, y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getRightBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d",
+ textblock, y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getBorder (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int last;
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+
+ if (first == -1) {
+ // No float.
+ DBG_OBJ_LEAVE ();
+ return 0;
+ } else {
+ // It is not sufficient to find the first float, since a line
+ // (with height h) may cover the region of multiple float, of
+ // which the widest has to be choosen.
+ int border = 0;
+ bool covers = true;
+
+ // We are not searching until the end of the list, but until the
+ // float defined by lastGB and lastExtIndex.
+ for (int i = first; covers && i <= last; i++) {
+ Float *vloat = list->get(i);
+ covers = vloat->covers (textblock, y, h);
+ DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
+ i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
+
+ if (covers) {
+ int thisBorder;
+ if (vloat->generatingBlock == textblock) {
+ int borderIn = side == LEFT ?
+ vloat->generatingBlock->boxOffsetX() :
+ vloat->generatingBlock->boxRestWidth();
+ thisBorder = vloat->size.width + borderIn;
+ DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d",
+ vloat->size.width, borderIn, thisBorder);
+ } else {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (vloat->getWidget()->wasAllocated ());
+
+ Allocation *tba = getAllocation(textblock),
+ *fla = vloat->getWidget()->getAllocation ();
+ if (side == LEFT) {
+ thisBorder = fla->x + fla->width - tba->x;
+ DBG_OBJ_MSGF ("border", 1,
+ "not GB: thisBorder = %d + %d - %d = %d",
+ fla->x, fla->width, tba->x, thisBorder);
+ } else {
+ // See also calcFloatX.
+ thisBorder =
+ tba->x + textblock->getLineBreakWidth () - fla->x;
+ DBG_OBJ_MSGF ("border", 1,
+ "not GB: thisBorder = %d + %d - %d "
+ "= %d",
+ tba->x, textblock->getLineBreakWidth (), fla->x,
+ thisBorder);
+ }
+ }
+
+ border = max (border, thisBorder);
+ DBG_OBJ_MSGF ("border", 1, "=> border = %d", border);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+ return border;
+ }
+}
+
+
+OOFFloatsMgr::SortedFloatsVector *OOFFloatsMgr::getFloatsListForOOFAwareWidget
+ (OOFAwareWidget *textblock, Side side)
+{
+ DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForOOFAwareWidget", "%p, %s",
+ textblock, side == LEFT ? "LEFT" : "RIGHT");
+
+ OOFFloatsMgr::SortedFloatsVector *list;
+
+ if (wasAllocated (textblock)) {
+ DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list");
+ list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ } else {
+ DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list");
+ TBInfo *tbInfo = getOOFAwareWidget (textblock);
+ list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return list;
+}
+
+
+bool OOFFloatsMgr::hasFloatLeft (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s",
+ textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloatRight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s",
+ textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloat (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+ DBG_OBJ_LEAVE ();
+ return first != -1;
+}
+
+int OOFFloatsMgr::getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getRightFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getFloatHeight (OOFAwareWidget *textblock, Side side, int y,
+ int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
+ assert (first != -1); /* This method must not be called when there is no
+ float on the respective side. */
+
+ Float *vloat = list->get(first);
+ int yRelToFloat;
+
+ if (vloat->generatingBlock == textblock) {
+ yRelToFloat = y - vloat->yReal;
+ DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
+ y, vloat->yReal, yRelToFloat);
+ } else {
+ // The respective widgets are allocated; otherwise, hasFloat() would have
+ // returned false.
+ assert (wasAllocated (textblock));
+ assert (vloat->getWidget()->wasAllocated ());
+
+ Allocation *tba = getAllocation(textblock),
+ *fla = vloat->getWidget()->getAllocation ();
+ yRelToFloat = tba->y + y - fla->y;
+
+ DBG_OBJ_MSGF ("border", 1,
+ "caller is not CB: yRelToFloat = %d + %d - %d = %d",
+ tba->y, y, fla->y, yRelToFloat);
+ }
+
+ ensureFloatSize (vloat);
+ int height = vloat->size.ascent + vloat->size.descent - yRelToFloat;
+
+ DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d",
+ vloat->size.ascent, vloat->size.descent, yRelToFloat, height);
+ DBG_OBJ_LEAVE ();
+ return height;
+}
+
+/**
+ * Returns position relative to the textblock "tb".
+ */
+int OOFFloatsMgr::getClearPosition (OOFAwareWidget *textblock)
+{
+ return getOOFAwareWidget(textblock)->clearPosition;
+}
+
+int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", textblock);
+
+ int pos;
+
+ if (textblock->getStyle()) {
+ bool left = false, right = false;
+ switch (textblock->getStyle()->clear) {
+ case CLEAR_NONE: break;
+ case CLEAR_LEFT: left = true; break;
+ case CLEAR_RIGHT: right = true; break;
+ case CLEAR_BOTH: left = right = true; break;
+ default: assertNotReached ();
+ }
+
+ pos = max (left ? calcClearPosition (textblock, LEFT) : 0,
+ right ? calcClearPosition (textblock, RIGHT) : 0);
+ } else
+ pos = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
+ DBG_OBJ_LEAVE ();
+
+ return pos;
+}
+
+bool OOFFloatsMgr::affectsLeftBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_LEFT;
+}
+
+bool OOFFloatsMgr::affectsRightBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_RIGHT;
+};
+
+bool OOFFloatsMgr::mayAffectBordersAtAll ()
+{
+ return true;
+}
+
+int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock, Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s",
+ textblock, side == LEFT ? "LEFT" : "RIGHT");
+
+ int pos;
+
+ if (!wasAllocated (textblock))
+ // There is no relation yet to floats generated by other
+ // textblocks, and this textblocks floats are unimportant for
+ // the "clear" property.
+ pos = 0;
+ else {
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+
+ // Search the last float before (therfore -1) this textblock.
+ int i = list->findFloatIndex (textblock, -1);
+ if (i < 0) {
+ pos = 0;
+ DBG_OBJ_MSG ("resize.oofm", 1, "no float");
+ } else {
+ Float *vloat = list->get(i);
+ assert (vloat->generatingBlock != textblock);
+ if (!wasAllocated (vloat->generatingBlock))
+ pos = 0; // See above.
+ else {
+ ensureFloatSize (vloat);
+ pos = max (getAllocation(vloat->generatingBlock)->y + vloat->yReal
+ + vloat->size.ascent + vloat->size.descent
+ - getAllocation(textblock)->y,
+ 0);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p => max (%d + %d + (%d + %d) - %d, 0)",
+ vloat->getWidget (),
+ getAllocation(vloat->generatingBlock)->y,
+ vloat->yReal, vloat->size.ascent, vloat->size.descent,
+ getAllocation(textblock)->y);
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
+ DBG_OBJ_LEAVE ();
+
+ return pos;
+}
+
+void OOFFloatsMgr::ensureFloatSize (Float *vloat)
+{
+ // Historical note: relative sizes (e. g. percentages) are already
+ // handled by (at this time) Layout::containerSizeChanged, so
+ // Float::dirty will be set.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p",
+ vloat->getWidget ());
+
+ if (vloat->dirty) {
+ DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation");
+
+ vloat->getWidget()->sizeRequest (&vloat->size);
+ vloat->cbLineBreakWidth = container->getLineBreakWidth ();
+ vloat->dirty = false;
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)",
+ vloat->size.width, vloat->size.ascent, vloat->size.descent);
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width",
+ vloat->size.width);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent",
+ vloat->size.ascent);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent",
+ vloat->size.descent);
+
+ // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd()
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::dealingWithSizeOfChild (core::Widget *child)
+{
+ return false;
+}
+
+int OOFFloatsMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+int OOFFloatsMgr::getNumWidgets ()
+{
+ return leftFloatsAll->size() + rightFloatsAll->size();
+}
+
+Widget *OOFFloatsMgr::getWidget (int i)
+{
+ if (i < leftFloatsAll->size())
+ return leftFloatsAll->get(i)->getWidget ();
+ else
+ return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh
new file mode 100644
index 00000000..c30ac172
--- /dev/null
+++ b/dw/ooffloatsmgr.hh
@@ -0,0 +1,406 @@
+#ifndef __DW_OOFFLOATSMGR_HH__
+#define __DW_OOFFLOATSMGR_HH__
+
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+/**
+ * \brief OutOfFlowMgr implementation dealing with floats.
+ *
+ * Note: The identifiers and comments of this class still refer to
+ * "Textblock" instead of "OOFAwareWidget"; should be cleaned up some
+ * day. (OTOH, these widgets are always textblocks.)
+ */
+class OOFFloatsMgr: public OutOfFlowMgr
+{
+ friend class WidgetInfo;
+
+private:
+ enum Side { LEFT, RIGHT };
+ enum SFVType { GB, CB };
+
+ OOFAwareWidget *container;
+
+ // These two values are redundant to TBInfo::wasAllocated and
+ // TBInfo::allocation, for some special cases.
+ bool containerWasAllocated;
+ core::Allocation containerAllocation;
+
+ class WidgetInfo: public lout::object::Object
+ {
+ private:
+ bool wasAllocated;
+ int xCB, yCB; // relative to the containing block
+ int width, height;
+
+ OOFFloatsMgr *oofm;
+ core::Widget *widget;
+
+ protected:
+ OOFFloatsMgr *getOOFFloatsMgr () { return oofm; }
+
+ public:
+ WidgetInfo (OOFFloatsMgr *oofm, core::Widget *widget);
+
+ inline bool wasThenAllocated () { return wasAllocated; }
+ inline int getOldXCB () { return xCB; }
+ inline int getOldYCB () { return yCB; }
+ inline int getOldWidth () { return width; }
+ inline int getOldHeight () { return height; }
+
+
+ void update (bool wasAllocated, int xCB, int yCB, int width, int height);
+
+ inline core::Widget *getWidget () { return widget; }
+ };
+
+ class Float: public WidgetInfo
+ {
+ public:
+ class ComparePosition: public lout::object::Comparator
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ OOFAwareWidget *refTB;
+ SFVType type; // actually only used for debugging
+
+ public:
+ ComparePosition (OOFFloatsMgr *oofm, OOFAwareWidget *refTB,
+ SFVType type)
+ { this->oofm = oofm; this->refTB = refTB; this->type = type; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ class CompareSideSpanningIndex: public lout::object::Comparator
+ {
+ public:
+ int compare(Object *o1, Object *o2);
+ };
+
+ class CompareGBAndExtIndex: public lout::object::Comparator
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ SFVType type; // actually only used for debugging
+
+ public:
+ CompareGBAndExtIndex (OOFFloatsMgr *oofm, SFVType type)
+ { this->oofm = oofm; this->type = type; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ OOFAwareWidget *generatingBlock;
+ int externalIndex;
+ int yReq, yReal; // relative to generator, not container
+ int indexGBList; /* Refers to TBInfo::leftFloatsGB or
+ TBInfo::rightFloatsGB, respectively. -1
+ initially. */
+ int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB,
+ respectively. -1 initially. */
+ int sideSpanningIndex, mark;
+ core::Requisition size;
+ int cbLineBreakWidth; /* On which the calculation of relative sizes
+ is based. Height not yet used, and probably
+ not added before size redesign. */
+ bool dirty, sizeChangedSinceLastAllocation;
+
+ Float (OOFFloatsMgr *oofm, core::Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex);
+
+ inline bool isNowAllocated () { return getWidget()->wasAllocated (); }
+ inline int getNewXCB () { return getWidget()->getAllocation()->x -
+ getOOFFloatsMgr()->containerAllocation.x; }
+ inline int getNewYCB () { return getWidget()->getAllocation()->y -
+ getOOFFloatsMgr()->containerAllocation.y; }
+ inline int getNewWidth () { return getWidget()->getAllocation()->width; }
+ inline int getNewHeight () { return getWidget()->getAllocation()->ascent +
+ getWidget()->getAllocation()->descent; }
+ void updateAllocation ();
+
+ inline int *getIndexRef (SFVType type) {
+ return type == GB ? &indexGBList : &indexCBList; }
+ inline int getIndex (SFVType type) { return *(getIndexRef (type)); }
+ inline void setIndex (SFVType type, int value) {
+ *(getIndexRef (type)) = value; }
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ bool covers (OOFAwareWidget *textblock, int y, int h);
+ };
+
+ /**
+ * This list is kept sorted.
+ *
+ * To prevent accessing methods of the base class in an
+ * uncontrolled way, the inheritance is private, not public; this
+ * means that all methods must be delegated (see iterator(), size()
+ * etc. below.)
+ *
+ * TODO Update comment: still sorted, but ...
+ *
+ * More: add() and change() may check order again.
+ */
+ class SortedFloatsVector: private lout::container::typed::Vector<Float>
+ {
+ public:
+ SFVType type;
+
+ private:
+ OOFFloatsMgr *oofm;
+ Side side;
+
+ public:
+ inline SortedFloatsVector (OOFFloatsMgr *oofm, Side side, SFVType type) :
+ lout::container::typed::Vector<Float> (1, false)
+ { this->oofm = oofm; this->side = side; this->type = type; }
+
+ int findFloatIndex (OOFAwareWidget *lastGB, int lastExtIndex);
+ int find (OOFAwareWidget *textblock, int y, int start, int end);
+ int findFirst (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex, int *lastReturn);
+ int findLastBeforeSideSpanningIndex (int sideSpanningIndex);
+ void put (Float *vloat);
+
+ inline lout::container::typed::Iterator<Float> iterator()
+ { return lout::container::typed::Vector<Float>::iterator (); }
+ inline int size ()
+ { return lout::container::typed::Vector<Float>::size (); }
+ inline Float *get (int pos)
+ { return lout::container::typed::Vector<Float>::get (pos); }
+ inline void clear ()
+ { lout::container::typed::Vector<Float>::clear (); }
+ };
+
+ class TBInfo: public WidgetInfo
+ {
+ public:
+ int lineBreakWidth;
+ int index; // position within "tbInfos"
+
+ TBInfo *parent;
+ int parentExtIndex;
+
+ // These two values are set by sizeAllocateStart(), and they are
+ // accessable also within sizeAllocateEnd() for the same
+ // textblock, for which allocation and WAS_ALLOCATED is set
+ // *after* sizeAllocateEnd(). See the two functions
+ // wasAllocated(Widget*) and getAllocation(Widget*) (further
+ // down) for usage.
+ bool wasAllocated;
+ core::Allocation allocation;
+ int clearPosition;
+
+ // These two lists store all floats generated by this textblock,
+ // as long as this textblock is not allocates.
+ SortedFloatsVector *leftFloatsGB, *rightFloatsGB;
+
+ TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex);
+ ~TBInfo ();
+
+ inline bool isNowAllocated () {
+ return getOOFFloatsMgr()->wasAllocated (getOOFAwareWidget ()); }
+ inline int getNewXCB () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->x -
+ getOOFFloatsMgr()->containerAllocation.x; }
+ inline int getNewYCB () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->y -
+ getOOFFloatsMgr()->containerAllocation.y; }
+ inline int getNewWidth () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->width; }
+ inline int getNewHeight () {
+ core::Allocation *allocation =
+ getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ());
+ return allocation->ascent + allocation->descent; }
+ void updateAllocation ();
+
+ inline OOFAwareWidget *getOOFAwareWidget ()
+ { return (OOFAwareWidget*)getWidget (); }
+ };
+
+ // These two lists store all floats, in the order in which they are
+ // defined. Only used for iterators.
+ lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll;
+
+ // These two lists store all floats whose generators are already
+ // allocated.
+ SortedFloatsVector *leftFloatsCB, *rightFloatsCB;
+
+ // These two attributes are used in the size allocation process;
+ // see sizeAllocateStart and sizeAllocateEnd.
+ int lastAllocatedLeftFloat, lastAllocatedRightFloat;
+
+ lout::container::typed::HashTable<lout::object::TypedPointer
+ <dw::core::Widget>, Float> *floatsByWidget;
+
+ lout::container::typed::Vector<TBInfo> *tbInfos;
+ lout::container::typed::HashTable<lout::object::TypedPointer<OOFAwareWidget>,
+ TBInfo> *tbInfosByOOFAwareWidget;
+
+ int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
+
+ /**
+ * Variant of Widget::wasAllocated(), which can also be used within
+ * OOFM::sizeAllocateEnd().
+ */
+ inline bool wasAllocated (OOFAwareWidget *textblock) {
+ return getOOFAwareWidget(textblock)->wasAllocated;
+ }
+
+ /**
+ * Variant of Widget::getAllocation(), which can also be used
+ * within OOFM::sizeAllocateEnd().
+ */
+ inline core::Allocation *getAllocation (OOFAwareWidget *textblock) {
+ return &(getOOFAwareWidget(textblock)->allocation);
+ }
+
+ void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
+ int diff);
+ Float *findFloatByWidget (core::Widget *widget);
+
+ void moveFromGBToCB (Side side);
+ void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
+ int getGBWidthForAllocation (Float *vloat);
+ int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth);
+
+ bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos,
+ core::Widget **minFloat);
+ bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos,
+ core::Widget **minFloat);
+ bool hasRelationChanged (bool oldTBAlloc,
+ int oldTBx, int oldTBy, int oldTBw, int oldTBh,
+ int newTBx, int newTBy, int newTBw, int newTBh,
+ bool oldFlAlloc,
+ int oldFlx, int oldFly, int oldFlw, int oldFlh,
+ int newFlx, int newFly, int newFlw, int newFlh,
+ Side side, int *floatPos);
+
+ void checkAllocatedFloatCollisions (Side side);
+
+ bool doFloatsExceedCB (Side side);
+ bool haveExtremesChanged (Side side);
+
+ void drawFloats (SortedFloatsVector *list, core::View *view,
+ core::Rectangle *area, core::DrawingContext *context);
+ core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
+ core::GettingWidgetAtPointContext
+ *context);
+
+ bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal,
+ bool useAllocation);
+ bool collidesH (Float *vloat, Float *other, SFVType type);
+
+ void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
+ SortedFloatsVector **listOpp, Side *side);
+
+ void getFloatsSize (core::Requisition *cbReq, Side side, int *width,
+ int *height);
+ void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth,
+ int *maxWidth);
+
+ TBInfo *getOOFAwareWidget (OOFAwareWidget *widget);
+ TBInfo *getOOFAwareWidgetWhenRegistered (OOFAwareWidget *widget);
+ inline bool isOOFAwareWidgetRegistered (OOFAwareWidget *widget)
+ { return getOOFAwareWidgetWhenRegistered (widget) != NULL; }
+ int getBorder (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ SortedFloatsVector *getFloatsListForOOFAwareWidget (OOFAwareWidget
+ *textblock,
+ Side side);
+ bool hasFloat (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getFloatHeight (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int calcClearPosition (OOFAwareWidget *textblock);
+ int calcClearPosition (OOFAwareWidget *textblock, Side side);
+
+ void ensureFloatSize (Float *vloat);
+
+ inline static int createSubRefLeftFloat (int index) { return index << 1; }
+ inline static int createSubRefRightFloat (int index)
+ { return (index << 1) | 1; }
+
+ inline static bool isSubRefLeftFloat (int ref)
+ { return ref != -1 && (ref & 1) == 0; }
+ inline static bool isSubRefRightFloat (int ref)
+ { return ref != -1 && (ref & 1) == 1; }
+
+ inline static int getFloatIndexFromSubRef (int ref)
+ { return ref == -1 ? ref : (ref >> 1); }
+
+public:
+ OOFFloatsMgr (OOFAwareWidget *container);
+ ~OOFFloatsMgr ();
+
+ void sizeAllocateStart (OOFAwareWidget *caller,
+ core::Allocation *allocation);
+ void sizeAllocateEnd (OOFAwareWidget *caller);
+ void containerSizeChangedForChildren ();
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *context);
+
+ void addWidgetInFlow (OOFAwareWidget *textblock, OOFAwareWidget *parentBlock,
+ int externalIndex);
+ int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generatingBlock,
+ int externalIndex);
+ void calcWidgetRefSize (core::Widget *widget,core::Requisition *size);
+ void moveExternalIndices (OOFAwareWidget *generatingBlock, int oldStartIndex,
+ int diff);
+
+ void tellPosition1 (core::Widget *widget, int x, int y);
+ void tellPosition2 (core::Widget *widget, int x, int y);
+ void tellIncompletePosition1 (core::Widget *generator, core::Widget *widget,
+ int x, int y);
+ void tellIncompletePosition2 (core::Widget *generator, core::Widget *widget,
+ int x, int y);
+
+ void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
+ bool containerMustAdjustExtraSpace ();
+ void getExtremes (core::Extremes *cbExtr,
+ int *oofMinWidth, int *oofMaxWidth);
+
+ int getLeftBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool hasFloatLeft (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ bool hasFloatRight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+ bool mayAffectBordersAtAll ();
+
+ int getClearPosition (OOFAwareWidget *textblock);
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
+ int getNumWidgets ();
+ core::Widget *getWidget (int i);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFFLOATSMGR_HH__
diff --git a/dw/oofposabslikemgr.cc b/dw/oofposabslikemgr.cc
new file mode 100644
index 00000000..bde9d71b
--- /dev/null
+++ b/dw/oofposabslikemgr.cc
@@ -0,0 +1,427 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofposabslikemgr.hh"
+
+using namespace dw::core;
+using namespace lout::misc;
+
+namespace dw {
+
+namespace oof {
+
+OOFPosAbsLikeMgr::OOFPosAbsLikeMgr (OOFAwareWidget *container) :
+ OOFPositionedMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosAbsLikeMgr");
+}
+
+OOFPosAbsLikeMgr::~OOFPosAbsLikeMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+void OOFPosAbsLikeMgr::calcWidgetRefSize (Widget *widget, Requisition *size)
+{
+ size->width = size->ascent = size->descent = 0;
+}
+
+void OOFPosAbsLikeMgr::sizeAllocateChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "sizeAllocateChildren");
+
+ int refWidth = container->getAvailWidth (true) - containerBoxDiffWidth ();
+ int refHeight = container->getAvailHeight (true) - containerBoxDiffHeight ();
+
+ for (int i = 0; i < children->size(); i++) {
+ Child *child = children->get (i);
+
+ int x, y, width, ascent, descent;
+ calcPosAndSizeChildOfChild (child, refWidth, refHeight, &x, &y, &width,
+ &ascent, &descent);
+
+ Allocation childAllocation;
+ childAllocation.x = containerAllocation.x + x + containerBoxOffsetX ();
+ childAllocation.y = containerAllocation.y + y + containerBoxOffsetY ();
+ childAllocation.width = width;
+ childAllocation.ascent = ascent;
+ childAllocation.descent = descent;
+
+ child->widget->sizeAllocate (&childAllocation);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPosAbsLikeMgr::getSize (Requisition *containerReq, int *oofWidth,
+ int *oofHeight)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getSize", "%d * (%d + %d)",
+ containerReq->width, containerReq->ascent,
+ containerReq->descent);
+
+ *oofWidth = *oofHeight = 0;
+
+ int refWidth = container->getAvailWidth (true);
+ int refHeight = container->getAvailHeight (true);
+
+ for (int i = 0; i < children->size(); i++) {
+ Child *child = children->get(i);
+
+ // Children whose position cannot be determined will be
+ // considered later in sizeAllocateEnd.
+ if (posXDefined (child) && posYDefined (child)) {
+ int x, y, width, ascent, descent;
+ calcPosAndSizeChildOfChild (child, refWidth, refHeight, &x, &y, &width,
+ &ascent, &descent);
+ *oofWidth = max (*oofWidth, x + width) + containerBoxDiffWidth ();
+ *oofHeight =
+ max (*oofHeight, y + ascent + descent) + containerBoxDiffHeight ();
+
+ child->consideredForSize = true;
+ } else
+ child->consideredForSize = false;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d * %d", *oofWidth, *oofHeight);
+}
+
+void OOFPosAbsLikeMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ containerExtr->minWidth, containerExtr->maxWidth);
+
+ *oofMinWidth = *oofMaxWidth = 0;
+
+ for (int i = 0; i < children->size(); i++) {
+ Child *child = children->get(i);
+
+ // Children whose position cannot be determined will be
+ // considered later in sizeAllocateEnd.
+ if (posXDefined (child)) {
+ int x, width;
+ Extremes childExtr;
+ child->widget->getExtremes (&childExtr);
+
+ // Here, we put the extremes of the container in relation to
+ // the extremes of the child, as sizes are put in relation
+ // for calculating the size. In one case, the allocation is
+ // used: when neither "left" nor "right" is set, and so the
+ // position told by the generator is used.
+ //
+ // If you look at the Textblock widget, you'll find that this
+ // is always boxOffsetX(), and the horizontal position of a
+ // textblock within its parent is also constant; so this is
+ // not a problem.
+ //
+ // (TODO What about a table cell within a table?)
+
+ calcHPosAndSizeChildOfChild (child, containerExtr->minWidth,
+ childExtr.minWidth, &x, &width);
+ *oofMinWidth = max (*oofMinWidth, x + width);
+
+ calcHPosAndSizeChildOfChild (child, containerExtr->maxWidth,
+ childExtr.maxWidth, &x, &width);
+ *oofMaxWidth = max (*oofMaxWidth, x + width);
+
+ child->consideredForExtremes = true;
+ } else
+ child->consideredForExtremes = false;
+ }
+
+ *oofMinWidth += containerBoxDiffWidth ();
+ *oofMaxWidth += containerBoxDiffWidth ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> %d / %d", *oofMinWidth, *oofMaxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+int OOFPosAbsLikeMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0,
+ "OOFPositionedMgr/getAvailWidthOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int width;
+
+ if (child->getStyle()->width == style::LENGTH_AUTO &&
+ child->getStyle()->minWidth == style::LENGTH_AUTO &&
+ child->getStyle()->maxWidth == style::LENGTH_AUTO) {
+ // TODO This should (perhaps?) only used when 'width' is undefined.
+ // TODO Is "boxDiffWidth()" correct here?
+ DBG_OBJ_MSG ("resize.oofm", 1, "no specification");
+ if (forceValue) {
+ int availWidth = container->getAvailWidth (true), left, right;
+
+ // Regard undefined values as 0:
+ if (!getPosLeft (child, availWidth, &left)) left = 0;
+ if (!getPosRight (child, availWidth, &right)) right = 0;
+
+ width = max (availWidth - containerBoxDiffWidth () - left - right, 0);
+ } else
+ width = -1;
+ } else {
+ if (forceValue) {
+ int availWidth = container->getAvailWidth (true);
+ child->calcFinalWidth (child->getStyle(),
+ availWidth - containerBoxDiffWidth (), NULL,
+ 0, true, &width);
+ } else
+ width = -1;
+ }
+
+ if (width != -1)
+ width = max (width, child->getMinWidth (NULL, forceValue));
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+
+ return width;
+}
+
+int OOFPosAbsLikeMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0,
+ "OOFPositionedMgr/getAvailHeightOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int height;
+
+ if (child->getStyle()->height == style::LENGTH_AUTO &&
+ child->getStyle()->minHeight == style::LENGTH_AUTO &&
+ child->getStyle()->maxHeight == style::LENGTH_AUTO) {
+ // TODO This should (perhaps?) only used when 'height' is undefined.
+ // TODO Is "boxDiffHeight()" correct here?
+ DBG_OBJ_MSG ("resize.oofm", 1, "no specification");
+ if (forceValue) {
+ int availHeight = container->getAvailHeight (true), top, bottom;
+
+ // Regard undefined values as 0:
+ if (!getPosTop (child, availHeight, &top)) top = 0;
+ if (!getPosBottom (child, availHeight, &bottom)) bottom = 0;
+
+ height =
+ max (availHeight - containerBoxDiffHeight () - top - bottom, 0);
+ } else
+ height = -1;
+ } else {
+ if (forceValue) {
+ int availHeight = container->getAvailHeight (true);
+ height = child->calcHeight (child->getStyle()->height, true,
+ availHeight - containerBoxDiffHeight (),
+ NULL, true);
+ } else
+ height = -1;
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+bool OOFPosAbsLikeMgr::posXAbsolute (Child *child)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "posXAbsolute", "[%p]", child->widget);
+ bool b =
+ (style::isAbsLength (child->widget->getStyle()->left) ||
+ style::isPerLength (child->widget->getStyle()->left)) &&
+ (style::isAbsLength (child->widget->getStyle()->right) ||
+ style::isPerLength (child->widget->getStyle()->right));
+ DBG_OBJ_LEAVE_VAL ("%s", boolToStr (b));
+ return b;
+}
+
+bool OOFPosAbsLikeMgr::posYAbsolute (Child *child)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "posYAbsolute", "[%p]", child->widget);
+ bool b =
+ (style::isAbsLength (child->widget->getStyle()->top) ||
+ style::isPerLength (child->widget->getStyle()->top)) &&
+ (style::isAbsLength (child->widget->getStyle()->bottom) ||
+ style::isPerLength (child->widget->getStyle()->bottom));
+ DBG_OBJ_LEAVE_VAL ("%s", boolToStr (b));
+ return b;
+}
+
+void OOFPosAbsLikeMgr::calcPosAndSizeChildOfChild (Child *child, int refWidth,
+ int refHeight, int *xPtr,
+ int *yPtr, int *widthPtr,
+ int *ascentPtr,
+ int *descentPtr)
+{
+ // *xPtr and *yPtr refer to reference area; caller must adjust them.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "calcPosAndSizeChildOfChild",
+ "[%p], %d, %d, ...", child->widget, refWidth, refHeight);
+
+ // TODO (i) Consider {min|max}-{width|heigt}. (ii) Height is always
+ // apportioned to descent (ascent is preserved), which makes sense
+ // when the children are textblocks. (iii) Consider minimal width
+ // (getMinWidth)?
+
+ Requisition childRequisition;
+ child->widget->sizeRequest (&childRequisition);
+
+ calcHPosAndSizeChildOfChild (child, refWidth, childRequisition.width,
+ xPtr, widthPtr);
+ calcVPosAndSizeChildOfChild (child, refHeight, childRequisition.ascent,
+ childRequisition.descent, yPtr, ascentPtr,
+ descentPtr);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPosAbsLikeMgr::calcHPosAndSizeChildOfChild (Child *child, int refWidth,
+ int origChildWidth,
+ int *xPtr, int *widthPtr)
+{
+ assert (refWidth != -1 || (xPtr == NULL && widthPtr == NULL));
+
+ int width;
+ bool widthDefined;
+ if (style::isAbsLength (child->widget->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "absolute width: %dpx",
+ style::absLengthVal (child->widget->getStyle()->width));
+ width = style::absLengthVal (child->widget->getStyle()->width)
+ + child->widget->boxDiffWidth ();
+ widthDefined = true;
+ } else if (style::isPerLength (child->widget->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->widget->getStyle()->width));
+ width = style::multiplyWithPerLength (refWidth,
+ child->widget->getStyle()->width)
+ + child->widget->boxDiffWidth ();
+ widthDefined = true;
+ } else {
+ DBG_OBJ_MSG ("resize.oofm", 1, "width not specified");
+ width = origChildWidth;
+ widthDefined = false;
+ }
+
+ int left, right;
+ bool leftDefined = getPosLeft (child->widget, refWidth, &left),
+ rightDefined = getPosRight (child->widget, refWidth, &right);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> left = %d, right = %d, width = %d (defined: %s)",
+ left, right, width, widthDefined ? "true" : "false");
+
+ if (xPtr) {
+ if (!leftDefined && !rightDefined)
+ *xPtr = generatorPosX (child) + child->x;
+ else {
+ if (!leftDefined && rightDefined)
+ *xPtr = refWidth - width - right - containerBoxRestWidth ();
+ else if (leftDefined && !rightDefined)
+ *xPtr = left + containerBoxOffsetX ();
+ else {
+ *xPtr = left;
+ if (!widthDefined) {
+ width = refWidth - (left + right + containerBoxDiffWidth ());
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> width (corrected) = %d",
+ width);
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> x = %d", *xPtr);
+ }
+
+ if (widthPtr)
+ *widthPtr = width;
+}
+
+void OOFPosAbsLikeMgr::calcVPosAndSizeChildOfChild (Child *child, int refHeight,
+ int origChildAscent,
+ int origChildDescent,
+ int *yPtr, int *ascentPtr,
+ int *descentPtr)
+{
+ assert (refHeight != -1 ||
+ (yPtr == NULL && ascentPtr == NULL && descentPtr == NULL));
+
+ int ascent = origChildAscent, descent = origChildDescent;
+ bool heightDefined;
+
+ if (style::isAbsLength (child->widget->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "absolute height: %dpx",
+ style::absLengthVal (child->widget->getStyle()->height));
+ int height = style::absLengthVal (child->widget->getStyle()->height)
+ + child->widget->boxDiffHeight ();
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ heightDefined = true;
+ } else if (style::isPerLength (child->widget->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->widget->getStyle()->height));
+ int height =
+ style::multiplyWithPerLength (refHeight,
+ child->widget->getStyle()->height)
+ + child->widget->boxDiffHeight ();
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ heightDefined = true;
+ } else {
+ DBG_OBJ_MSG ("resize.oofm", 1, "height not specified");
+ heightDefined = false;
+ }
+
+ int top, bottom;
+ bool topDefined = getPosTop (child->widget, refHeight, &top),
+ bottomDefined = getPosBottom (child->widget, refHeight, &bottom);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> top = %d, bottom = %d, height = %d + %d (defined: %s)",
+ top, bottom, ascent, descent,
+ heightDefined ? "true" : "false");
+
+ if (yPtr) {
+ if (!topDefined && !bottomDefined)
+ *yPtr = generatorPosY (child) + child->y;
+ else {
+ if (!topDefined && bottomDefined)
+ *yPtr = refHeight - (ascent + descent) - bottom
+ - containerBoxDiffHeight ();
+ else if (topDefined && !bottomDefined)
+ *yPtr = top + containerBoxOffsetY ();
+ else {
+ *yPtr = top;
+ if (!heightDefined) {
+ int height =
+ refHeight - (top + bottom + containerBoxDiffHeight ());
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ DBG_OBJ_MSGF ("resize.oofm", 0,
+ "=> ascent + descent (corrected) = %d + %d",
+ ascent, descent);
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> y = %d", *yPtr);
+ }
+
+ if (ascentPtr)
+ *ascentPtr = ascent;
+ if (descentPtr)
+ *descentPtr = descent;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposabslikemgr.hh b/dw/oofposabslikemgr.hh
new file mode 100644
index 00000000..f9e94a5d
--- /dev/null
+++ b/dw/oofposabslikemgr.hh
@@ -0,0 +1,61 @@
+#ifndef __DW_OOFPOSABSLIKEMGR_HH__
+#define __DW_OOFPOSABSLIKEMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosAbsLikeMgr: public OOFPositionedMgr
+{
+protected:
+ virtual int containerBoxOffsetX () = 0;
+ virtual int containerBoxOffsetY () = 0;
+ virtual int containerBoxRestWidth () = 0;
+ virtual int containerBoxRestHeight () = 0;
+
+ inline int containerBoxDiffWidth ()
+ { return containerBoxOffsetX () + containerBoxRestWidth (); }
+ inline int containerBoxDiffHeight ()
+ { return containerBoxOffsetY () + containerBoxRestHeight (); }
+
+ bool haveExtremesChanged ();
+
+ void sizeAllocateChildren ();
+
+ bool posXAbsolute (Child *child);
+ bool posYAbsolute (Child *child);
+
+ void calcPosAndSizeChildOfChild (Child *child, int refWidth, int refHeight,
+ int *xPtr, int *yPtr, int *widthPtr,
+ int *ascentPtr, int *descentPtr);
+ void calcHPosAndSizeChildOfChild (Child *child, int refWidth,
+ int origChildWidth, int *xPtr,
+ int *widthPtr);
+ void calcVPosAndSizeChildOfChild (Child *child, int refHeight,
+ int origChildAscent, int origChildDescent,
+ int *yPtr, int *ascentPtr,
+ int *descentPtr);
+
+
+public:
+ OOFPosAbsLikeMgr (OOFAwareWidget *container);
+ ~OOFPosAbsLikeMgr ();
+
+ void calcWidgetRefSize (core::Widget *widget, core::Requisition *size);
+
+ void getSize (core::Requisition *containerReq, int *oofWidth,
+ int *oofHeight);
+ void getExtremes (core::Extremes *containerExtr,
+ int *oofMinWidth, int *oofMaxWidth);
+
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFPOSABSLIKEMGR_HH__
diff --git a/dw/oofposabsmgr.cc b/dw/oofposabsmgr.cc
new file mode 100644
index 00000000..c8bc64b1
--- /dev/null
+++ b/dw/oofposabsmgr.cc
@@ -0,0 +1,68 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofposabsmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+OOFPosAbsMgr::OOFPosAbsMgr (OOFAwareWidget *container) :
+ OOFPosAbsLikeMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosAbsMgr");
+}
+
+OOFPosAbsMgr::~OOFPosAbsMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+// Comment for all containerBox* implementations: for the toplevel
+// widget, assume margin = border = 0 (should perhaps set so when
+// widgets are constructed), so that the padding area is actually the
+// allocation.
+
+int OOFPosAbsMgr::containerBoxOffsetX ()
+{
+ return container->getParent () ?
+ container->boxOffsetX () - container->getStyle()->padding.left : 0;
+}
+
+int OOFPosAbsMgr::containerBoxOffsetY ()
+{
+ return container->getParent () ?
+ container->boxOffsetY () - container->getStyle()->padding.top : 0;
+}
+
+int OOFPosAbsMgr::containerBoxRestWidth ()
+{
+ return container->getParent () ?
+ container->boxRestWidth () - container->getStyle()->padding.right : 0;
+}
+
+int OOFPosAbsMgr::containerBoxRestHeight ()
+{
+ return container->getParent () ?
+ container->boxRestHeight () - container->getStyle()->padding.bottom : 0;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposabsmgr.hh b/dw/oofposabsmgr.hh
new file mode 100644
index 00000000..153f8ff2
--- /dev/null
+++ b/dw/oofposabsmgr.hh
@@ -0,0 +1,27 @@
+#ifndef __DW_OOFPOSABSMGR_HH__
+#define __DW_OOFPOSABSMGR_HH__
+
+#include "oofposabslikemgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosAbsMgr: public OOFPosAbsLikeMgr
+{
+protected:
+ int containerBoxOffsetX ();
+ int containerBoxOffsetY ();
+ int containerBoxRestWidth ();
+ int containerBoxRestHeight ();
+
+public:
+ OOFPosAbsMgr (OOFAwareWidget *container);
+ ~OOFPosAbsMgr ();
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFPOSABSMGR_HH__
diff --git a/dw/oofposfixedmgr.cc b/dw/oofposfixedmgr.cc
new file mode 100644
index 00000000..1b36cd5c
--- /dev/null
+++ b/dw/oofposfixedmgr.cc
@@ -0,0 +1,59 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofposfixedmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+OOFPosFixedMgr::OOFPosFixedMgr (OOFAwareWidget *container) :
+ OOFPosAbsLikeMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosFixedMgr");
+}
+
+OOFPosFixedMgr::~OOFPosFixedMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+int OOFPosFixedMgr::containerBoxOffsetX ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxOffsetY ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxRestWidth ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxRestHeight ()
+{
+ return 0;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposfixedmgr.hh b/dw/oofposfixedmgr.hh
new file mode 100644
index 00000000..3f7b9683
--- /dev/null
+++ b/dw/oofposfixedmgr.hh
@@ -0,0 +1,27 @@
+#ifndef __DW_OOFPOSFIXEDMGR_HH__
+#define __DW_OOFPOSFIXEDMGR_HH__
+
+#include "oofposabslikemgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosFixedMgr: public OOFPosAbsLikeMgr
+{
+protected:
+ int containerBoxOffsetX ();
+ int containerBoxOffsetY ();
+ int containerBoxRestWidth ();
+ int containerBoxRestHeight ();
+
+public:
+ OOFPosFixedMgr (OOFAwareWidget *container);
+ ~OOFPosFixedMgr ();
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFPOSFIXEDMGR_HH__
diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc
new file mode 100644
index 00000000..1ab7e06e
--- /dev/null
+++ b/dw/oofpositionedmgr.cc
@@ -0,0 +1,396 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofpositionedmgr.hh"
+#include "../lout/debug.hh"
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace dw {
+
+namespace oof {
+
+OOFPositionedMgr::Child::Child (core::Widget *widget, OOFAwareWidget *generator,
+ int externalIndex)
+{
+ this->widget = widget;
+ this->generator = generator;
+ this->externalIndex = externalIndex;
+
+ x = y = 0;
+
+ // Initially, this child does not actually have been considered,
+ // but since adding a new element will force a size/extremes
+ // calculation, this is equivalent.
+ consideredForSize = consideredForExtremes = true;
+}
+
+OOFPositionedMgr::OOFPositionedMgr (OOFAwareWidget *container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPositionedMgr");
+
+ this->container = (OOFAwareWidget*)container;
+ children = new Vector<Child> (1, false);
+ childrenByWidget = new HashTable<TypedPointer<Widget>, Child> (true, true);
+
+ containerAllocation = *(container->getAllocation());
+
+ DBG_OBJ_SET_NUM ("children.size", children->size());
+}
+
+OOFPositionedMgr::~OOFPositionedMgr ()
+{
+ delete children;
+ delete childrenByWidget;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFPositionedMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ if (caller == container) {
+ if (containerAllocationState == NOT_ALLOCATED)
+ containerAllocationState = IN_ALLOCATION;
+ containerAllocation = *allocation;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFPositionedMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == container) {
+ sizeAllocateChildren ();
+
+ bool extremesChanged = !allChildrenConsideredForExtremes ();
+ if (extremesChanged || doChildrenExceedContainer () ||
+ !allChildrenConsideredForSize ())
+ container->oofSizeChanged (extremesChanged);
+
+ containerAllocationState = WAS_ALLOCATED;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFPositionedMgr::doChildrenExceedContainer ()
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "doChildrenExceedContainer");
+
+ // This method is called to determine whether the *requisition* of
+ // the container must be recalculated. So, we check the allocations
+ // of the children against the *requisition* of the container,
+ // which may (e. g. within tables) differ from the new allocation.
+ // (Generally, a widget may allocated at a different size.)
+
+ Requisition containerReq;
+ container->sizeRequest (&containerReq);
+ bool exceeds = false;
+
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < children->size () && !exceeds; i++) {
+ Child *child = children->get (i);
+ Allocation *childAlloc = child->widget->getAllocation ();
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "Does childAlloc = (%d, %d, %d * %d) exceed container "
+ "alloc+req = (%d, %d, %d * %d)?",
+ childAlloc->x, childAlloc->y, childAlloc->width,
+ childAlloc->ascent + childAlloc->descent,
+ containerAllocation.x, containerAllocation.y,
+ containerReq.width,
+ containerReq.ascent + containerReq.descent);
+ if (childAlloc->x + childAlloc->width
+ > containerAllocation.x + containerReq.width ||
+ childAlloc->y + childAlloc->ascent + childAlloc->descent
+ > containerAllocation.y +
+ containerReq.ascent + containerReq.descent) {
+ exceeds = true;
+ DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 2, "No.");
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return exceeds;
+}
+
+void OOFPositionedMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < children->size(); i++)
+ children->get(i)->widget->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::draw (View *view, Rectangle *area,
+ DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ for (int i = 0; i < children->size(); i++) {
+ Child *child = children->get(i);
+
+ Rectangle childArea;
+ if (!context->hasWidgetBeenProcessedAsInterruption (child->widget) &&
+ !StackingContextMgr::handledByStackingContextMgr (child->widget) &&
+ child->widget->intersects (container, area, &childArea))
+ child->widget->draw (view, &childArea, context);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::addWidgetInFlow (OOFAwareWidget *widget,
+ OOFAwareWidget *parent,
+ int externalIndex)
+{
+}
+
+int OOFPositionedMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generator,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generator, externalIndex);
+
+ Child *child = new Child (widget, generator, externalIndex);
+ children->put (child);
+ childrenByWidget->put (new TypedPointer<Widget> (widget), child);
+
+ int subRef = children->size() - 1;
+ DBG_OBJ_SET_NUM ("children.size", children->size());
+ DBG_OBJ_ARRSET_PTR ("children", children->size() - 1, widget);
+
+ DBG_OBJ_SET_PTR_O (widget, "<Positioned>.generator", generator);
+ DBG_OBJ_SET_NUM_O (widget, "<Positioned>.externalIndex", externalIndex);
+
+ DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef);
+ DBG_OBJ_LEAVE ();
+ return subRef;
+}
+
+void OOFPositionedMgr::moveExternalIndices (OOFAwareWidget *generator,
+ int oldStartIndex, int diff)
+{
+ for (int i = 0; i < children->size (); i++) {
+ Child *child = children->get (i);
+ if (child->externalIndex >= oldStartIndex) {
+ child->externalIndex += diff;
+ DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.externalIndex",
+ child->externalIndex);
+ }
+ }
+}
+
+void OOFPositionedMgr::markSizeChange (int ref)
+{
+}
+
+
+void OOFPositionedMgr::markExtremesChange (int ref)
+{
+}
+
+Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext
+ *context)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+
+ for (int i = children->size() - 1; widgetAtPoint == NULL && i >= 0; i--) {
+ Widget *childWidget = children->get(i)->widget;
+ if (!context->hasWidgetBeenProcessedAsInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget))
+ widgetAtPoint = childWidget->getWidgetAtPoint (x, y, context);
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+
+ return widgetAtPoint;
+}
+
+void OOFPositionedMgr::tellPosition1 (Widget *widget, int x, int y)
+{
+}
+
+void OOFPositionedMgr::tellPosition2 (Widget *widget, int x, int y)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition2", "%p, %d, %d",
+ widget, x, y);
+
+ TypedPointer<Widget> key (widget);
+ Child *child = childrenByWidget->get (&key);
+ assert (child);
+
+ child->x = x;
+ child->y = y;
+
+ DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.x", x);
+ DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.y", y);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::tellIncompletePosition1 (Widget *generator,
+ Widget *widget, int x, int y)
+{
+ // Nothing to do.
+}
+
+void OOFPositionedMgr::tellIncompletePosition2 (Widget *generator,
+ Widget *widget, int x, int y)
+{
+ // TODO
+}
+
+bool OOFPositionedMgr::containerMustAdjustExtraSpace ()
+{
+ return true;
+}
+
+int OOFPositionedMgr::getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return false;
+}
+
+
+int OOFPositionedMgr::getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getClearPosition (OOFAwareWidget *widget)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::affectsLeftBorder (Widget *widget)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::affectsRightBorder (Widget *widget)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::mayAffectBordersAtAll ()
+{
+ return false;
+}
+
+bool OOFPositionedMgr::dealingWithSizeOfChild (Widget *child)
+{
+ return true;
+}
+
+int OOFPositionedMgr::getNumWidgets ()
+{
+ return children->size();
+}
+
+Widget *OOFPositionedMgr::getWidget (int i)
+{
+ return children->get(i)->widget;
+}
+
+bool OOFPositionedMgr::getPosBorder (style::Length cssValue, int refLength,
+ int *result)
+{
+ if (style::isAbsLength (cssValue)) {
+ *result = style::absLengthVal (cssValue);
+ return true;
+ } else if (style::isPerLength (cssValue)) {
+ *result = style::multiplyWithPerLength (refLength, cssValue);
+ return true;
+ } else
+ // "false" means "undefined":
+ return false;
+}
+
+bool OOFPositionedMgr::allChildrenConsideredForSize ()
+{
+ for (int i = 0; i < children->size(); i++)
+ if (!children->get(i)->consideredForSize)
+ return false;
+ return true;
+}
+
+bool OOFPositionedMgr::allChildrenConsideredForExtremes ()
+{
+ for (int i = 0; i < children->size(); i++)
+ if (!children->get(i)->consideredForExtremes)
+ return false;
+ return true;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh
new file mode 100644
index 00000000..09706235
--- /dev/null
+++ b/dw/oofpositionedmgr.hh
@@ -0,0 +1,143 @@
+ #ifndef __DW_OOFPOSITIONEDMGR_HH__
+#define __DW_OOFPOSITIONEDMGR_HH__
+
+#include "outofflowmgr.hh"
+#include "oofawarewidget.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPositionedMgr: public OutOfFlowMgr
+{
+protected:
+ class Child: public lout::object::Object
+ {
+ public:
+ core::Widget *widget;
+ OOFAwareWidget *generator;
+ int externalIndex, x, y;
+ bool consideredForSize, consideredForExtremes;
+
+ Child (core::Widget *widget, OOFAwareWidget *generator,
+ int externalIndex);
+ };
+
+ OOFAwareWidget *container;
+ core::Allocation containerAllocation;
+ enum { NOT_ALLOCATED, IN_ALLOCATION, WAS_ALLOCATED }
+ containerAllocationState;
+
+ lout::container::typed::Vector<Child> *children;
+ lout::container::typed::HashTable<lout::object::TypedPointer
+ <dw::core::Widget>,
+ Child> *childrenByWidget;
+
+ inline bool getPosLeft (core::Widget *child, int availWidth, int *result)
+ { return getPosBorder (child->getStyle()->left, availWidth, result); }
+ inline bool getPosRight (core::Widget *child, int availWidth, int *result)
+ { return getPosBorder (child->getStyle()->right, availWidth, result); }
+ inline bool getPosTop (core::Widget *child, int availHeight, int *result)
+ { return getPosBorder (child->getStyle()->top, availHeight, result); }
+ inline bool getPosBottom (core::Widget *child, int availHeight, int *result)
+ { return getPosBorder (child->getStyle()->bottom, availHeight, result); }
+
+ bool getPosBorder (core::style::Length cssValue, int refLength, int *result);
+
+ bool allChildrenConsideredForSize ();
+ bool allChildrenConsideredForExtremes ();
+
+ bool doChildrenExceedContainer ();
+
+ virtual void sizeAllocateChildren () = 0;
+ virtual bool posXAbsolute (Child *child) = 0;
+ virtual bool posYAbsolute (Child *child) = 0;
+
+ inline bool generatorPosDefined (Child *child) {
+ return child->generator == container ||
+ (containerAllocationState != NOT_ALLOCATED
+ && child->generator->wasAllocated ());
+ }
+ inline int generatorPosX (Child *child) {
+ assert (generatorPosDefined (child));
+ return child->generator == container ? 0 :
+ child->generator->getAllocation()->x - containerAllocation.x;
+ }
+ inline int generatorPosY (Child *child) {
+ assert (generatorPosDefined (child));
+ return child->generator == container ? 0 :
+ child->generator->getAllocation()->y - containerAllocation.y;
+ }
+
+ inline bool posXDefined (Child *child)
+ { return posXAbsolute (child) || generatorPosDefined (child); }
+
+ inline bool posYDefined (Child *child)
+ { return posYAbsolute (child) || generatorPosDefined (child); }
+
+public:
+ OOFPositionedMgr (OOFAwareWidget *container);
+ ~OOFPositionedMgr ();
+
+ void sizeAllocateStart (OOFAwareWidget *caller,
+ core::Allocation *allocation);
+ void sizeAllocateEnd (OOFAwareWidget *caller);
+
+ void containerSizeChangedForChildren ();
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *context);
+
+ void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent,
+ int externalIndex);
+ int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator,
+ int externalIndex);
+ void moveExternalIndices (OOFAwareWidget *generator, int oldStartIndex,
+ int diff);
+
+ void tellPosition1 (core::Widget *widget, int x, int y);
+ void tellPosition2 (core::Widget *widget, int x, int y);
+ void tellIncompletePosition1 (core::Widget *generator, core::Widget *widget,
+ int x, int y);
+ void tellIncompletePosition2 (core::Widget *generator, core::Widget *widget,
+ int x, int y);
+
+
+ bool containerMustAdjustExtraSpace ();
+
+ int getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ int getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ bool hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ bool hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ int getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ int getClearPosition (OOFAwareWidget *widget);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+ bool mayAffectBordersAtAll ();
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+
+ int getNumWidgets ();
+ core::Widget *getWidget (int i);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFPOSITIONEDMGR_HH__
diff --git a/dw/oofposrelmgr.cc b/dw/oofposrelmgr.cc
new file mode 100644
index 00000000..c19eb2e7
--- /dev/null
+++ b/dw/oofposrelmgr.cc
@@ -0,0 +1,249 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofposrelmgr.hh"
+
+using namespace dw::core;
+using namespace lout::object;
+using namespace lout::misc;
+
+namespace dw {
+
+namespace oof {
+
+OOFPosRelMgr::OOFPosRelMgr (OOFAwareWidget *container) :
+ OOFPositionedMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosRelMgr");
+}
+
+OOFPosRelMgr::~OOFPosRelMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+
+void OOFPosRelMgr::markSizeChange (int ref)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
+ Child *child = children->get(ref);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "generator = %p, externalIndex = %d",
+ child->generator, child->externalIndex);
+ child->generator->widgetRefSizeChanged (child->externalIndex);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPosRelMgr::markExtremesChange (int ref)
+{
+}
+
+void OOFPosRelMgr::calcWidgetRefSize (Widget *widget, Requisition *size)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "calcWidgetRefSize", "%p", widget);
+
+ widget->sizeRequest (size);
+
+ // In some cases, the widget has been enlarged for widgets out of
+ // flow. Partly, this is done by adding "extra space"; however, at
+ // this point, the extra space is not relevant here. See
+ // "oofawarewidget.cc" for a calculation of RequisitionWithoutOOF.
+ // (Notice also that Widget::sizeRequest has to be called in all
+ // cases.)
+
+ if (widget->instanceOf (OOFAwareWidget::CLASS_ID))
+ *size = *((OOFAwareWidget*)widget)->getRequisitionWithoutOOF ();
+
+
+ DBG_OBJ_LEAVE_VAL ("%d * (%d + %d)",
+ size->width, size->ascent, size->descent);
+}
+
+
+void OOFPosRelMgr::sizeAllocateChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "sizeAllocateChildren");
+
+ for (int i = 0; i < children->size (); i++) {
+ Child *child = children->get(i);
+
+ Requisition childReq;
+ child->widget->sizeRequest (&childReq);
+
+ Allocation childAlloc;
+ childAlloc.x = containerAllocation.x + getChildPosX (child);
+ childAlloc.y = containerAllocation.y + getChildPosY (child);
+ childAlloc.width = childReq.width;
+ childAlloc.ascent = childReq.ascent;
+ childAlloc.descent = childReq.descent;
+ child->widget->sizeAllocate (&childAlloc);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPosRelMgr::getSize (Requisition *containerReq, int *oofWidth,
+ int *oofHeight)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getSize", "%d * (%d + %d)",
+ containerReq->width, containerReq->ascent,
+ containerReq->descent);
+
+ *oofWidth = *oofHeight = 0;
+
+ for (int i = 0; i < children->size (); i++) {
+ Child *child = children->get(i);
+
+ // Children whose position cannot be determined will be
+ // considered later in sizeAllocateEnd.
+ if (posXDefined (child) && posYDefined (child)) {
+ Requisition childReq;
+ child->widget->sizeRequest (&childReq);
+ *oofWidth = max (*oofWidth, getChildPosX (child) + childReq.width);
+ *oofHeight = max (*oofHeight,
+ getChildPosY (child) + childReq.ascent
+ + childReq.descent);
+
+ child->consideredForSize = true;
+ } else
+ child->consideredForSize = false;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d * %d", *oofWidth, *oofHeight);
+}
+
+void OOFPosRelMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ *oofMinWidth = *oofMaxWidth = 0;
+
+ for (int i = 0; i < children->size (); i++) {
+ Child *child = children->get(i);
+
+ // Children whose position cannot be determined will be
+ // considered later in sizeAllocateEnd.
+ if (posXDefined (child)) {
+ Extremes childExtr;
+ child->widget->getExtremes (&childExtr);
+
+ // Put the extremes of the container in relation to the extremes
+ // of the child, as in OOFPosAbsLikeMgr::getExtremes (see
+ // comment there).
+ *oofMinWidth = max (*oofMinWidth,
+ getChildPosX (child, containerExtr->minWidth)
+ + childExtr.minWidth);
+ *oofMaxWidth = max (*oofMaxWidth,
+ getChildPosX (child, containerExtr->maxWidth)
+ + childExtr.maxWidth);
+
+ child->consideredForExtremes = true;
+ } else
+ child->consideredForExtremes = false;
+ }
+}
+
+bool OOFPosRelMgr::posXAbsolute (Child *child)
+{
+ return false;
+}
+
+bool OOFPosRelMgr::posYAbsolute (Child *child)
+{
+ return false;
+}
+
+int OOFPosRelMgr::getChildPosX (Child *child, int refWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getChildPosX", "[%p], %d",
+ child->widget, refWidth);
+
+ int gx = generatorPosX (child);
+ int dim = getChildPosDim (child->widget->getStyle()->left,
+ child->widget->getStyle()->right,
+ child->x,
+ refWidth
+ - child->widget->getStyle()->boxDiffWidth ());
+
+ DBG_OBJ_LEAVE_VAL ("%d + %d = %d", gx, dim, gx + dim);
+ return gx + dim;
+}
+
+
+int OOFPosRelMgr::getChildPosY (Child *child, int refHeight)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getChildPosY", "[%p], %d",
+ child->widget, refHeight);
+
+ int gy = generatorPosY (child);
+ int dim = getChildPosDim (child->widget->getStyle()->top,
+ child->widget->getStyle()->bottom,
+ child->y,
+ refHeight
+ - child->widget->getStyle()->boxDiffHeight ());
+
+ DBG_OBJ_LEAVE_VAL ("%d + %d = %d", gy, dim, gy + dim);
+ return gy + dim;
+}
+
+int OOFPosRelMgr::getChildPosDim (style::Length posCssValue,
+ style::Length negCssValue, int refPos,
+ int refLength)
+{
+ // posCssValue refers to "left" or "top", negCssValue refers to "right" or
+ // "bottom". The former values are preferred ("left" over "right" etc.),
+ // which should later depend on the CSS value "direction".
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getChildPosDim",
+ "<i>%d</i>, <i>%d</i>, %d, %d",
+ posCssValue, negCssValue, refPos, refLength);
+
+ int diff;
+ if (getPosBorder (posCssValue, refLength, &diff))
+ DBG_OBJ_MSGF ("resize.oofm", 1, "posCssValue: diff = %d", diff);
+ else {
+ if (getPosBorder (negCssValue, refLength, &diff)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "negCssValue: diff = %d", diff);
+ diff *= -1;
+ } else
+ diff = 0;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d + %d = %d", refPos, diff, refPos + diff);
+ return refPos + diff;
+}
+
+bool OOFPosRelMgr::dealingWithSizeOfChild (Widget *child)
+{
+ return false;
+}
+
+int OOFPosRelMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+int OOFPosRelMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposrelmgr.hh b/dw/oofposrelmgr.hh
new file mode 100644
index 00000000..d61c15d9
--- /dev/null
+++ b/dw/oofposrelmgr.hh
@@ -0,0 +1,50 @@
+#ifndef __DW_OOFPOSRELMGR_HH__
+#define __DW_OOFPOSRELMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosRelMgr: public OOFPositionedMgr
+{
+protected:
+ void sizeAllocateChildren ();
+ bool posXAbsolute (Child *child);
+ bool posYAbsolute (Child *child);
+
+ int getChildPosX (Child *child, int refWidth);
+ int getChildPosY (Child *child, int refHeight);
+ int getChildPosDim (core::style::Length posCssValue,
+ core::style::Length negCssValue, int refPos,
+ int refLength);
+
+ inline int getChildPosX (Child *child)
+ { return getChildPosX (child, container->getAvailWidth (true)); }
+ inline int getChildPosY (Child *child)
+ { return getChildPosY (child, container->getAvailHeight (true)); }
+
+public:
+ OOFPosRelMgr (OOFAwareWidget *container);
+ ~OOFPosRelMgr ();
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ void calcWidgetRefSize (core::Widget *widget, core::Requisition *size);
+
+ void getSize (core::Requisition *containerReq, int *oofWidth,
+ int *oofHeight);
+ void getExtremes (core::Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth);
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFPOSRELMGR_HH__
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc
index 5081a2cb..405c5e62 100644
--- a/dw/outofflowmgr.cc
+++ b/dw/outofflowmgr.cc
@@ -19,2275 +19,22 @@
#include "outofflowmgr.hh"
-#include "textblock.hh"
+#include "oofawarewidget.hh"
#include "../lout/debug.hh"
-using namespace lout::object;
-using namespace lout::container::typed;
-using namespace lout::misc;
-using namespace dw::core;
-using namespace dw::core::style;
namespace dw {
-OutOfFlowMgr::WidgetInfo::WidgetInfo (OutOfFlowMgr *oofm, Widget *widget)
-{
- this->oofm = oofm;
- this->widget = widget;
- wasAllocated = false;
- xCB = yCB = width = height = -1;
-}
-
-void OutOfFlowMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
- int width, int height)
-{
- DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
- wasAllocated ? "true" : "false", xCB, yCB, width, height);
-
- this->wasAllocated = wasAllocated;
- this->xCB = xCB;
- this->yCB = yCB;
- this->width = width;
- this->height = height;
-
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
-
- DBG_OBJ_LEAVE_O (widget);
-}
-
-// ----------------------------------------------------------------------
-
-OutOfFlowMgr::Float::Float (OutOfFlowMgr *oofm, Widget *widget,
- Textblock *generatingBlock, int externalIndex) :
- WidgetInfo (oofm, widget)
-{
- this->generatingBlock = generatingBlock;
- this->externalIndex = externalIndex;
-
- yReq = yReal = size.width = size.ascent = size.descent = 0;
- dirty = sizeChangedSinceLastAllocation = true;
- indexGBList = indexCBList = -1;
-
- // Sometimes a float with widget = NULL is created as a key; this
- // is not interesting for RTFL.
- if (widget) {
- DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
- sizeChangedSinceLastAllocation);
- }
-}
-
-void OutOfFlowMgr::Float::updateAllocation ()
-{
- DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
-
- update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
- getNewHeight ());
-
- DBG_OBJ_LEAVE_O (getWidget ());
-}
-
-void OutOfFlowMgr::Float::intoStringBuffer(StringBuffer *sb)
-{
- sb->append ("{ widget = ");
- sb->appendPointer (getWidget ());
-
- if (getWidget ()) {
- sb->append (" (");
- sb->append (getWidget()->getClassName ());
- sb->append (")");
- }
-
- sb->append (", indexGBList = ");
- sb->appendInt (indexGBList);
- sb->append (", indexCBList = ");
- sb->appendInt (indexCBList);
- sb->append (", sideSpanningIndex = ");
- sb->appendInt (sideSpanningIndex);
- sb->append (", generatingBlock = ");
- sb->appendPointer (generatingBlock);
- sb->append (", yReq = ");
- sb->appendInt (yReq);
- sb->append (", yReal = ");
- sb->appendInt (yReal);
- sb->append (", size = { ");
- sb->appendInt (size.width);
- sb->append (" * ");
- sb->appendInt (size.ascent);
- sb->append (" + ");
- sb->appendInt (size.descent);
- sb->append (" }, dirty = ");
- sb->appendBool (dirty);
- sb->append (", sizeChangedSinceLastAllocation = ");
- sb->appendBool (sizeChangedSinceLastAllocation);
- sb->append (" }");
-}
-
-bool OutOfFlowMgr::Float::covers (Textblock *textblock, int y, int h)
-{
- DBG_OBJ_ENTER_O ("border", 0, getOutOfFlowMgr (), "covers",
- "%p, %d, %d [vloat: %p]",
- textblock, y, h, getWidget ());
-
- bool b;
-
- if (textblock == generatingBlock) {
- int reqyGB = y;
- int flyGB = yReal;
- getOutOfFlowMgr()->ensureFloatSize (this);
- int flh = size.ascent + size.descent;
- b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "for generator: reqyGB = %d, flyGB = %d, "
- "flh = %d + %d = %d => %s",
- reqyGB, flyGB, size.ascent, size.descent, flh,
- b ? "true" : "false");
- } else {
- // (If the textblock were not allocated, the GB list would have
- // been choosen instead of the CB list, and so this else-branch
- // would not have been not executed.)
- assert (getOutOfFlowMgr()->wasAllocated (textblock));
-
- if (!getWidget()->wasAllocated ()) {
- DBG_OBJ_MSG_O ("border", 1, getOutOfFlowMgr (),
- "not generator (not allocated) => false");
- b = false;
- } else {
- Allocation *tba = getOutOfFlowMgr()->getAllocation(textblock),
- *fla = getWidget()->getAllocation ();
- int reqyCanv = tba->y + y;
- int flyCanv = fla->y;
- int flh = fla->ascent + fla->descent;
- b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "not generator (allocated): reqyCanv = %d + %d = %d, "
- "flyCanv = %d, flh = %d + %d = %d => %s",
- tba->y, y, reqyCanv, flyCanv,
- fla->ascent, fla->descent, flh, b ? "true" : "false");
- }
- }
-
- DBG_OBJ_LEAVE_O (getOutOfFlowMgr ());
-
- return b;
-}
-
-int OutOfFlowMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
-{
- Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
- int r;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm,
- "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
- fl1->getIndex (type), fl2->getIndex (type), refTB);
-
- if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
- r = fl1->yReal - fl2->yReal;
- } else {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
- DBG_OBJ_MSG_START_O (oofm);
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
- fl1->generatingBlock, fl2->generatingBlock);
-
- // (i) Floats may not yet been allocated. Non-allocated floats
- // do not have an effect yet, they are considered "at the end"
- // of the list.
-
- // (ii) Float::widget is NULL for the key used for binary
- // search. In this case, Float::yReal is used instead (which is
- // set in SortedFloatsVector::find, too). The generator is the
- // textblock, and should be allocated. (If not, the GB list
- // would have been choosen instead of the CB list, and so this
- // else-branch would not have been not executed.)
-
- bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
- bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
- fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
- a2 ? "yes" : "no");
-
- if (a1 && a2) {
- int fly1, fly2;
-
- if (fl1->getWidget()) {
- fly1 = fl1->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
- } else {
- assert (oofm->wasAllocated (fl1->generatingBlock));
- fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
- oofm->getAllocation(fl1->generatingBlock)->y,
- fl1->yReal, fly1);
- }
-
- if (fl2->getWidget()) {
- fly2 = fl2->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
- } else {
- assert (oofm->wasAllocated (fl2->generatingBlock));
- fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
- oofm->getAllocation(fl2->generatingBlock)->y,
- fl2->yReal, fly2);
- }
-
- r = fly1 - fly2;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
- } else if (a1 && !a2)
- r = -1;
- else if (!a1 && a2)
- r = +1;
- else // if (!a1 && !a2)
- return 0;
-
- DBG_OBJ_MSG_END_O (oofm);
- }
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
- Object *o2)
-{
- return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
-}
-
-int OutOfFlowMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
-{
- Float *f1 = (Float*)o1, *f2 = (Float*)o2;
- int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
- "#%d -> %p/%d, #%d -> %p/#%d",
- f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
- f2->getIndex (type), f2->generatingBlock,
- f2->externalIndex);
-
- if (f1->generatingBlock == f2->generatingBlock) {
- r = f1->externalIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(a) generating blocks equal => %d - %d = %d",
- f1->externalIndex, f2->externalIndex, r);
- } else {
- TBInfo *t1 = oofm->getTextblock (f1->generatingBlock),
- *t2 = oofm->getTextblock (f2->generatingBlock);
- bool rdef = false;
-
- for (TBInfo *t = t1; t != NULL; t = t->parent)
- if (t->parent == t2) {
- rdef = true;
- r = t->parentExtIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(b) %p is an achestor of %p; direct child is "
- "%p (%d) => %d - %d = %d\n",
- t2->getTextblock (), t1->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- t->parentExtIndex, f2->externalIndex, r);
- }
-
- for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
- if (t->parent == t1) {
- r = f1->externalIndex - t->parentExtIndex;
- rdef = true;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(c) %p is an achestor of %p; direct child is %p "
- "(%d) => %d - %d = %d\n",
- t1->getTextblock (), t2->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- f1->externalIndex, t->parentExtIndex, r);
- }
-
- if (!rdef) {
- r = t1->index - t2->index;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
- t1->index, t2->index, r);
- }
- }
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::findFloatIndex (Textblock *lastGB,
- int lastExtIndex)
-{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
- lastGB, lastExtIndex);
-
- Float key (oofm, NULL, lastGB, lastExtIndex);
- key.setIndex (type, -1); // for debugging
- Float::CompareGBAndExtIndex comparator (oofm, type);
- int i = bsearch (&key, false, &comparator);
-
- // At position i is the next larger element, so element i should
- // not included, but i - 1 returned; except if the exact element is
- // found: then include it and so return i.
- int r;
- if (i == size())
- r = i - 1;
- else {
- Float *f = get (i);
- if (comparator.compare (f, &key) == 0)
- r = i;
- else
- r = i - 1;
- }
-
- //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
- // "in %s list %p on the %s side\n",
- // oofm->containingBlock, lastGB, lastExtIndex, i, r, size (),
- // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
-
- //for (int i = 0; i < size (); i++) {
- // Float *f = get(i);
- // TBInfo *t = oofm->getTextblock(f->generatingBlock);
- // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
- // t->index, t->parent ? t->parent->textblock : NULL,
- // get(i)->externalIndex);
- //}
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
+namespace oof {
-int OutOfFlowMgr::SortedFloatsVector::find (Textblock *textblock, int y,
- int start, int end)
+OutOfFlowMgr::OutOfFlowMgr ()
{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d",
- textblock, y, start, end);
-
- Float key (oofm, NULL, NULL, 0);
- key.generatingBlock = textblock;
- key.yReal = y;
- key.setIndex (type, -1); // for debugging
- Float::ComparePosition comparator (oofm, textblock, type);
- int result = bsearch (&key, false, start, end, &comparator);
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
- DBG_OBJ_LEAVE_O (oofm);
- return result;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::findFirst (Textblock *textblock,
- int y, int h,
- Textblock *lastGB,
- int lastExtIndex,
- int *lastReturn)
-{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d",
- textblock, y, h, lastGB, lastExtIndex);
-
- DBG_IF_RTFL {
- DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:");
- DBG_OBJ_MSG_START_O (oofm);
-
- for (int i = 0; i < size(); i++) {
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), "
- "%s, %s, ext = %d, GB = %p); widget at (%d, %d)",
- i, get(i)->getWidget (), get(i)->getIndex (type),
- get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal,
- get(i)->size.width, get(i)->size.ascent,
- get(i)->size.descent,
- get(i)->dirty ? "dirty" : "clean",
- get(i)->sizeChangedSinceLastAllocation ? "scsla"
- : "sNcsla",
- get(i)->externalIndex, get(i)->generatingBlock,
- get(i)->getWidget()->getAllocation()->x,
- get(i)->getWidget()->getAllocation()->y);
- }
-
- DBG_OBJ_MSG_END_O (oofm);
- }
-
- int last = findFloatIndex (lastGB, lastExtIndex);
- DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last);
- assert (last < size());
-
- // If the caller wants to reuse this value:
- if (lastReturn)
- *lastReturn = last;
-
- int i = find (textblock, y, 0, last), result;
- DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i);
-
- // Note: The smallest value of "i" is 0, which means that "y" is before or
- // equal to the first float. The largest value is "last + 1", which means
- // that "y" is after the last float. In both cases, the first or last,
- // respectively, float is a candidate. Generally, both floats, before and
- // at the search position, are candidates.
-
- if (i > 0 && get(i - 1)->covers (textblock, y, h))
- result = i - 1;
- else if (i <= last && get(i)->covers (textblock, y, h))
- result = i;
- else
- result = -1;
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
- DBG_OBJ_LEAVE_O (oofm);
- return result;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex
- (int sideSpanningIndex)
-{
- OutOfFlowMgr::Float::CompareSideSpanningIndex comparator;
- Float key (NULL, NULL, NULL, 0);
- key.sideSpanningIndex = sideSpanningIndex;
- return bsearch (&key, false, &comparator) - 1;
-}
-
-void OutOfFlowMgr::SortedFloatsVector::put (Float *vloat)
-{
- lout::container::typed::Vector<Float>::put (vloat);
- vloat->setIndex (type, size() - 1);
-}
-
-OutOfFlowMgr::TBInfo::TBInfo (OutOfFlowMgr *oofm, Textblock *textblock,
- TBInfo *parent, int parentExtIndex) :
- WidgetInfo (oofm, textblock)
-{
- this->parent = parent;
- this->parentExtIndex = parentExtIndex;
-
- leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB);
- rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB);
-
- wasAllocated = getWidget()->wasAllocated ();
- allocation = *(getWidget()->getAllocation ());
- clearPosition = 0;
-}
-
-OutOfFlowMgr::TBInfo::~TBInfo ()
-{
- delete leftFloatsGB;
- delete rightFloatsGB;
-}
-
-void OutOfFlowMgr::TBInfo::updateAllocation ()
-{
- DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
-
- update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
- getNewHeight ());
-
- DBG_OBJ_LEAVE_O (getWidget ());
-}
-
-OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock)
-{
- DBG_OBJ_CREATE ("dw::OutOfFlowMgr");
-
- this->containingBlock = containingBlock;
-
- leftFloatsCB = new SortedFloatsVector (this, LEFT, CB);
- rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB);
-
- DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
- DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
-
- leftFloatsAll = new Vector<Float> (1, true);
- rightFloatsAll = new Vector<Float> (1, true);
-
- DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
- DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
-
- floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
-
- tbInfos = new Vector<TBInfo> (1, false);
- tbInfosByTextblock =
- new HashTable <TypedPointer <Textblock>, TBInfo> (true, true);
-
- leftFloatsMark = rightFloatsMark = 0;
- lastLeftTBIndex = lastRightTBIndex = 0;
-
- containingBlockWasAllocated = containingBlock->wasAllocated ();
- containingBlockAllocation = *(containingBlock->getAllocation());
-
- addWidgetInFlow (containingBlock, NULL, 0);
}
OutOfFlowMgr::~OutOfFlowMgr ()
{
- //printf ("OutOfFlowMgr::~OutOfFlowMgr\n");
-
- delete leftFloatsCB;
- delete rightFloatsCB;
-
- // Order is important: tbInfosByTextblock is owner of the instances
- // of TBInfo.tbInfosByTextblock
- delete tbInfos;
- delete tbInfosByTextblock;
-
- delete floatsByWidget;
-
- // Order is important, since the instances of Float are owned by
- // leftFloatsAll and rightFloatsAll, so these should be deleted
- // last.
- delete leftFloatsAll;
- delete rightFloatsAll;
-
- DBG_OBJ_DELETE ();
-}
-
-void OutOfFlowMgr::sizeAllocateStart (Textblock *caller, Allocation *allocation)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
- "%p, (%d, %d, %d * (%d + %d))",
- caller, allocation->x, allocation->y, allocation->width,
- allocation->ascent, allocation->descent);
-
- getTextblock(caller)->allocation = *allocation;
- getTextblock(caller)->wasAllocated = true;
-
- if (caller == containingBlock) {
- // In the size allocation process, the *first* OOFM method
- // called is sizeAllocateStart, with the containing block as an
- // argument. So this is the correct point to initialize size
- // allocation.
-
- containingBlockAllocation = *allocation;
- containingBlockWasAllocated = true;
-
- // Move floats from GB lists to the one CB list.
- moveFromGBToCB (LEFT);
- moveFromGBToCB (RIGHT);
-
- // These attributes are used to keep track which floats have
- // been allocated (referring to leftFloatsCB and rightFloatsCB).
- lastAllocatedLeftFloat = lastAllocatedRightFloat = -1;
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
-
- // (Later, absolutely positioned blocks have to be allocated.)
-
- if (caller != containingBlock) {
- // Allocate all floats "before" this textblock.
- sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
- sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
- }
-
- // The checks below do not cover "clear position" in all cases, so
- // this is done here separately. This position is stored in TBInfo
- // and calculated at this points; changes will be noticed to the
- // textblock.
- TBInfo *tbInfo = getTextblock (caller);
- int newClearPosition = calcClearPosition (caller);
- if (newClearPosition != tbInfo->clearPosition) {
- tbInfo->clearPosition = newClearPosition;
- caller->clearPositionChanged ();
- }
-
- if (caller == containingBlock) {
- // In the size allocation process, the *last* OOFM method called
- // is sizeAllocateEnd, with the containing block as an
- // argument. So this is the correct point to finish size
- // allocation.
-
- // Allocate all remaining floats.
- sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1);
- sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1);
-
- // Check changes of both textblocks and floats allocation. (All
- // is checked by hasRelationChanged (...).)
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- int minFloatPos;
- Widget *minFloat;
- if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
- tb->borderChanged (minFloatPos, minFloat);
- }
-
- checkAllocatedFloatCollisions (LEFT);
- checkAllocatedFloatCollisions (RIGHT);
-
- // Store some information for later use.
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- tbInfo->updateAllocation ();
- tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
- }
-
- // There are cases where some allocated floats (TODO: later also
- // absolutely positioned elements?) exceed the CB allocation.
- bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT);
-
- // Similar for extremes. (TODO: here also absolutely positioned
- // elements?)
- bool extremesChanged =
- haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT);
-
- for (int i = 0; i < leftFloatsCB->size(); i++)
- leftFloatsCB->get(i)->updateAllocation ();
-
- for (int i = 0; i < rightFloatsCB->size(); i++)
- rightFloatsCB->get(i)->updateAllocation ();
-
- if (sizeChanged || extremesChanged)
- containingBlock->oofSizeChanged (extremesChanged);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::containerSizeChangedForChildren ()
-{
- DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
-
- DBG_OBJ_MSGF ("resize", 0, "%d left floats, %d right floats",
- leftFloatsAll->size (), rightFloatsAll->size ());
-
- for (int i = 0; i < leftFloatsAll->size (); i++)
- leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
- for (int i = 0; i < rightFloatsAll->size (); i++)
- rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
- Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, ...", tbInfo->getWidget ());
-
- int leftMinPos, rightMinPos;
- Widget *leftMinFloat, *rightMinFloat;
- bool c1 =
- hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
- bool c2 =
- hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
- if (c1 || c2) {
- if (!c1) {
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- } else if (!c2) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else {
- if (leftMinPos < rightMinPos) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else{
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- }
- }
- }
-
- if (c1 || c2)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "has changed: minFloatPos = %d, minFloat = %p",
- *minFloatPos, *minFloat);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
- return c1 || c2;
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
- int *minFloatPos, Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, %s, ...",
- tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size(); i++) {
- // TODO binary search?
- Float *vloat = list->get(i);
- int floatPos;
-
- if (tbInfo->getTextblock () == vloat->generatingBlock)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "not checking (generating!) textblock %p against float "
- "%p", tbInfo->getWidget (), vloat->getWidget ());
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock);
-
- int newFlx = calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x,
- getGBWidthForAllocation (vloat));
- int newFly = vloat->generatingBlock->getAllocation()->y
- - containingBlockAllocation.y + vloat->yReal;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "checking textblock %p against float %p",
- tbInfo->getWidget (), vloat->getWidget ());
- DBG_OBJ_MSG_START ();
-
- if (hasRelationChanged (tbInfo->wasThenAllocated (),
- tbInfo->getOldXCB (), tbInfo->getOldYCB (),
- tbInfo->getNewWidth (),
- tbInfo->getNewHeight (),
- tbInfo->getNewXCB (), tbInfo->getNewYCB (),
- tbInfo->getNewWidth (),
- tbInfo->getNewHeight (),
- vloat->wasThenAllocated (),
- // When not allocated before, these values
- // are undefined, but this does not matter,
- // since they are neither used.
- vloat->getOldXCB (), vloat->getOldYCB (),
- vloat->getOldWidth (), vloat->getOldHeight (),
- newFlx, newFly, vloat->size.width,
- vloat->size.ascent + vloat->size.descent,
- side, &floatPos)) {
- if (!changed || floatPos < *minFloatPos) {
- *minFloatPos = floatPos;
- *minFloat = vloat->getWidget ();
- }
- changed = true;
- } else
- DBG_OBJ_MSG ("resize.oofm", 0, "No.");
-
- DBG_OBJ_MSG_END ();
- }
-
- // All floarts are searched, to find the minimum. TODO: Are
- // floats sorted, so this can be shortened? (The first is the
- // minimum?)
- }
-
- if (changed)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "has changed: minFloatPos = %d, minFloat = %p",
- *minFloatPos, *minFloat);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
- return changed;
-}
-
-/**
- * \brief ...
- *
- * All coordinates are given relative to the CB. *floatPos is relative
- * to the TB, and may be negative.
- */
-bool OutOfFlowMgr::hasRelationChanged (bool oldTBAlloc,
- int oldTBx, int oldTBy, int oldTBw,
- int oldTBh, int newTBx, int newTBy,
- int newTBw, int newTBh,
- bool oldFlAlloc,
- int oldFlx, int oldFly, int oldFlw,
- int oldFlh, int newFlx, int newFly,
- int newFlw, int newFlh,
- Side side, int *floatPos)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT");
-
- if (oldTBAlloc)
- DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d",
- oldTBx, oldTBy, oldTBw, oldTBh);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined");
- DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d",
- newTBx, newTBy, newTBw, newTBh);
-
- if (oldFlAlloc)
- DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d",
- oldFlx, oldFly, oldFlw, oldFlh);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined");
- DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d",
- newFlx, newFly, newFlw, newFlh);
-
- bool result;
- if (oldTBAlloc && oldFlAlloc) {
- bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh;
- bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.",
- oldCov ? "yes" : "no", newCov ? "yes" : "no");
- DBG_OBJ_MSG_START ();
-
- if (oldCov && newCov) {
- int yOld = oldFly - oldTBy, yNew = newFly - newTBy;
- if (yOld == yNew) {
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "old (%d - %d) and new (%d - %d) position equal: %d",
- oldFly, oldTBy, newFly, newTBy, yOld);
-
- // Float position has not changed, but perhaps the amout
- // how far the float reaches into the TB. (TODO:
- // Generally, not only here, it could be tested whether
- // the float reaches into the TB at all.)
- int wOld, wNew;
- if (side == LEFT) {
- wOld = oldFlx + oldFlw - oldTBx;
- wNew = newFlx + newFlw - newTBx;
- } else {
- wOld = oldTBx + oldTBw - oldFlx;
- wNew = newTBx + newTBw - newFlx;
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n",
- wOld, wNew);
-
- if (wOld == wNew) {
- if (oldFlh == newFlh)
- result = false;
- else {
- // Only heights of floats changed. Relevant only
- // from bottoms of float.
- *floatPos = min (yOld + oldFlh, yNew + newFlh);
- result = true;
- }
- } else {
- *floatPos = yOld;
- result = true;
- }
- } else {
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "old (%d - %d = %d) and new (%d - %d = %d) position "
- "different",
- oldFly, oldTBy, yOld, newFly, newTBy, yNew);
- *floatPos = min (yOld, yNew);
- result = true;
- }
- } else if (oldCov) {
- *floatPos = oldFly - oldTBy;
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "returning old position: %d - %d = %d", oldFly, oldTBy,
- *floatPos);
- } else if (newCov) {
- *floatPos = newFly - newTBy;
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "returning new position: %d - %d = %d", newFly, newTBy,
- *floatPos);
- } else
- result = false;
-
- DBG_OBJ_MSG_END ();
- } else {
- // Not allocated before: ignore all old values, only check whether
- // TB is covered by Float.
- if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) {
- *floatPos = newFly - newTBy;
- result = true;
- } else
- result = false;
- }
-
- if (result)
- DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d",
- *floatPos);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
-
- return result;
-}
-
-void OutOfFlowMgr::checkAllocatedFloatCollisions (Side side)
-{
- // In some cases, the collision detection in tellPosition() is
- // based on the wrong allocations. Here (just after all Floats have
- // been allocated), we correct this.
-
- // TODO In some cases this approach is rather slow, causing a too
- // long queueResize() cascade.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB;
-
- // While iterating through the list of floats to be checked, we
- // iterate equally through the list of the opposite floats, using
- // this index:
- int oppIndex = 0;
-
- for (int index = 0; index < list->size (); index++) {
- Float *vloat = list->get(index);
- bool needsChange = false;
- int yRealNew = INT_MAX;
-
- // Same side.
- if (index >= 1) {
- Float *other = list->get(index - 1);
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "same side: checking %p (#%d, GB: %p) against "
- "%p (#%d, GB: %p)",
- vloat->getWidget (), index, vloat->generatingBlock,
- other->getWidget (), index - 1, other->generatingBlock);
-
- if (vloat->generatingBlock != other->generatingBlock) {
- int yRealNewSame;
- if (collidesV (vloat, other, CB, &yRealNewSame, true)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides, new yReal = %d (old: %d)",
- yRealNewSame, vloat->yReal);
- if (vloat->yReal != yRealNewSame) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewSame);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
- }
- }
-
- if (oppList->size () > 0) {
- // Other side. Iterate to next float on the other side,
- // before this float.
- while (oppIndex + 1 < oppList->size () &&
- oppList->get(oppIndex + 1)->sideSpanningIndex
- < vloat->sideSpanningIndex)
- oppIndex++;
-
- if (oppList->get(oppIndex)->sideSpanningIndex
- < vloat->sideSpanningIndex) {
- int oppIndexTmp = oppIndex, yRealNewOpp;
-
- // Aproach is similar to tellPosition(); see comments
- // there. Again, loop as long as the vertical dimensions test
- // is positive (and, of course, there are floats), ...
- for (bool foundColl = false;
- !foundColl && oppIndexTmp >= 0 &&
- collidesV (vloat, oppList->get (oppIndexTmp), CB,
- &yRealNewOpp, true);
- oppIndexTmp--) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "opposite side (after collision (v) test): "
- "checking %p (#%d/%d, GB: %p) against "
- "%p (#%d/%d, GB: %p)",
- vloat->getWidget (), index,
- vloat->sideSpanningIndex,
- vloat->generatingBlock,
- oppList->get(oppIndexTmp)->getWidget (),
- oppList->get(oppIndexTmp)->getIndex (CB),
- oppList->get(oppIndexTmp)->sideSpanningIndex,
- oppList->get(oppIndexTmp)->generatingBlock);
-
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides (h), new yReal = %d (old: %d)",
- yRealNewOpp, vloat->yReal);
- foundColl = true;
- if (vloat->yReal != yRealNewOpp) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewOpp);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
- }
- }
- }
-
- if (needsChange)
- vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
- vloat->getWidget ());
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::doFloatsExceedCB (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This method is called to determine whether the *requisition* of
- // the CB must be recalculated. So, we check the float allocations
- // against the *requisition* of the CB, which may (e. g. within
- // tables) differ from the new allocation. (Generally, a widget may
- // allocated at a different size.)
- core::Requisition cbReq;
- containingBlock->sizeRequest (&cbReq);
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool exceeds = false;
-
- DBG_OBJ_MSG_START ();
-
- for (int i = 0; i < list->size () && !exceeds; i++) {
- Float *vloat = list->get (i);
- if (vloat->getWidget()->wasAllocated ()) {
- Allocation *fla = vloat->getWidget()->getAllocation ();
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "Does FlA = (%d, %d, %d * %d) exceed CBA = "
- "(%d, %d, %d * %d)?",
- fla->x, fla->y, fla->width, fla->ascent + fla->descent,
- containingBlockAllocation.x, containingBlockAllocation.y,
- cbReq.width, cbReq.ascent + cbReq.descent);
- if (fla->x + fla->width > containingBlockAllocation.x + cbReq.width ||
- fla->y + fla->ascent + fla->descent
- > containingBlockAllocation.y + cbReq.ascent + cbReq.descent) {
- exceeds = true;
- DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
- } else
- DBG_OBJ_MSG ("resize.oofm", 2, "No.");
- }
- }
-
- DBG_OBJ_MSG_END ();
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return exceeds;
-}
-
-bool OutOfFlowMgr::haveExtremesChanged (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This is quite different from doFloatsExceedCB, since there is no
- // counterpart to getExtremes, as sizeAllocate is a counterpart to
- // sizeRequest. So we have to determine whether the allocation has
- // changed the extremes, which is done by examining the part of the
- // allocation which is part of the extremes calculation (see
- // getFloatsExtremes). Changes of the extremes are handled by the
- // normal queueResize mechanism.
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size () && !changed; i++) {
- Float *vloat = list->get (i);
- // When the GB is the CB, an allocation change does not play a
- // role here.
- if (vloat->generatingBlock != containingBlock) {
- if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
- changed = true;
- else {
- // This method is called within sizeAllocateEnd, where
- // containinBlock->getAllocation() (old value) and
- // containinBlockAllocation (new value) are different.
-
- Allocation *oldCBA = containingBlock->getAllocation ();
- Allocation *newCBA = &containingBlockAllocation;
-
- // Compare also to getFloatsExtremes. The box difference
- // of the GB (from style) has not changed in this context,
- // so it is ignored.
-
- int oldDiffLeft = vloat->getOldXCB ();
- int newDiffLeft = vloat->getNewXCB ();
- int oldDiffRight =
- oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
- int newDiffRight =
- newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
-
- if (// regarding minimum
- (side == LEFT && oldDiffLeft != newDiffLeft) ||
- (side == RIGHT && oldDiffRight != newDiffRight) ||
- // regarding maximum
- oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
- changed = true;
- }
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return changed;
-}
-
-void OutOfFlowMgr::moveFromGBToCB (Side side)
-{
- DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
-
- for (int mark = 0; mark <= *floatsMark; mark++)
- for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
- it.hasNext (); ) {
- TBInfo *tbInfo = it.getNext ();
- SortedFloatsVector *src =
- side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
- for (int i = 0; i < src->size (); i++) {
- Float *vloat = src->get (i);
- // "vloat->indexCBList == -1": prevent copying the vloat twice.
- if (vloat->indexCBList == -1 && vloat->mark == mark) {
- dest->put (vloat);
- DBG_OBJ_MSGF ("oofm.resize", 1,
- "moving float %p (mark %d) to CB list\n",
- vloat->getWidget (), vloat->mark);
- DBG_OBJ_SET_NUM (side == LEFT ?
- "leftFloatsCB.size" : "rightFloatsCB.size",
- dest->size());
- DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
- "leftFloatsCB" : "rightFloatsCB",
- dest->size() - 1, "widget",
- vloat->getWidget ());
-
- }
- }
- }
-
- *floatsMark = 0;
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
-{
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *lastAllocatedFloat =
- side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
- "%s, [%d ->] %d [size = %d]",
- side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
- newLastAllocatedFloat, list->size ());
-
- Allocation *cba = &containingBlockAllocation;
-
- for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
- Float *vloat = list->get(i);
- ensureFloatSize (vloat);
-
- Allocation *gba = getAllocation (vloat->generatingBlock);
-
- Allocation childAllocation;
- childAllocation.x = cba->x + calcFloatX (vloat, side, gba->x - cba->x,
- getGBWidthForAllocation (vloat));
- childAllocation.y = gba->y + vloat->yReal;
- childAllocation.width = vloat->size.width;
- childAllocation.ascent = vloat->size.ascent;
- childAllocation.descent = vloat->size.descent;
-
- vloat->getWidget()->sizeAllocate (&childAllocation);
- }
-
- *lastAllocatedFloat = newLastAllocatedFloat;
-
- DBG_OBJ_LEAVE ();
-}
-
-// Used as argument "gbWidth" for calcFloatX(), in the context of allocation.
-int OutOfFlowMgr::getGBWidthForAllocation (Float *vloat)
-{
- // See comments in getFloatsSize() for a detailed rationale ...
- if (containingBlock->mustBeWidenedToAvailWidth ())
- return vloat->generatingBlock->getLineBreakWidth ();
- else
- // ... but notice this difference: not GB width + float width is
- // used, but only GB width, since the float width has already
- // been included in getFloatsSize().
- return min (getAllocation(vloat->generatingBlock)->width,
- vloat->generatingBlock->getLineBreakWidth ());
-}
-
-/**
- * \brief ...
- *
- * gbX is given relative to the CB, as is the return value.
- */
-int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth)
-{
- DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d",
- vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
- gbWidth);
- int x;
-
- switch (side) {
- case LEFT:
- // Left floats are always aligned on the left side of the
- // generator (content, not allocation) ...
- x = gbX + vloat->generatingBlock->getStyle()->boxOffsetX();
- DBG_OBJ_MSGF ("resize.common", 1, "left: x = %d + %d = %d",
- gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x);
- // ... but when the float exceeds the line break width of the
- // container, it is corrected (but not left of the container).
- // This way, we save space and, especially within tables, avoid
- // some problems.
- if (wasAllocated (containingBlock) &&
- x + vloat->size.width > containingBlock->getLineBreakWidth ()) {
- x = max (0, containingBlock->getLineBreakWidth () - vloat->size.width);
- DBG_OBJ_MSGF ("resize.common", 1,
- "corrected to: max (0, %d - %d) = %d",
- containingBlock->getLineBreakWidth (), vloat->size.width,
- x);
- }
- break;
-
- case RIGHT:
- // Similar for right floats, but in this case, floats are
- // shifted to the right when they are too big (instead of
- // shifting the generator to the right).
-
- x = max (gbX + gbWidth - vloat->size.width
- - vloat->generatingBlock->getStyle()->boxRestWidth(),
- // Do not exceed CB allocation:
- 0);
- DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d",
- gbX, gbWidth, vloat->size.width,
- vloat->generatingBlock->getStyle()->boxRestWidth(), x);
- break;
-
- default:
- assertNotReached ();
- x = 0;
- break;
- }
-
- DBG_OBJ_LEAVE ();
- return x;
-}
-
-void OutOfFlowMgr::draw (View *view, Rectangle *area)
-{
- drawFloats (leftFloatsCB, view, area);
- drawFloats (rightFloatsCB, view, area);
-}
-
-void OutOfFlowMgr::drawFloats (SortedFloatsVector *list, View *view,
- Rectangle *area)
-{
- // This could be improved, since the list is sorted: search the
- // first float fitting into the area, and iterate until one is
- // found below the area.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- Rectangle childArea;
- if (vloat->getWidget()->intersects (area, &childArea))
- vloat->getWidget()->draw (view, &childArea);
- }
-}
-
-void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock,
- Textblock *parentBlock, int externalIndex)
-{
- //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
- // containingBlock, textblock, parentBlock, externalIndex);
-
- TBInfo *tbInfo =
- new TBInfo (this, textblock,
- parentBlock ? getTextblock (parentBlock) : NULL,
- externalIndex);
- tbInfo->index = tbInfos->size();
-
- tbInfos->put (tbInfo);
- tbInfosByTextblock->put (new TypedPointer<Textblock> (textblock), tbInfo);
-}
-
-void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
- int externalIndex)
-{
- DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
- widget, generatingBlock, externalIndex);
-
- if (isWidgetFloat (widget)) {
- TBInfo *tbInfo = getTextblock (generatingBlock);
-
- Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
-
- // Note: Putting the float first in the GB list, and then,
- // possibly into the CB list (in that order) will trigger
- // setting Float::inCBList to the right value.
-
- switch (widget->getStyle()->vloat) {
- case FLOAT_LEFT:
- leftFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefLeftFloat (leftFloatsAll->size() - 1);
- DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
- tbInfo->leftFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- leftFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastLeftTBIndex)
- leftFloatsMark++;
-
- vloat->mark = leftFloatsMark;
- //printf ("[%p] adding left float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastLeftTBIndex);
-
- lastLeftTBIndex = tbInfo->index;
- }
- break;
-
- case FLOAT_RIGHT:
- rightFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefRightFloat (rightFloatsAll->size() - 1);
- DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
- tbInfo->rightFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- rightFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastRightTBIndex)
- rightFloatsMark++;
-
- vloat->mark = rightFloatsMark;
- //printf ("[%p] adding right float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastRightTBIndex);
-
- lastRightTBIndex = tbInfo->index;
- }
-
- break;
-
- default:
- assertNotReached();
- }
-
- // "sideSpanningIndex" is only compared, so this simple
- // assignment is sufficient; differenciation between GB and CB
- // lists is not neccessary. TODO: Can this also be applied to
- // "index", to simplify the current code? Check: where is
- // "index" used.
- vloat->sideSpanningIndex =
- leftFloatsAll->size() + rightFloatsAll->size() - 1;
-
- floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
- } else
- // May be extended.
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::moveExternalIndices (Textblock *generatingBlock,
- int oldStartIndex, int diff)
-{
- TBInfo *tbInfo = getTextblock (generatingBlock);
- moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff);
- moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff);
-}
-
-void OutOfFlowMgr::moveExternalIndices (SortedFloatsVector *list,
- int oldStartIndex, int diff)
-{
- // Could be faster with binary search, but the GB (not CB!) lists
- // should be rather small.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- if (vloat->externalIndex >= oldStartIndex) {
- vloat->externalIndex += diff;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
- vloat->externalIndex);
- }
- }
-}
-
-OutOfFlowMgr::Float *OutOfFlowMgr::findFloatByWidget (Widget *widget)
-{
- TypedPointer <Widget> key (widget);
- Float *vloat = floatsByWidget->get (&key);
- assert (vloat != NULL);
- return vloat;
-}
-
-void OutOfFlowMgr::markSizeChange (int ref)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
-
- if (isRefFloat (ref)) {
- Float *vloat;
-
- if (isRefLeftFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = leftFloatsAll->get (i);
- //printf (" => left float %d\n", i);
- } else if (isRefRightFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = rightFloatsAll->get (i);
- //printf (" => right float %d\n", i);
- } else {
- assertNotReached();
- vloat = NULL; // compiler happiness
- }
-
- vloat->dirty = vloat->sizeChangedSinceLastAllocation = true;
-
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (),
- "<Float>.sizeChangedSinceLastAllocation",
- vloat->sizeChangedSinceLastAllocation);
-
- // The generating block is told directly about this. (Others later, in
- // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which
- // differentiates many special cases), but the size is not known yet,
- vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ());
- } else
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-
-void OutOfFlowMgr::markExtremesChange (int ref)
-{
- // Nothing to do here.
-}
-
-Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level)
-{
- Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level);
- if (childAtPoint == NULL)
- childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level);
- return childAtPoint;
-}
-
-Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list,
- int x, int y, int level)
-{
- for (int i = 0; i < list->size(); i++) {
- // Could use binary search to be faster.
- Float *vloat = list->get(i);
- if (vloat->getWidget()->wasAllocated ()) {
- Widget *childAtPoint =
- vloat->getWidget()->getWidgetAtPoint (x, y, level + 1);
- if (childAtPoint)
- return childAtPoint;
- }
- }
-
- return NULL;
-}
-
-void OutOfFlowMgr::tellPosition (Widget *widget, int yReq)
-{
- if (isWidgetFloat (widget))
- tellFloatPosition (widget, yReq);
-
- // Nothing to do for absolutely positioned blocks.
-}
-
-
-void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "tellFloatPosition", "%p, %d",
- widget, yReq);
-
- assert (yReq >= 0);
-
- Float *vloat = findFloatByWidget(widget);
-
- SortedFloatsVector *listSame, *listOpp;
- Side side;
- getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
- ensureFloatSize (vloat);
-
- // "yReal" may change due to collisions (see below).
- vloat->yReq = vloat->yReal = yReq;
-
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
-
- // Test collisions (on this side). Although there are (rare) cases
- // where it could make sense, the horizontal dimensions are not
- // tested; especially since searching and border calculation would
- // be confused. For this reaspn, only the previous float is
- // relevant. (Cf. below, collisions on the other side.)
- int index = vloat->getIndex (listSame->type), yRealNew;
- if (index >= 1 &&
- collidesV (vloat, listSame->get (index - 1), listSame->type,
- &yRealNew, false)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- }
-
- // Test collisions (on the opposite side). There are cases when
- // more than one float has to be tested. Consider the following
- // HTML snippet ("id" attribute only used for simple reference
- // below, as #f1, #f2, and #f3):
- //
- // <div style="float:left" id="f1">
- // Left left left left left left left left left left.
- // </div>
- // <div style="float:left" id="f2">Also left.</div>
- // <div style="float:right" id="f3">Right.</div>
- //
- // When displayed with a suitable window width (only slightly wider
- // than the text within #f1), this should look like this:
- //
- // ---------------------------------------------------------
- // | Left left left left left left left left left left. |
- // | Also left. Right. |
- // ---------------------------------------------------------
- //
- // Consider float #f3: a collision test with #f2, considering
- // vertical dimensions, is positive, but not the test with
- // horizontal dimensions (because #f2 and #f3 are too
- // narrow). However, a collision has to be tested with #f1;
- // otherwise #f3 and #f1 would overlap.
-
- int oppFloatIndex =
- listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
- // Generally, the rules are simple: loop as long as the vertical
- // dimensions test is positive (and, of course, there are floats),
- // ...
- for (bool foundColl = false;
- !foundColl && oppFloatIndex >= 0 &&
- collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
- &yRealNew, false);
- oppFloatIndex--) {
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- foundColl = true;
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
- vloat->yReq, vloat->yReal);
-
- DBG_OBJ_LEAVE ();
}
-bool OutOfFlowMgr::collidesV (Float *vloat, Float *other, SFVType type,
- int *yReal, bool useAllocation)
-{
- // Only checks vertical (possible) collisions, and only refers to
- // vloat->yReal; never to vloat->allocation->y, even when the GBs are
- // different. Used only in tellPosition.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
- vloat->getIndex (type), vloat->getWidget (),
- other->getIndex (type), other->getWidget ());
-
- bool result;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
-
- if (vloat->generatingBlock == other->generatingBlock) {
- ensureFloatSize (other);
- int otherBottomGB =
- other->yReal + other->size.ascent + other->size.descent;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "same generators: otherBottomGB = %d + (%d + %d) = %d",
- other->yReal, other->size.ascent, other->size.descent,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- } else {
- // If the other float is not allocated, there is no collision. The
- // allocation of this float (vloat) is not used at all.
- if (!other->getWidget()->wasAllocated ())
- result = false;
- else {
- assert (wasAllocated (vloat->generatingBlock));
- Allocation *gba = getAllocation (vloat->generatingBlock),
- *flaOther = other->getWidget()->getAllocation ();
-
- // We distinguish two cases (by different values of useAllocation):
- // (i) within tellPosition, GB allocation + yReal is used for the
- // y position of the other float, while (ii) in checkAllocatedFloat-
- // Collisions, the float allocation is used. The latter is necessary
- // by the definition of this method, the former increases performance,
- // as compared to using the float allocation, in some cases, as in
- // this:
- //
- // When '<div><div style="float:left">[Some text]</div></div>' is
- // repeated n times, the resize idle function (Layout::resizeIdle)
- // would be repeated roughly n times, when also in case (i) the float
- // allocation is used, since for the collision test of float n with
- // float n - 1, the allocation of float n - 1 does not yet reflect the
- // collision test between n - 1 and n - 2, but yReal does for n - 1.
- //
- // On the other hand, the GB allocations will most likely more stable
- // than the float allocations.
- //
- // Cases where this is incorrect will hopefully be rare, and, in any
- // case, corrected in sizeAllocateEnd, either because hasRelation-
- // Changed returns true, or in checkAllocatedFloatCollisions.
-
- int otherFloatY = useAllocation ? flaOther->y :
- getAllocation(other->generatingBlock)->y + other->yReal;
- int otherBottomGB =
- otherFloatY + flaOther->ascent + flaOther->descent - gba->y;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "different generators: "
- "otherBottomGB = %d + (%d + %d) - %d = %d",
- otherFloatY, flaOther->ascent, flaOther->descent, gba->y,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- }
- }
-
- if (result)
- DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
-
- DBG_OBJ_LEAVE ();
- return result;
-}
-
-
-bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type)
-{
- // Only checks horizontal collision. For a complete test, use
- // collidesV (...) && collidesH (...).
- bool collidesH;
-
- if (vloat->generatingBlock == other->generatingBlock)
- collidesH = vloat->size.width + other->size.width
- + vloat->generatingBlock->getStyle()->boxDiffWidth()
- > vloat->generatingBlock->getLineBreakWidth();
- else {
- // Again, if the other float is not allocated, there is no
- // collision. Compare to collidesV. (But vloat->size is used
- // here.)
- if (!other->getWidget()->wasAllocated ())
- collidesH = false;
- else {
- assert (wasAllocated (vloat->generatingBlock));
- Allocation *gba = getAllocation (vloat->generatingBlock);
- int vloatX =
- calcFloatX (vloat,
- vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
- LEFT : RIGHT,
- gba->x, getGBWidthForAllocation (vloat));
-
- // Generally: right border of the left float > left border of
- // the right float (all in canvas coordinates).
- if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
- // "vloat" is left, "other" is right
- collidesH = vloatX + vloat->size.width
- > other->getWidget()->getAllocation()->x;
- else
- // "other" is left, "vloat" is right
- collidesH = other->getWidget()->getAllocation()->x
- + other->getWidget()->getAllocation()->width
- > vloatX;
- }
- }
-
- return collidesH;
-}
-
-void OutOfFlowMgr::getFloatsListsAndSide (Float *vloat,
- SortedFloatsVector **listSame,
- SortedFloatsVector **listOpp,
- Side *side)
-{
- TBInfo *tbInfo = getTextblock (vloat->generatingBlock);
-
- switch (vloat->getWidget()->getStyle()->vloat) {
- case FLOAT_LEFT:
- if (wasAllocated (vloat->generatingBlock)) {
- if (listSame) *listSame = leftFloatsCB;
- if (listOpp) *listOpp = rightFloatsCB;
- } else {
- if (listSame) *listSame = tbInfo->leftFloatsGB;
- if (listOpp) *listOpp = tbInfo->rightFloatsGB;
- }
- if (side) *side = LEFT;
- break;
-
- case FLOAT_RIGHT:
- if (wasAllocated (vloat->generatingBlock)) {
- if (listSame) *listSame = rightFloatsCB;
- if (listOpp) *listOpp = leftFloatsCB;
- } else {
- if (listSame) *listSame = tbInfo->rightFloatsGB;
- if (listOpp) *listOpp = tbInfo->leftFloatsGB;
- }
- if (side) *side = RIGHT;
- break;
-
- default:
- assertNotReached();
- }
-}
-
-void OutOfFlowMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight)
-{
- DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
-
- int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
- getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
- getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
-
- *oofWidth = max (oofWidthtLeft, oofWidthRight);
- *oofHeight = max (oofHeightLeft, oofHeightRight);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)",
- oofWidthtLeft, oofWidthRight, *oofWidth,
- oofHeightLeft, oofHeightRight, *oofHeight);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
- int *height)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
- cbReq->width, cbReq->ascent, cbReq->descent,
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
-
- *width = *height = 0;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "float %p has generator %p (container is %p)",
- vloat->getWidget (), vloat->generatingBlock,
- containingBlock);
-
- if (vloat->generatingBlock == containingBlock ||
- wasAllocated (vloat->generatingBlock)) {
- ensureFloatSize (vloat);
- int x, y;
-
- int effWidth;
- if (containingBlock->mustBeWidenedToAvailWidth ())
- // For most textblocks, the line break width is used for
- // calculating the x position. (This changed for GROWS,
- // where the width of a textblock is often smaller that
- // the line break.)
- effWidth = vloat->generatingBlock->getLineBreakWidth ();
- else
- // For some textblocks, like inline blocks, the line break
- // width would be too large for right floats in some
- // cases.
- //
- // (i) Consider a small inline block with only a few words
- // in one line, narrower that line break width minus
- // float width. In this case, the sum should be used.
- //
- // (ii) If there is more than one line, the line break
- // will already be exceeded, and so be smaller that
- // GB width + float width.
- effWidth = min (cbReq->width + vloat->size.width,
- vloat->generatingBlock->getLineBreakWidth ());
-
- if (vloat->generatingBlock == containingBlock) {
- x = calcFloatX (vloat, side, 0, effWidth);
- y = vloat->yReal;
- } else {
- Allocation *gba = getAllocation(vloat->generatingBlock);
- x = calcFloatX (vloat, side, gba->x - containingBlockAllocation.x,
- effWidth);
- y = gba->y - containingBlockAllocation.y + vloat->yReal;
- }
-
- *width = max (*width, x + vloat->size.width);
- *height = max (*height, y + vloat->size.ascent + vloat->size.descent);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: (%d + %d) * "
- "(%d + (%d + %d)) => %d * %d",
- vloat->getWidget (), vloat->generatingBlock,
- x, vloat->size.width,
- y, vloat->size.ascent, vloat->size.descent,
- *width, *height);
- } else
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: not allocated",
- vloat->getWidget (), vloat->generatingBlock);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
- int *oofMaxWidth)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
- cbExtr->minWidth, cbExtr->maxWidth);
-
- int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
- getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
- getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
-
- *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
- *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
- oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
- oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
- int *minWidth, int *maxWidth)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
- cbExtr->minWidth, cbExtr->maxWidth,
- side == LEFT ? "LEFT" : "RIGHT");
-
- *minWidth = *maxWidth = 0;
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "float %p has generator %p (container is %p)",
- vloat->getWidget (), vloat->generatingBlock,
- containingBlock);
-
- if (vloat->generatingBlock == containingBlock ||
- wasAllocated (vloat->generatingBlock)) {
- Extremes extr;
- vloat->getWidget()->getExtremes (&extr);
-
- // The calculation of extremes must be kept consistent with
- // getFloatsSize(). Especially this means for the *minimal* width:
- //
- // - The right border (difference between float and
- // container) does not have to be considered (see
- // getFloatsSize().
- //
- // - This is also the case for the left border, as seen in
- // calcFloatX() ("... but when the float exceeds the line
- // break width" ...).
-
- *minWidth = max (*minWidth, extr.minWidth);
-
- // For the maximal width, borders must be considered.
-
- if (vloat->generatingBlock == containingBlock)
- *maxWidth =
- max (*maxWidth,
- extr.maxWidth
- + vloat->generatingBlock->getStyle()->boxDiffWidth());
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock);
- *maxWidth =
- max (*maxWidth,
- extr.maxWidth
- + vloat->generatingBlock->getStyle()->boxDiffWidth()
- + max (containingBlockAllocation.width - gba->width, 0));
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d / %d => %d / %d",
- extr.minWidth, extr.maxWidth, *minWidth, *maxWidth);
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "not allocated");
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-OutOfFlowMgr::TBInfo *OutOfFlowMgr::getTextblock (Textblock *textblock)
-{
- TypedPointer<Textblock> key (textblock);
- TBInfo *tbInfo = tbInfosByTextblock->get (&key);
- assert (tbInfo);
- return tbInfo;
-}
-
-/**
- * Get the left border for the vertical position of *y*, for a height
- * of *h", based on floats; relative to the allocation of the calling
- * textblock.
- *
- * The border includes marging/border/padding of the calling textblock
- * but is 0 if there is no float, so a caller should also consider
- * other borders.
- */
-int OutOfFlowMgr::getLeftBorder (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d",
- textblock, y, h, lastGB, lastExtIndex, b);
- return b;
-}
-
-/**
- * Get the right border for the vertical position of *y*, for a height
- * of *h*, based on floats.
- *
- * See also getLeftBorder(int, int);
- */
-int OutOfFlowMgr::getRightBorder (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d",
- textblock, y, h, lastGB, lastExtIndex, b);
- return b;
-}
-
-int OutOfFlowMgr::getBorder (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int last;
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last);
-
- DBG_OBJ_MSGF ("border", 1, "first = %d", first);
-
- if (first == -1) {
- // No float.
- DBG_OBJ_LEAVE ();
- return 0;
- } else {
- // It is not sufficient to find the first float, since a line
- // (with height h) may cover the region of multiple float, of
- // which the widest has to be choosen.
- int border = 0;
- bool covers = true;
-
- // We are not searching until the end of the list, but until the
- // float defined by lastGB and lastExtIndex.
- for (int i = first; covers && i <= last; i++) {
- Float *vloat = list->get(i);
- covers = vloat->covers (textblock, y, h);
- DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
- i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
-
- if (covers) {
- int thisBorder;
- if (vloat->generatingBlock == textblock) {
- int borderIn = side == LEFT ?
- vloat->generatingBlock->getStyle()->boxOffsetX() :
- vloat->generatingBlock->getStyle()->boxRestWidth();
- thisBorder = vloat->size.width + borderIn;
- DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d",
- vloat->size.width, borderIn, thisBorder);
- } else {
- assert (wasAllocated (vloat->generatingBlock));
- assert (vloat->getWidget()->wasAllocated ());
-
- Allocation *tba = getAllocation(textblock),
- *fla = vloat->getWidget()->getAllocation ();
- if (side == LEFT) {
- thisBorder = fla->x + fla->width - tba->x;
- DBG_OBJ_MSGF ("border", 1,
- "not GB: thisBorder = %d + %d - %d = %d",
- fla->x, fla->width, tba->x, thisBorder);
- } else {
- // See also calcFloatX.
- thisBorder =
- tba->x + textblock->getLineBreakWidth () - fla->x;
- DBG_OBJ_MSGF ("border", 1,
- "not GB: thisBorder = %d + %d - %d "
- "= %d",
- tba->x, textblock->getLineBreakWidth (), fla->x,
- thisBorder);
- }
- }
-
- border = max (border, thisBorder);
- DBG_OBJ_MSGF ("border", 1, "=> border = %d", border);
- }
- }
-
- DBG_OBJ_LEAVE ();
- return border;
- }
-}
-
-
-OutOfFlowMgr::SortedFloatsVector *OutOfFlowMgr::getFloatsListForTextblock
- (Textblock *textblock, Side side)
-{
- DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForTextblock", "%p, %s",
- textblock, side == LEFT ? "LEFT" : "RIGHT");
-
- OutOfFlowMgr::SortedFloatsVector *list;
-
- if (wasAllocated (textblock)) {
- DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list");
- list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- } else {
- DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list");
- TBInfo *tbInfo = getTextblock (textblock);
- list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
- }
-
- DBG_OBJ_LEAVE ();
- return list;
-}
-
-
-bool OutOfFlowMgr::hasFloatLeft (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s",
- textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
- return b;
-}
-
-bool OutOfFlowMgr::hasFloatRight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s",
- textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
- return b;
-}
-
-bool OutOfFlowMgr::hasFloat (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
-
- DBG_OBJ_MSGF ("border", 1, "first = %d", first);
- DBG_OBJ_LEAVE ();
- return first != -1;
-}
-
-int OutOfFlowMgr::getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex);
-}
-
-int OutOfFlowMgr::getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex);
-}
-
-// Calculate height from the position *y*.
-int OutOfFlowMgr::getFloatHeight (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
- assert (first != -1); /* This method must not be called when there is no
- float on the respective side. */
-
- Float *vloat = list->get(first);
- int yRelToFloat;
-
- if (vloat->generatingBlock == textblock) {
- yRelToFloat = y - vloat->yReal;
- DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
- y, vloat->yReal, yRelToFloat);
- } else {
- // The respective widgets are allocated; otherwise, hasFloat() would have
- // returned false.
- assert (wasAllocated (textblock));
- assert (vloat->getWidget()->wasAllocated ());
-
- Allocation *tba = getAllocation(textblock),
- *fla = vloat->getWidget()->getAllocation ();
- yRelToFloat = tba->y + y - fla->y;
-
- DBG_OBJ_MSGF ("border", 1,
- "caller is not CB: yRelToFloat = %d + %d - %d = %d",
- tba->y, y, fla->y, yRelToFloat);
- }
-
- ensureFloatSize (vloat);
- int height = vloat->size.ascent + vloat->size.descent - yRelToFloat;
-
- DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d",
- vloat->size.ascent, vloat->size.descent, yRelToFloat, height);
- DBG_OBJ_LEAVE ();
- return height;
-}
-
-/**
- * Returns position relative to the textblock "tb".
- */
-int OutOfFlowMgr::getClearPosition (Textblock *tb)
-{
- return getTextblock(tb)->clearPosition;
-}
-
-int OutOfFlowMgr::calcClearPosition (Textblock *tb)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", tb);
-
- int pos;
-
- if (tb->getStyle()) {
- bool left = false, right = false;
- switch (tb->getStyle()->clear) {
- case CLEAR_NONE: break;
- case CLEAR_LEFT: left = true; break;
- case CLEAR_RIGHT: right = true; break;
- case CLEAR_BOTH: left = right = true; break;
- default: assertNotReached ();
- }
-
- pos = max (left ? calcClearPosition (tb, LEFT) : 0,
- right ? calcClearPosition (tb, RIGHT) : 0);
- } else
- pos = 0;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
- DBG_OBJ_LEAVE ();
-
- return pos;
-}
-
-int OutOfFlowMgr::calcClearPosition (Textblock *tb, Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s",
- tb, side == LEFT ? "LEFT" : "RIGHT");
-
- int pos;
-
- if (!wasAllocated (tb))
- // There is no relation yet to floats generated by other
- // textblocks, and this textblocks floats are unimportant for
- // the "clear" property.
- pos = 0;
- else {
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
-
- // Search the last float before (therfore -1) this textblock.
- int i = list->findFloatIndex (tb, -1);
- if (i < 0) {
- pos = 0;
- DBG_OBJ_MSG ("resize.oofm", 1, "no float");
- } else {
- Float *vloat = list->get(i);
- assert (vloat->generatingBlock != tb);
- if (!wasAllocated (vloat->generatingBlock))
- pos = 0; // See above.
- else {
- ensureFloatSize (vloat);
- pos = max (getAllocation(vloat->generatingBlock)->y + vloat->yReal
- + vloat->size.ascent + vloat->size.descent
- - getAllocation(tb)->y,
- 0);
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "float %p => max (%d + %d + (%d + %d) - %d, 0)",
- vloat->getWidget (),
- getAllocation(vloat->generatingBlock)->y,
- vloat->yReal, vloat->size.ascent, vloat->size.descent,
- getAllocation(tb)->y);
- }
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
- DBG_OBJ_LEAVE ();
-
- return pos;
-}
-
-void OutOfFlowMgr::ensureFloatSize (Float *vloat)
-{
- // Historical note: relative sizes (e. g. percentages) are already
- // handled by (at this time) Layout::containerSizeChanged, so
- // Float::dirty will be set.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p",
- vloat->getWidget ());
-
- if (vloat->dirty) {
- DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation");
-
- vloat->getWidget()->sizeRequest (&vloat->size);
- vloat->cbLineBreakWidth = containingBlock->getLineBreakWidth ();
- vloat->dirty = false;
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)",
- vloat->size.width, vloat->size.ascent, vloat->size.descent);
-
- DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width",
- vloat->size.width);
- DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent",
- vloat->size.ascent);
- DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent",
- vloat->size.descent);
-
- // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd()
- }
-
- DBG_OBJ_LEAVE ();
-}
+} // namespace oof
} // namespace dw
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index 78146d08..88ec349d 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -5,431 +5,145 @@
namespace dw {
-class Textblock;
+/**
+ * \brief Out Of Flow. See \ref dw-out-of-flow.
+ */
+namespace oof {
+
+class OOFAwareWidget;
/**
- * \brief Represents additional data for containing blocks.
+ * \brief Represents additional data for OOF containers.
*/
class OutOfFlowMgr
{
- friend class WidgetInfo;
-
-private:
- enum Side { LEFT, RIGHT };
- enum SFVType { GB, CB };
-
- Textblock *containingBlock;
-
- // These two values are redundant to TBInfo::wasAllocated and
- // TBInfo::allocation, for some special cases.
- bool containingBlockWasAllocated;
- core::Allocation containingBlockAllocation;
-
- class WidgetInfo: public lout::object::Object
- {
- private:
- bool wasAllocated;
- int xCB, yCB; // relative to the containing block
- int width, height;
-
- OutOfFlowMgr *oofm;
- core::Widget *widget;
-
- protected:
- OutOfFlowMgr *getOutOfFlowMgr () { return oofm; }
-
- public:
- WidgetInfo (OutOfFlowMgr *oofm, core::Widget *widget);
-
- inline bool wasThenAllocated () { return wasAllocated; }
- inline int getOldXCB () { return xCB; }
- inline int getOldYCB () { return yCB; }
- inline int getOldWidth () { return width; }
- inline int getOldHeight () { return height; }
-
-
- void update (bool wasAllocated, int xCB, int yCB, int width, int height);
-
- inline core::Widget *getWidget () { return widget; }
- };
-
- class Float: public WidgetInfo
- {
- public:
- class ComparePosition: public lout::object::Comparator
- {
- private:
- OutOfFlowMgr *oofm;
- Textblock *refTB;
- SFVType type; // actually only used for debugging
-
- public:
- ComparePosition (OutOfFlowMgr *oofm, Textblock *refTB, SFVType type)
- { this->oofm = oofm; this->refTB = refTB; this->type = type; }
- int compare(Object *o1, Object *o2);
- };
-
- class CompareSideSpanningIndex: public lout::object::Comparator
- {
- public:
- int compare(Object *o1, Object *o2);
- };
-
- class CompareGBAndExtIndex: public lout::object::Comparator
- {
- private:
- OutOfFlowMgr *oofm;
- SFVType type; // actually only used for debugging
-
- public:
- CompareGBAndExtIndex (OutOfFlowMgr *oofm, SFVType type)
- { this->oofm = oofm; this->type = type; }
- int compare(Object *o1, Object *o2);
- };
-
- Textblock *generatingBlock;
- int externalIndex;
- int yReq, yReal; // relative to generator, not container
- int indexGBList; /* Refers to TBInfo::leftFloatsGB or
- TBInfo::rightFloatsGB, respectively. -1
- initially. */
- int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB,
- respectively. -1 initially. */
- int sideSpanningIndex, mark;
- core::Requisition size;
- int cbLineBreakWidth; /* On which the calculation of relative sizes
- is based. Height not yet used, and probably
- not added before size redesign. */
- bool dirty, sizeChangedSinceLastAllocation;
-
- Float (OutOfFlowMgr *oofm, core::Widget *widget,
- Textblock *generatingBlock, int externalIndex);
-
- inline bool isNowAllocated () { return getWidget()->wasAllocated (); }
- inline int getNewXCB () { return getWidget()->getAllocation()->x -
- getOutOfFlowMgr()->containingBlockAllocation.x; }
- inline int getNewYCB () { return getWidget()->getAllocation()->y -
- getOutOfFlowMgr()->containingBlockAllocation.y; }
- inline int getNewWidth () { return getWidget()->getAllocation()->width; }
- inline int getNewHeight () { return getWidget()->getAllocation()->ascent +
- getWidget()->getAllocation()->descent; }
- void updateAllocation ();
-
- inline int *getIndexRef (SFVType type) {
- return type == GB ? &indexGBList : &indexCBList; }
- inline int getIndex (SFVType type) { return *(getIndexRef (type)); }
- inline void setIndex (SFVType type, int value) {
- *(getIndexRef (type)) = value; }
-
- void intoStringBuffer(lout::misc::StringBuffer *sb);
-
- bool covers (Textblock *textblock, int y, int h);
- };
+public:
+ OutOfFlowMgr ();
+ virtual ~OutOfFlowMgr ();
+
+ virtual void sizeAllocateStart (OOFAwareWidget *caller,
+ core::Allocation *allocation) = 0;
+ virtual void sizeAllocateEnd (OOFAwareWidget *caller) = 0;
+ virtual void containerSizeChangedForChildren () = 0;
+ virtual void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context) = 0;
+
+ virtual void markSizeChange (int ref) = 0;
+ virtual void markExtremesChange (int ref) = 0;
+ virtual core::Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext
+ *context) = 0;
+
+ virtual void addWidgetInFlow (OOFAwareWidget *widget,
+ OOFAwareWidget *parent, int externalIndex) = 0;
+ virtual int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator,
+ int externalIndex) = 0;
+ virtual void calcWidgetRefSize (core::Widget *widget,
+ core::Requisition *size) = 0;
+ virtual void moveExternalIndices (OOFAwareWidget *generator,
+ int oldStartIndex, int diff) = 0;
+
+ /**
+ * \brief Called before tellPosition2, see there for more.
+ */
+ virtual void tellPosition1 (core::Widget *widget, int x, int y) = 0;
/**
- * This list is kept sorted.
- *
- * To prevent accessing methods of the base class in an
- * uncontrolled way, the inheritance is private, not public; this
- * means that all methods must be delegated (see iterator(), size()
- * etc. below.)
- *
- * TODO Update comment: still sorted, but ...
+ * \brief Called after tellPosition1.
*
- * More: add() and change() may check order again.
+ * An implementation should only implement either tellPosition1 or
+ * tellPosition2. Coordinates are relative to the *container*.
*/
- class SortedFloatsVector: private lout::container::typed::Vector<Float>
- {
- public:
- SFVType type;
-
- private:
- OutOfFlowMgr *oofm;
- Side side;
-
- public:
- inline SortedFloatsVector (OutOfFlowMgr *oofm, Side side, SFVType type) :
- lout::container::typed::Vector<Float> (1, false)
- { this->oofm = oofm; this->side = side; this->type = type; }
-
- int findFloatIndex (Textblock *lastGB, int lastExtIndex);
- int find (Textblock *textblock, int y, int start, int end);
- int findFirst (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex, int *lastReturn);
- int findLastBeforeSideSpanningIndex (int sideSpanningIndex);
- void put (Float *vloat);
-
- inline lout::container::typed::Iterator<Float> iterator()
- { return lout::container::typed::Vector<Float>::iterator (); }
- inline int size ()
- { return lout::container::typed::Vector<Float>::size (); }
- inline Float *get (int pos)
- { return lout::container::typed::Vector<Float>::get (pos); }
- inline void clear ()
- { lout::container::typed::Vector<Float>::clear (); }
- };
-
- class TBInfo: public WidgetInfo
- {
- public:
- int lineBreakWidth;
- int index; // position within "tbInfos"
-
- TBInfo *parent;
- int parentExtIndex;
+ virtual void tellPosition2 (core::Widget *widget, int x, int y) = 0;
- // These two values are set by sizeAllocateStart(), and they are
- // accessable also within sizeAllocateEnd() for the same
- // textblock, for which allocation and WAS_ALLOCATED is set
- // *after* sizeAllocateEnd(). See the two functions
- // wasAllocated(Widget*) and getAllocation(Widget*) (further
- // down) for usage.
- bool wasAllocated;
- core::Allocation allocation;
- int clearPosition;
+ virtual void tellIncompletePosition1 (core::Widget *generator,
+ core::Widget *widget, int x, int y)
+ = 0;
+ virtual void tellIncompletePosition2 (core::Widget *generator,
+ core::Widget *widget, int x, int y)
+ = 0;
- // These two lists store all floats generated by this textblock,
- // as long as this textblock is not allocates.
- SortedFloatsVector *leftFloatsGB, *rightFloatsGB;
-
- TBInfo (OutOfFlowMgr *oofm, Textblock *textblock,
- TBInfo *parent, int parentExtIndex);
- ~TBInfo ();
-
- inline bool isNowAllocated () {
- return getOutOfFlowMgr()->wasAllocated (getTextblock ()); }
- inline int getNewXCB () {
- return getOutOfFlowMgr()->getAllocation (getTextblock ())->x -
- getOutOfFlowMgr()->containingBlockAllocation.x; }
- inline int getNewYCB () {
- return getOutOfFlowMgr()->getAllocation (getTextblock ())->y -
- getOutOfFlowMgr()->containingBlockAllocation.y; }
- inline int getNewWidth () {
- return getOutOfFlowMgr()->getAllocation (getTextblock ())->width; }
- inline int getNewHeight () {
- core::Allocation *allocation =
- getOutOfFlowMgr()->getAllocation (getTextblock ());
- return allocation->ascent + allocation->descent; }
- void updateAllocation ();
-
- inline Textblock *getTextblock () { return (Textblock*)getWidget (); }
- };
-
- // These two lists store all floats, in the order in which they are
- // defined. Only used for iterators.
- lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll;
-
- // These two lists store all floats whose generators are already
- // allocated.
- SortedFloatsVector *leftFloatsCB, *rightFloatsCB;
-
- // These two attributes are used in the size allocation process;
- // see sizeAllocateStart and sizeAllocateEnd.
- int lastAllocatedLeftFloat, lastAllocatedRightFloat;
-
- lout::container::typed::HashTable<lout::object::TypedPointer
- <dw::core::Widget>, Float> *floatsByWidget;
-
- lout::container::typed::Vector<TBInfo> *tbInfos;
- lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>,
- TBInfo> *tbInfosByTextblock;
-
- int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
+ virtual void getSize (core::Requisition *containerReq, int *oofWidth,
+ int *oofHeight) = 0;
+ virtual bool containerMustAdjustExtraSpace ()= 0;
+ virtual void getExtremes (core::Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth) = 0;
/**
- * Variant of Widget::wasAllocated(), which can also be used within
- * OOFM::sizeAllocateEnd().
+ * Get the left border for the vertical position of *y*, for a height
+ * of *h", based on floats; relative to the *container*.
+ *
+ * The border includes marging/border/padding of the calling textblock
+ * but is 0 if there is no float, so a caller should also consider
+ * other borders.
*/
- inline bool wasAllocated (Textblock *textblock) {
- return getTextblock(textblock)->wasAllocated;
- }
+ virtual int getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
/**
- * Variant of Widget::getAllocation(), which can also be used
- * within OOFM::sizeAllocateEnd().
+ * Get the right border for the vertical position of *y*, for a height
+ * of *h*, based on floats; relative to the *container*.
+ *
+ * See also getLeftBorder().
*/
- inline core::Allocation *getAllocation (Textblock *textblock) {
- return &(getTextblock(textblock)->allocation);
- }
-
- void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
- int diff);
- Float *findFloatByWidget (core::Widget *widget);
+ virtual int getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
- void moveFromGBToCB (Side side);
- void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
- int getGBWidthForAllocation (Float *vloat);
- int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth);
-
- bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos,
- core::Widget **minFloat);
- bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos,
- core::Widget **minFloat);
- bool hasRelationChanged (bool oldTBAlloc,
- int oldTBx, int oldTBy, int oldTBw, int oldTBh,
- int newTBx, int newTBy, int newTBw, int newTBh,
- bool oldFlAlloc,
- int oldFlx, int oldFly, int oldFlw, int oldFlh,
- int newFlx, int newFly, int newFlw, int newFlh,
- Side side, int *floatPos);
-
- void checkAllocatedFloatCollisions (Side side);
-
- bool doFloatsExceedCB (Side side);
- bool haveExtremesChanged (Side side);
-
- void drawFloats (SortedFloatsVector *list, core::View *view,
- core::Rectangle *area);
- core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
- int level);
-
- bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal,
- bool useAllocation);
- bool collidesH (Float *vloat, Float *other, SFVType type);
-
- void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
- SortedFloatsVector **listOpp, Side *side);
-
- void getFloatsSize (core::Requisition *cbReq, Side side, int *width,
- int *height);
- void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth,
- int *maxWidth);
-
- TBInfo *getTextblock (Textblock *textblock);
- int getBorder (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- SortedFloatsVector *getFloatsListForTextblock (Textblock *textblock,
- Side side);
- bool hasFloat (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getFloatHeight (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int calcClearPosition (Textblock *tb, Side side);
- int calcClearPosition (Textblock *tb);
-
- void ensureFloatSize (Float *vloat);
-
- void tellFloatPosition (core::Widget *widget, int yReq);
-
- static inline bool isStyleFloat (core::style::Style *style)
- { return style->vloat != core::style::FLOAT_NONE; }
- static inline bool isWidgetFloat (core::Widget *widget)
- { return isStyleFloat (widget->getStyle()); }
-
- /*
- * Format for parent ref (see also below for isRefOutOfFlow,
- * createRefNormalFlow, and getLineNoFromRef.
- *
- * Widget in flow:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | line number | 0 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * So, anything with the least signifant bit set to 1 is out of flow.
- *
- * Floats:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | left float index | 0 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | right float index | 1 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ /**
+ * Return whether there is a float on the left side. *y* is
+ * relative to the *container*.
*
- * Absolutely positioned blocks: solved differently in the
- * "dillo_grows" repository.
+ * See also getLeftBorder().
*/
+ virtual bool hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
- inline static bool isRefFloat (int ref)
- { return ref != -1 && (ref & 3) == 1; }
- inline static bool isRefLeftFloat (int ref)
- { return ref != -1 && (ref & 7) == 1; }
- inline static bool isRefRightFloat (int ref)
- { return ref != -1 && (ref & 7) == 5; }
-
- inline static int createRefLeftFloat (int index)
- { return (index << 3) | 1; }
- inline static int createRefRightFloat (int index)
- { return (index << 3) | 5; }
-
- inline static int getFloatIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 3); }
-
-public:
- OutOfFlowMgr (Textblock *containingBlock);
- ~OutOfFlowMgr ();
-
- void sizeAllocateStart (Textblock *caller, core::Allocation *allocation);
- void sizeAllocateEnd (Textblock *caller);
- void containerSizeChangedForChildren ();
- void draw (core::View *view, core::Rectangle *area);
-
- void markSizeChange (int ref);
- void markExtremesChange (int ref);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
-
- static bool isStyleOutOfFlow (core::style::Style *style)
- { return isStyleFloat (style); }
- static inline bool isWidgetOutOfFlow (core::Widget *widget)
- { return isStyleOutOfFlow (widget->getStyle()); }
-
- void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
- int externalIndex);
- void addWidgetOOF (core::Widget *widget, Textblock *generatingBlock,
- int externalIndex);
- void moveExternalIndices (Textblock *generatingBlock, int oldStartIndex,
- int diff);
-
- void tellPosition (core::Widget *widget, int yReq);
-
- void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
- void getExtremes (core::Extremes *cbExtr,
- int *oofMinWidth, int *oofMaxWidth);
-
- int getLeftBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- int getRightBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- bool hasFloatLeft (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- bool hasFloatRight (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- int getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- int getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getClearPosition (Textblock *tb);
+ /**
+ * Return whether there is a float on the right side. *y* is
+ * relative to the *container*.
+ *
+ * See also hasFloatLeft(), getLeftBorder();
+ */
+ virtual bool hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
- inline static bool isRefOutOfFlow (int ref)
- { return ref != -1 && (ref & 1) != 0; }
- inline static int createRefNormalFlow (int lineNo) { return lineNo << 1; }
- inline static int getLineNoFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 1); }
+ /**
+ * Assuming there is a float on the left side, return the rest
+ * height of it. *y* is relative to the *container*.
+ *
+ * See also getLeftBorder().
+ */
+ virtual int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+ = 0;
+ /**
+ * Assuming there is a float on the right side, return the rest
+ * height of it. *y* is relative to the *container*.
+ *
+ * See also getLeftFloatHeight(), getLeftBorder().
+ */
+ virtual int getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+ = 0;
+
+ virtual bool affectsLeftBorder (core::Widget *widget) = 0;
+ virtual bool affectsRightBorder (core::Widget *widget) = 0;
+ virtual bool mayAffectBordersAtAll () = 0;
+
+ virtual int getClearPosition (OOFAwareWidget *widget) = 0;
+
+ virtual bool dealingWithSizeOfChild (core::Widget *child) = 0;
+ virtual int getAvailWidthOfChild (core::Widget *child, bool forceValue) = 0;
+ virtual int getAvailHeightOfChild (core::Widget *child, bool forceValue) = 0;
+
// for iterators
- inline int getNumWidgets ()
- { return leftFloatsAll->size() + rightFloatsAll->size(); }
-
- inline core::Widget *getWidget (int i) {
- if (i < leftFloatsAll->size())
- return leftFloatsAll->get(i)->getWidget ();
- else
- return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
- }
-
- inline bool affectsLeftBorder (core::Widget *widget) {
- return widget->getStyle()->vloat == core::style::FLOAT_LEFT; }
- inline bool affectsRightBorder (core::Widget *widget) {
- return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; }
+ virtual int getNumWidgets () = 0;
+ virtual core::Widget *getWidget (int i) = 0;
};
+} // namespace oof
+
} // namespace dw
#endif // __DW_OUTOFFLOWMGR_HH__
diff --git a/dw/regardingborder.hh b/dw/regardingborder.hh
index 4c8951ad..1cb6c25f 100644
--- a/dw/regardingborder.hh
+++ b/dw/regardingborder.hh
@@ -1,7 +1,7 @@
#ifndef __DW_REGARDINGBORDER_HH__
#define __DW_REGARDINGBORDER_HH__
-#include "core.hh"
+#include "oofawarewidget.hh"
namespace dw {
@@ -9,11 +9,8 @@ namespace dw {
* \brief Base class (rather a tag interface) for those widgets
* regarding borders defined by floats, and so allocated on the
* full width.
- *
- * Will, when integrated to the "dillo_grows" repository, become a sub
- * class of OOFAwareWidget.
*/
-class RegardingBorder: public core::Widget
+class RegardingBorder: public oof::OOFAwareWidget
{
public:
static int CLASS_ID;
diff --git a/dw/ruler.cc b/dw/ruler.cc
index ccf58baa..bff43479 100644
--- a/dw/ruler.cc
+++ b/dw/ruler.cc
@@ -39,17 +39,16 @@ Ruler::~Ruler ()
DBG_OBJ_DELETE ();
}
-void Ruler::sizeRequestImpl (core::Requisition *requisition)
+void Ruler::sizeRequestSimpl (core::Requisition *requisition)
{
- requisition->width =
- lout::misc::max (getAvailWidth (true), getStyle()->boxDiffWidth ());
- requisition->ascent = getStyle()->boxOffsetY ();
- requisition->descent = getStyle()->boxRestHeight ();
+ requisition->width = lout::misc::max (getAvailWidth (true), boxDiffWidth ());
+ requisition->ascent = boxOffsetY ();
+ requisition->descent = boxRestHeight ();
}
-void Ruler::getExtremesImpl (core::Extremes *extremes)
+void Ruler::getExtremesSimpl (core::Extremes *extremes)
{
- extremes->minWidth = extremes->maxWidth = getStyle()->boxDiffWidth ();
+ extremes->minWidth = extremes->maxWidth = boxDiffWidth ();
extremes->minWidthIntrinsic = extremes->minWidth;
extremes->maxWidthIntrinsic = extremes->maxWidth;
correctExtremes (extremes, false);
@@ -74,7 +73,8 @@ bool Ruler::usesAvailWidth ()
return true;
}
-void Ruler::draw (core::View *view, core::Rectangle *area)
+void Ruler::draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context)
{
drawWidgetBox (view, area, false);
}
diff --git a/dw/ruler.hh b/dw/ruler.hh
index cd4f63f4..74323d95 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -14,18 +14,18 @@ namespace dw {
* Ruler implements RegardingBorder; this way, it is simpler to fit
* the ruler exactly within the space between floats. Currently, the
* drawn area of the ruler is too large (but most of the superfluous
- * part is hidden by the floats); this problem will not solved but in
- * "dillo_grows", where RegardingBorder is a sub class of
- * OOFAwareWidget.
+ * part is hidden by the floats); this problem will soon solved here
+ * in the "dillo_grows" repository.
*/
class Ruler: public RegardingBorder
{
protected:
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void sizeRequestSimpl (core::Requisition *requisition);
+ void getExtremesSimpl (core::Extremes *extremes);
void containerSizeChangedForChildren ();
bool usesAvailWidth ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
public:
static int CLASS_ID;
diff --git a/dw/selection.cc b/dw/selection.cc
index b67f4a6d..a69eb82a 100644
--- a/dw/selection.cc
+++ b/dw/selection.cc
@@ -93,63 +93,79 @@ void SelectionState::resetLink ()
bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo,
EventButton *event)
{
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ it->intoStringBuffer (&sb);
+ DBG_OBJ_ENTER ("events", 0, "buttonPress", "[%s], %d, %d, ...",
+ sb.getChars (), charPos, linkNo);
+ }
+
Widget *itWidget = it->getWidget ();
bool ret = false;
- if (!event) return ret;
-
- if (event->button == 3) {
- // menu popup
- layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
- ret = true;
- } else if (linkNo != -1) {
- // link handling
- (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
- resetLink ();
- linkState = LINK_PRESSED;
- linkButton = event->button;
- DeepIterator *newLink = new DeepIterator (it);
- if (newLink->isEmpty ()) {
- delete newLink;
+ if (event) {
+ if (event->button == 3) {
+ // menu popup
+ layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
+ ret = true;
+ } else if (linkNo != -1) {
+ // link handling
+ (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
resetLink ();
- } else {
- link = newLink;
- // It may be that the user has pressed on something activatable
- // (linkNo != -1), but there is no contents, e.g. with images
- // without ALTernative text.
- if (link) {
- linkChar = correctCharPos (link, charPos);
- linkNumber = linkNo;
+ linkState = LINK_PRESSED;
+ linkButton = event->button;
+ DeepIterator *newLink = new DeepIterator (it);
+ if (newLink->isEmpty ()) {
+ delete newLink;
+ resetLink ();
+ } else {
+ link = newLink;
+ // It may be that the user has pressed on something activatable
+ // (linkNo != -1), but there is no contents, e.g. with images
+ // without ALTernative text.
+ if (link) {
+ linkChar = correctCharPos (link, charPos);
+ linkNumber = linkNo;
+ }
}
- }
- // We do not return the value of the signal method,
- // but we do actually process this event.
- ret = true;
- } else if (event->button == 1) {
- // normal selection handling
- highlight (false, 0);
- resetSelection ();
-
- selectionState = SELECTING;
- DeepIterator *newFrom = new DeepIterator (it);
- if (newFrom->isEmpty ()) {
- delete newFrom;
+ // We do not return the value of the signal method,
+ // but we do actually process this event.
+ ret = true;
+ } else if (event->button == 1) {
+ // normal selection handling
+ highlight (false, 0);
resetSelection ();
- } else {
- from = newFrom;
- fromChar = correctCharPos (from, charPos);
- to = from->cloneDeepIterator ();
- toChar = correctCharPos (to, charPos);
+
+ selectionState = SELECTING;
+ DeepIterator *newFrom = new DeepIterator (it);
+ if (newFrom->isEmpty ()) {
+ delete newFrom;
+ resetSelection ();
+ } else {
+ from = newFrom;
+ fromChar = correctCharPos (from, charPos);
+ to = from->cloneDeepIterator ();
+ toChar = correctCharPos (to, charPos);
+ }
+ ret = true;
}
- ret = true;
}
+ DBG_OBJ_MSGF ("events", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
return ret;
}
bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo,
EventButton *event)
{
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ it->intoStringBuffer (&sb);
+ DBG_OBJ_ENTER ("events", 0, "buttonRelease", "[%s], %d, %d, ...",
+ sb.getChars (), charPos, linkNo);
+ }
+
Widget *itWidget = it->getWidget ();
bool ret = false;
@@ -186,6 +202,8 @@ bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo,
}
}
+ DBG_OBJ_MSGF ("events", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
return ret;
}
diff --git a/dw/simpletablecell.cc b/dw/simpletablecell.cc
index feec46c8..f39d94b5 100644
--- a/dw/simpletablecell.cc
+++ b/dw/simpletablecell.cc
@@ -57,7 +57,7 @@ bool SimpleTableCell::mustBeWidenedToAvailWidth ()
int SimpleTableCell::getAvailWidthOfChild (Widget *child, bool forceValue)
{
- DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell/getAvailWidthOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell::getAvailWidthOfChild",
"%p, %s", child, forceValue ? "true" : "false");
int width = tablecell::correctAvailWidthOfChild
@@ -70,7 +70,7 @@ int SimpleTableCell::getAvailWidthOfChild (Widget *child, bool forceValue)
int SimpleTableCell::getAvailHeightOfChild (Widget *child, bool forceValue)
{
- DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell/getAvailHeightOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell::getAvailHeightOfChild",
"%p, %s", child, forceValue ? "true" : "false");
int height = tablecell::correctAvailHeightOfChild
@@ -87,7 +87,7 @@ void SimpleTableCell::correctRequisitionOfChild (Widget *child,
int*,
int*))
{
- DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell/correctRequisitionOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell::correctRequisitionOfChild",
"%p, %d * (%d + %d), ...", child, requisition->width,
requisition->ascent, requisition->descent);
@@ -102,7 +102,7 @@ void SimpleTableCell::correctExtremesOfChild (Widget *child,
core::Extremes *extremes,
bool useAdjustmentWidth)
{
- DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell/correctExtremesOfChild",
+ DBG_OBJ_ENTER ("resize", 0, "SimpleTableCell::correctExtremesOfChild",
"%p, %d (%d) / %d (%d)",
child, extremes->minWidth, extremes->minWidthIntrinsic,
extremes->maxWidth, extremes->maxWidthIntrinsic);
@@ -126,4 +126,9 @@ int SimpleTableCell::applyPerHeight (int containerHeight,
return tablecell::applyPerHeight (this, containerHeight, perHeight);
}
+bool SimpleTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF ()
+{
+ return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+}
+
} // namespace dw
diff --git a/dw/simpletablecell.hh b/dw/simpletablecell.hh
index 60715d90..90f24ae4 100644
--- a/dw/simpletablecell.hh
+++ b/dw/simpletablecell.hh
@@ -19,6 +19,8 @@ protected:
bool getAdjustMinWidth ();
+ bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
public:
static int CLASS_ID;
diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc
new file mode 100644
index 00000000..98cef164
--- /dev/null
+++ b/dw/stackingcontextmgr.cc
@@ -0,0 +1,195 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.hh"
+#include "../lout/debug.hh"
+
+using namespace lout::misc;
+using namespace lout::container::typed;
+
+namespace dw {
+
+namespace core {
+
+StackingContextMgr::StackingContextMgr (Widget *widget)
+{
+ DBG_OBJ_CREATE ("dw::core::StackingContextMgr");
+
+ this->widget = widget;
+
+ childSCWidgets = new Vector<Widget> (1, false);
+ DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size());
+
+ numZIndices = 0;
+ zIndices = NULL;
+ DBG_OBJ_SET_NUM ("numZIndices", numZIndices);
+}
+
+StackingContextMgr::~StackingContextMgr ()
+{
+ delete childSCWidgets;
+ if (zIndices)
+ free (zIndices);
+ DBG_OBJ_DELETE ();
+}
+
+void StackingContextMgr::addChildSCWidget (Widget *widget)
+{
+ DBG_OBJ_ENTER ("common.scm", 0, "addChildSCWidget", "%p [z-index = %d]",
+ widget, widget->getStyle()->zIndex);
+
+ int pos = findZIndex (widget->getStyle()->zIndex, true);
+ DBG_OBJ_MSGF ("common.scm", 1, "pos = %d", pos);
+ if (pos == -1) {
+ pos = findZIndex (widget->getStyle()->zIndex, false);
+ DBG_OBJ_MSGF ("common.scm", 1, "pos = %d", pos);
+
+ numZIndices++;
+ DBG_OBJ_SET_NUM ("numZIndices", numZIndices);
+ zIndices = (int*)(zIndices ?
+ realloc (zIndices, numZIndices * sizeof (int)) :
+ malloc (numZIndices * sizeof (int)));
+
+ for (int i = numZIndices - 1; i >= pos + 1; i--) {
+ zIndices[i] = zIndices[i - 1];
+ DBG_OBJ_ARRSET_NUM ("zIndex", i, zIndices[i]);
+ }
+
+ zIndices[pos] = widget->getStyle()->zIndex;
+ DBG_OBJ_ARRSET_NUM ("zIndex", pos, zIndices[pos]);
+ }
+
+ childSCWidgets->put (widget);
+ DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size());
+ DBG_OBJ_ARRSET_PTR ("childSCWidgets", childSCWidgets->size() - 1, widget);
+
+ DBG_OBJ_LEAVE ();
+}
+
+int StackingContextMgr::findZIndex (int zIndex, bool mustExist)
+{
+ int result = -123; // Compiler happiness: GCC 4.7 does not handle this?
+
+ if (numZIndices == 0)
+ result = mustExist ? -1 : 0;
+ else {
+ int low = 0, high = numZIndices - 1;
+ bool found = false;
+
+ while (!found) {
+ int index = (low + high) / 2;
+ if (zIndex == zIndices[index]) {
+ found = true;
+ result = index;
+ } else {
+ if (low >= high) {
+ if (mustExist) {
+ found = true;
+ result = -1;
+ } else {
+ found = true;
+ result = zIndex > zIndices[index] ? index + 1 : index;
+ }
+ }
+
+ if (zIndex < zIndices[index])
+ high = index - 1;
+ else
+ low = index + 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+void StackingContextMgr::draw (View *view, Rectangle *area, int startZIndex,
+ int endZIndex, DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "[%d, %d, %d * %d], %d, %d",
+ area->x, area->y, area->width, area->height, startZIndex,
+ endZIndex);
+
+ for (int zIndexIndex = 0; zIndexIndex < numZIndices; zIndexIndex++) {
+ // Wrong region of z-indices (top or bottom) is simply ignored
+ // (as well as non-defined zIndices).
+ if (zIndices != NULL && zIndices[zIndexIndex] >= startZIndex &&
+ zIndices[zIndexIndex] <= endZIndex) {
+ DBG_OBJ_MSGF ("draw", 1, "drawing zIndex = %d", zIndices[zIndexIndex]);
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < childSCWidgets->size (); i++) {
+ Widget *child = childSCWidgets->get (i);
+ DBG_OBJ_MSGF ("draw", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+
+ Rectangle childArea;
+ if (child->getStyle()->zIndex == zIndices[zIndexIndex] &&
+ child->intersects (widget, area, &childArea))
+ child->draw (view, &childArea, context);
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+Widget *StackingContextMgr::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext
+ *context,
+ int startZIndex, int endZIndex)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+
+ for (int zIndexIndex = numZIndices - 1;
+ widgetAtPoint == NULL && zIndexIndex >= 0; zIndexIndex--) {
+ // Wrong region of z-indices (top or bottom) is simply ignored
+ // (as well as non-defined zIndices).
+ if (zIndices != NULL && zIndices[zIndexIndex] >= startZIndex &&
+ zIndices[zIndexIndex] <= endZIndex) {
+ DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d",
+ zIndices[zIndexIndex]);
+ DBG_OBJ_MSG_START ();
+
+ for (int i = childSCWidgets->size () - 1;
+ widgetAtPoint == NULL && i >= 0; i--) {
+ Widget *child = childSCWidgets->get (i);
+ DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ if (child->getStyle()->zIndex == zIndices[zIndexIndex])
+ widgetAtPoint = child->getWidgetAtPoint (x, y, context);
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+} // namespace core
+
+} // namespace dw
diff --git a/dw/stackingcontextmgr.hh b/dw/stackingcontextmgr.hh
new file mode 100644
index 00000000..3a877031
--- /dev/null
+++ b/dw/stackingcontextmgr.hh
@@ -0,0 +1,75 @@
+#ifndef __DW_STACKINGCONTEXTMGR_HH__
+#define __DW_STACKINGCONTEXTMGR_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include "../lout/container.hh"
+
+#include <limits.h>
+
+namespace dw {
+
+namespace core {
+
+/**
+ * \brief See \ref dw-stacking-context.
+ */
+class StackingContextMgr
+{
+private:
+ Widget *widget;
+ lout::container::typed::Vector<Widget> *childSCWidgets;
+ int *zIndices, numZIndices;
+
+ int findZIndex (int zIndex, bool mustExist);
+ void draw (View *view, Rectangle *area, int startZIndex, int endZIndex,
+ DrawingContext *context);
+ Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *context,
+ int startZIndex, int endZIndex);
+
+public:
+ StackingContextMgr (Widget *widget);
+ ~StackingContextMgr ();
+
+ inline static bool isEstablishingStackingContext (Widget *widget) {
+ return widget->getStyle()->position != style::POSITION_STATIC &&
+ widget->getStyle()->zIndex != style::Z_INDEX_AUTO;
+ }
+
+ inline static bool handledByStackingContextMgr (Widget *widget) {
+ // Each widget establishing a stacking context is child of another
+ // stacking context, so drawn by StackingContextMgr::drawTop or
+ // StackingContextMgr::drawBottom etc.
+ return widget->getParent () != NULL
+ && isEstablishingStackingContext (widget);
+ }
+
+ void addChildSCWidget (Widget *widget);
+
+ inline int getNumZIndices () { return numZIndices; }
+ inline int getNumChildSCWidgets () { return childSCWidgets->size (); }
+
+ inline void drawBottom (View *view, Rectangle *area, DrawingContext *context)
+ { draw (view, area, INT_MIN, -1, context); }
+ void drawTop (View *view, Rectangle *area, DrawingContext *context)
+ { draw (view, area, 0, INT_MAX, context); }
+
+ inline Widget *getTopWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext
+ *context)
+ { return getWidgetAtPoint (x, y, context, 0, INT_MAX); }
+
+ inline Widget *getBottomWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext
+ *context)
+ { return getWidgetAtPoint (x, y, context, INT_MIN, -1); }
+};
+
+} // namespace core
+
+} // namespace dw
+
+#endif // __DW_STACKINGCONTEXTMGR_HH__
diff --git a/dw/style.cc b/dw/style.cc
index 54d9af4b..32a33a9e 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -93,6 +93,7 @@ void StyleAttrs::initValues ()
display = DISPLAY_INLINE;
whiteSpace = WHITE_SPACE_NORMAL;
cursor = CURSOR_DEFAULT;
+ zIndex = Z_INDEX_AUTO;
}
/**
@@ -203,6 +204,7 @@ bool StyleAttrs::equals (object::Object *other) {
listStylePosition == otherAttrs->listStylePosition &&
listStyleType == otherAttrs->listStyleType &&
cursor == otherAttrs->cursor &&
+ zIndex == otherAttrs->zIndex &&
x_link == otherAttrs->x_link &&
x_lang[0] == otherAttrs->x_lang[0] &&
x_lang[1] == otherAttrs->x_lang[1] &&
@@ -260,6 +262,7 @@ int StyleAttrs::hashValue () {
listStylePosition +
listStyleType +
cursor +
+ zIndex +
x_link +
x_lang[0] + x_lang[1] +
x_img +
@@ -381,6 +384,7 @@ void Style::copyAttrs (StyleAttrs *attrs)
listStylePosition = attrs->listStylePosition;
listStyleType = attrs->listStyleType;
cursor = attrs->cursor;
+ zIndex = attrs->zIndex;
x_link = attrs->x_link;
x_lang[0] = attrs->x_lang[0];
x_lang[1] = attrs->x_lang[1];
diff --git a/dw/style.hh b/dw/style.hh
index 230baa24..12ca1664 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -7,6 +7,8 @@
# error Do not include this file directly, use "core.hh" instead.
#endif
+#include <limits.h>
+
#include "../lout/signal.hh"
#include "../lout/debug.hh"
@@ -374,6 +376,17 @@ enum ClearType {
CLEAR_NONE
};
+enum {
+ /**
+ * \brief 'z-index' is stored as int; use this for the value 'auto'.
+ *
+ * Only some random value, which has to be checked explicitly; do
+ * not compare this (less or greater) to integer values of
+ * 'z-index'.
+ */
+ Z_INDEX_AUTO = INT_MAX
+};
+
/**
* \brief Type for representing all lengths within dw::core::style.
*
@@ -553,6 +566,7 @@ public:
ListStylePosition listStylePosition;
ListStyleType listStyleType;
Cursor cursor;
+ int zIndex;
int x_link;
int x_img;
diff --git a/dw/table.cc b/dw/table.cc
index d55fd72f..4c953e62 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -103,7 +103,7 @@ Table::~Table()
DBG_OBJ_DELETE ();
}
-void Table::sizeRequestImpl (core::Requisition *requisition)
+void Table::sizeRequestSimpl (core::Requisition *requisition)
{
DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl");
@@ -112,22 +112,24 @@ void Table::sizeRequestImpl (core::Requisition *requisition)
/**
* \bug Baselines are not regarded here.
*/
- requisition->width = getStyle()->boxDiffWidth ()
- + (numCols + 1) * getStyle()->hBorderSpacing;
+ requisition->width =
+ boxDiffWidth () + (numCols + 1) * getStyle()->hBorderSpacing;
for (int col = 0; col < numCols; col++)
requisition->width += colWidths->get (col);
requisition->ascent =
- getStyle()->boxDiffHeight () + cumHeight->get (numRows)
- + getStyle()->vBorderSpacing;
+ boxDiffHeight () + cumHeight->get (numRows) + getStyle()->vBorderSpacing;
requisition->descent = 0;
correctRequisition (requisition, core::splitHeightPreserveDescent);
+ // For the order, see similar reasoning for dw::Textblock.
+ correctRequisitionByOOF (requisition, core::splitHeightPreserveDescent);
+
DBG_OBJ_LEAVE ();
}
-void Table::getExtremesImpl (core::Extremes *extremes)
+void Table::getExtremesSimpl (core::Extremes *extremes)
{
DBG_OBJ_ENTER0 ("resize", 0, "getExtremesImpl");
@@ -154,6 +156,9 @@ void Table::getExtremesImpl (core::Extremes *extremes)
correctExtremes (extremes, true);
+ // For the order, see similar reasoning for dw::Textblock.
+ correctExtremesByOOF (extremes);
+
DBG_OBJ_LEAVE ();
}
@@ -163,16 +168,16 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
allocation->x, allocation->y, allocation->width,
allocation->ascent, allocation->descent);
+ sizeAllocateStart (allocation);
+
calcCellSizes (true);
/**
* \bug Baselines are not regarded here.
*/
- int offy =
- allocation->y + getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
- int x =
- allocation->x + getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
+ int offy = allocation->y + boxOffsetY () + getStyle()->vBorderSpacing;
+ int x = allocation->x + boxOffsetX () + getStyle()->hBorderSpacing;
for (int col = 0; col < numCols; col++) {
for (int row = 0; row < numRows; row++) {
@@ -203,6 +208,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
x += colWidths->get (col) + getStyle()->hBorderSpacing;
}
+ sizeAllocateEnd ();
+
DBG_OBJ_LEAVE ();
}
@@ -220,34 +227,40 @@ int Table::getAvailWidthOfChild (Widget *child, bool forceValue)
child, forceValue ? "true" : "false");
int width;
+ oof::OutOfFlowMgr *oofm;
- // We do not calculate the column widths at this point, because
- // this tends to be rather inefficient for tables with many
- // cells:
- //
- // For each of the n cells, some text is added (say, only one word
- // per cell). Textblock::addText will eventually (via addText0
- // etc.) call this method, Table::getAvailWidthOfChild. If
- // calcCellSizes() is called here, this will call
- // forceCalcCellSizes(), since the last call, sizes have to be
- // re-calculated (because cells have been added). This will
- // calculate the extremes for each existing cell, so
- // Widget::getExtremes is called n * (n + 1) / 2 times. Even if the
- // extremes are cached (so that getExtremesImpl does not have to be
- // called in each case), this would make rendering tables with more
- // than a few hundred cells unacceptably slow.
- //
- // Instead, column widths are calculated in Table::sizeRequestImpl.
- //
- // An alternative would be incremental resizing for tables; this
- // approach resembles the behaviour before GROWS.
-
- // TODO Does it still make sence to return -1 when forceValue is
- // set?
- if (forceValue)
- width = calcAvailWidthForDescendant (child);
- else
- width = -1;
+ if (isWidgetOOF(child) && (oofm = getWidgetOutOfFlowMgr(child)) &&
+ oofm->dealingWithSizeOfChild (child))
+ width = oofm->getAvailWidthOfChild (child, forceValue);
+ else {
+ // We do not calculate the column widths at this point, because
+ // this tends to be rather inefficient for tables with many
+ // cells:
+ //
+ // For each of the n cells, some text is added (say, only one word
+ // per cell). Textblock::addText will eventually (via addText0
+ // etc.) call this method, Table::getAvailWidthOfChild. If
+ // calcCellSizes() is called here, this will call
+ // forceCalcCellSizes(), since the last call, sizes have to be
+ // re-calculated (because cells have been added). This will
+ // calculate the extremes for each existing cell, so
+ // Widget::getExtremes is called n * (n + 1) / 2 times. Even if the
+ // extremes are cached (so that getExtremesImpl does not have to be
+ // called in each case), this would make rendering tables with more
+ // than a few hundred cells unacceptably slow.
+ //
+ // Instead, column widths are calculated in Table::sizeRequestImpl.
+ //
+ // An alternative would be incremental resizing for tables; this
+ // approach resembles the behaviour before GROWS.
+
+ // TODO Does it still make sence to return -1 when forceValue is
+ // set?
+ if (forceValue)
+ width = calcAvailWidthForDescendant (child);
+ else
+ width = -1;
+ }
DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
DBG_OBJ_LEAVE ();
@@ -266,10 +279,17 @@ int Table::calcAvailWidthForDescendant (Widget *child)
assert (actualChild != NULL);
- // ActualChild->parentRef contains the position in the children
- // array (see addCell()), so the column can be easily determined.
- int col = actualChild->parentRef % numCols;
- int colspanEff = children->get(actualChild->parentRef)->cell.colspanEff;
+ // ActualChild->parentRef contains (indirectly) the position in the
+ // children array (see addCell()), so the column can be easily
+ // determined.
+ int childNo = getParentRefInFlowSubRef (actualChild->parentRef);
+ int col = childNo % numCols;
+ DBG_OBJ_MSGF ("resize", 1, "actualChild = %p, "
+ "childNo = getParentRefInFlowSubRef (%d) = %d, "
+ "column = %d %% %d = %d",
+ actualChild, actualChild->parentRef, childNo, childNo,
+ numCols, col);
+ int colspanEff = children->get(childNo)->cell.colspanEff;
DBG_OBJ_MSGF ("resize", 1, "calculated from column %d, colspanEff = %d",
col, colspanEff);
@@ -318,6 +338,8 @@ void Table::containerSizeChangedForChildren ()
}
}
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -353,18 +375,21 @@ bool Table::isBlockLevel ()
return true;
}
-void Table::draw (core::View *view, core::Rectangle *area)
+void Table::drawLevel (core::View *view, core::Rectangle *area, int level,
+ core::DrawingContext *context)
{
- // Can be optimized, by iterating on the lines in area.
- drawWidgetBox (view, area, false);
+ DBG_OBJ_ENTER ("draw", 0, "Table::drawLevel", "[%d, %d, %d * %d], %s",
+ area->x, area->y, area->width, area->height,
+ stackingLevelText (level));
#if 0
+ // This old code belongs perhaps to the background. Check when reactivated.
int offx = getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
int offy = getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
int width = getContentWidth ();
-
+
// This part seems unnecessary. It also segfaulted sometimes when
- // cumHeight size was less than numRows. --jcid
+ // cumHeight size was less than numRows. --jcid
for (int row = 0; row < numRows; row++) {
if (rowStyle->get (row))
drawBox (view, rowStyle->get (row), area,
@@ -375,14 +400,58 @@ void Table::draw (core::View *view, core::Rectangle *area)
}
#endif
- for (int i = 0; i < children->size (); i++) {
- if (childDefined (i)) {
- Widget *child = children->get(i)->cell.widget;
- core::Rectangle childArea;
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ switch (level) {
+ case SL_IN_FLOW:
+ for (int i = 0; i < children->size (); i++) {
+ if (childDefined (i)) {
+ Widget *child = children->get(i)->cell.widget;
+ core::Rectangle childArea;
+ if (!core::StackingContextMgr::handledByStackingContextMgr (child)
+ && child->intersects (this, area, &childArea))
+ child->draw (view, &childArea, context);
+ }
+ }
+ break;
+
+ default:
+ OOFAwareWidget::drawLevel (view, area, level, context);
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+core::Widget *Table::getWidgetAtPointLevel (int x, int y, int level,
+ core::GettingWidgetAtPointContext
+ *context)
+{
+ DBG_OBJ_ENTER ("events", 0, "Table::getWidgetAtPointLevel", "%d, %d, %s",
+ x, y, stackingLevelText (level));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (level) {
+ case SL_IN_FLOW:
+ for (int i = children->size () - 1; widgetAtPoint == NULL && i >= 0;
+ i--) {
+ if (childDefined (i)) {
+ Widget *child = children->get(i)->cell.widget;
+ if (!core::StackingContextMgr::handledByStackingContextMgr (child))
+ widgetAtPoint = child->getWidgetAtPoint (x, y, context);
+ }
}
+ break;
+
+ default:
+ widgetAtPoint =
+ OOFAwareWidget::getWidgetAtPointLevel (x, y, level, context);
+ break;
}
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+
+ return widgetAtPoint;
}
void Table::removeChild (Widget *child)
@@ -475,14 +544,14 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
child->cell.rowspan = rowspan;
children->set (curRow * numCols + curCol, child);
- // The position in the children array is assigned to parentRef,
- // although incremental resizing is not implemented. Useful, e. g.,
- // in calcAvailWidthForDescendant(). See also reallocChildren().
- widget->parentRef = curRow * numCols + curCol;
+ // The position in the children array is (indirectly) assigned to parentRef,
+ // although incremental resizing is not implemented. Useful, e. g., in
+ // calcAvailWidthForDescendant(). See also reallocChildren().
+ widget->parentRef = makeParentRefInFlow (curRow * numCols + curCol);
DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
curCol += colspanEff;
-
+
widget->setParent (this);
if (rowStyle->get (curRow))
widget->setBgColor (rowStyle->get(curRow)->backgroundColor);
@@ -722,7 +791,7 @@ void Table::reallocChildren (int newNumCols, int newNumRows)
int n = row * newNumCols + col;
Child *child = children->get (n);
if (child != NULL && child->type == Child::CELL) {
- child->cell.widget->parentRef = n;
+ child->cell.widget->parentRef = makeParentRefInFlow (n);
DBG_OBJ_SET_NUM_O (child->cell.widget, "parentRef",
child->cell.widget->parentRef);
}
@@ -768,6 +837,9 @@ void Table::calcCellSizes (bool calcHeights)
void Table::forceCalcCellSizes (bool calcHeights)
{
+ DBG_OBJ_ENTER ("resize", 0, "forceCalcCellSizes", "%s",
+ calcHeights ? "true" : "false");
+
// Since Table::getAvailWidthOfChild does not calculate the column
// widths, and so initially a random value (100) is returned, a
// correction is necessary. The old values are temporary preserved
@@ -822,11 +894,14 @@ void Table::forceCalcCellSizes (bool calcHeights)
}
}
}
+
+ DBG_OBJ_LEAVE ();
}
void Table::actuallyCalcCellSizes (bool calcHeights)
{
- DBG_OBJ_ENTER0 ("resize", 0, "forceCalcCellSizes");
+ DBG_OBJ_ENTER ("resize", 0, "actuallyCalcCellSizes", "%s",
+ calcHeights ? "true" : "false");
int childHeight;
core::Extremes extremes;
diff --git a/dw/table.hh b/dw/table.hh
index 9b868642..3729da71 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -1,7 +1,7 @@
#ifndef __DW_TABLE_HH__
#define __DW_TABLE_HH__
-#include "core.hh"
+#include "oofawarewidget.hh"
#include "alignedtablecell.hh"
#include "../lout/misc.hh"
@@ -322,7 +322,7 @@ namespace dw {
* Here, \em foo-bar refers to the attribute \em bar of the tag \em foo foo.
* Look at the HTML parser for more details.
*/
-class Table: public core::Widget
+class Table: public oof::OOFAwareWidget
{
private:
struct Child
@@ -342,20 +342,17 @@ private:
};
};
- class TableIterator: public core::Iterator
+ class TableIterator: public OOFAwareWidgetIterator
{
- private:
- int index;
+ protected:
+ int numContentsInFlow ();
+ void getContentInFlow (int index, core::Content *content);
public:
TableIterator (Table *table, core::Content::Type mask, bool atEnd);
- TableIterator (Table *table, core::Content::Type mask, int index);
lout::object::Object *clone();
- int compareTo(lout::object::Comparable *other);
- bool next ();
- bool prev ();
void highlight (int start, int end, core::HighlightLayer layer);
void unhighlight (int direction, core::HighlightLayer layer);
void getAllocation (int start, int end, core::Allocation *allocation);
@@ -464,8 +461,8 @@ private:
}
protected:
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void sizeRequestSimpl (core::Requisition *requisition);
+ void getExtremesSimpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
void resizeDrawImpl ();
@@ -479,7 +476,11 @@ protected:
bool isBlockLevel ();
- void draw (core::View *view, core::Rectangle *area);
+ void drawLevel (core::View *view, core::Rectangle *area, int level,
+ core::DrawingContext *context);
+
+ Widget *getWidgetAtPointLevel (int x, int y, int level,
+ core::GettingWidgetAtPointContext *context);
//bool buttonPressImpl (core::EventButton *event);
//bool buttonReleaseImpl (core::EventButton *event);
diff --git a/dw/table_iterator.cc b/dw/table_iterator.cc
index 4da0ef4f..9ba61619 100644
--- a/dw/table_iterator.cc
+++ b/dw/table_iterator.cc
@@ -28,107 +28,62 @@ namespace dw {
Table::TableIterator::TableIterator (Table *table,
core::Content::Type mask, bool atEnd):
- core::Iterator (table, mask, atEnd)
+ OOFAwareWidgetIterator (table, mask, atEnd, table->children->size ())
{
- index = atEnd ? table->children->size () : -1;
- content.type = atEnd ? core::Content::END : core::Content::START;
-}
-
-Table::TableIterator::TableIterator (Table *table,
- core::Content::Type mask, int index):
- core::Iterator (table, mask, false)
-{
- this->index = index;
-
- if (index < 0)
- content.type = core::Content::START;
- else if (index >= table->children->size ())
- content.type = core::Content::END;
- else {
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- }
}
object::Object *Table::TableIterator::clone()
{
- return new TableIterator ((Table*)getWidget(), getMask(), index);
-}
-
-int Table::TableIterator::compareTo(object::Comparable *other)
-{
- return index - ((TableIterator*)other)->index;
+ TableIterator *tIt =
+ new TableIterator ((Table*)getWidget(), getMask(), false);
+ cloneValues (tIt);
+ return tIt;
}
-bool Table::TableIterator::next ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::END)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::END;
- return false;
- }
-
- do {
- index++;
- if (index >= table->children->size ()) {
- content.type = core::Content::END;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
-
-bool Table::TableIterator::prev ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::START)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::START;
- return false;
- }
-
- do {
- index--;
- if (index < 0) {
- content.type = core::Content::START;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
void Table::TableIterator::highlight (int start, int end,
core::HighlightLayer layer)
{
- /** todo Needs this an implementation? */
+ if (inFlow ()) {
+ /** todo Needs this an implementation? */
+ } else
+ highlightOOF (start, end, layer);
}
void Table::TableIterator::unhighlight (int direction,
core::HighlightLayer layer)
{
+ if (inFlow ()) {
+ // ???
+ } else
+ unhighlightOOF (direction, layer);
}
void Table::TableIterator::getAllocation (int start, int end,
core::Allocation *allocation)
{
- /** \bug Not implemented. */
+ if (inFlow ()) {
+ /** \bug Not implemented. */
+ } else
+ getAllocationOOF (start, end, allocation);
+}
+
+int Table::TableIterator::numContentsInFlow ()
+{
+ return ((Table*)getWidget())->children->size ();
+}
+
+void Table::TableIterator::getContentInFlow (int index,
+ core::Content *content)
+{
+ Table *table = (Table*)getWidget();
+
+ if (table->children->get(index) != NULL &&
+ table->children->get(index)->type == Child::CELL) {
+ content->type = core::Content::WIDGET_IN_FLOW;
+ content->widget = table->children->get(index)->cell.widget;
+ } else
+ content->type = core::Content::INVALID;
}
} // namespace dw
diff --git a/dw/tablecell.cc b/dw/tablecell.cc
index 3e143c96..a7b16776 100644
--- a/dw/tablecell.cc
+++ b/dw/tablecell.cc
@@ -45,7 +45,7 @@ bool isBlockLevel ()
int correctAvailWidthOfChild (core::Widget *widget, core::Widget *child,
int width, bool forceValue)
{
- DBG_OBJ_ENTER_O ("resize", 0, widget, "tablecell/correctAvailWidthOfChild",
+ DBG_OBJ_ENTER_O ("resize", 0, widget, "tablecell::correctAvailWidthOfChild",
"%p, %d, %s", child, width, forceValue ? "true" : "false");
// Make sure that this width does not exceed the width of the table
@@ -80,7 +80,7 @@ void correctCorrectedRequisitionOfChild (core::Widget *widget,
void (*splitHeightFun) (int, int*,
int*))
{
- DBG_OBJ_ENTER_O ("resize", 0, widget, "tablecell/correctRequisitionOfChild",
+ DBG_OBJ_ENTER_O ("resize", 0, widget, "tablecell::correctRequisitionOfChild",
"%p, %d * (%d + %d), ...", child, requisition->width,
requisition->ascent, requisition->descent);
diff --git a/dw/tablecell.hh b/dw/tablecell.hh
index 257f87c7..1300a944 100644
--- a/dw/tablecell.hh
+++ b/dw/tablecell.hh
@@ -31,6 +31,8 @@ int applyPerWidth (core::Widget *widget, int containerWidth,
int applyPerHeight (core::Widget *widget, int containerHeight,
core::style::Length perHeight);
+inline bool adjustExtraSpaceWhenCorrectingRequisitionByOOF () { return false; }
+
} // namespace dw
} // namespace dw
diff --git a/dw/textblock.cc b/dw/textblock.cc
index 21de1991..7dea2048 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -37,6 +37,7 @@ static dw::core::style::Tooltip *hoverTooltip = NULL;
using namespace lout;
+using namespace lout::misc;
using namespace lout::unicode;
namespace dw {
@@ -105,16 +106,6 @@ void Textblock::WordImgRenderer::draw (int x, int y, int width, int height)
}
-void Textblock::WordImgRenderer::print ()
-{
- printf ("%p: word #%d, ", this, wordNo);
- if (wordNo < textblock->words->size())
- textblock->printWordShort (textblock->words->getRef(wordNo));
- else
- printf ("<word %d does not exist>", wordNo);
- printf (", data set: %s", dataSet ? "yes" : "no");
-}
-
void Textblock::SpaceImgRenderer::getBgArea (int *x, int *y, int *width,
int *height)
{
@@ -128,16 +119,6 @@ core::style::Style *Textblock::SpaceImgRenderer::getStyle ()
return textblock->words->getRef(wordNo)->spaceStyle;
}
-void Textblock::SpaceImgRenderer::print ()
-{
- printf ("%p: word FOR SPACE #%d, ", this, wordNo);
- if (wordNo < textblock->words->size())
- textblock->printWordShort (textblock->words->getRef(wordNo));
- else
- printf ("<word %d does not exist>", wordNo);
- printf (", data set: %s", dataSet ? "yes" : "no");
-}
-
// ----------------------------------------------------------------------
Textblock::DivChar Textblock::divChars[NUM_DIV_CHARS] = {
@@ -227,7 +208,6 @@ Textblock::Textblock (bool limitTextWidth)
registerName ("dw::Textblock", &CLASS_ID);
setButtonSensitive(true);
- containingBlock = NULL;
hasListitemValue = false;
leftInnerPadding = 0;
line1Offset = 0;
@@ -238,6 +218,8 @@ Textblock::Textblock (bool limitTextWidth)
lastWordDrawn = -1;
DBG_OBJ_SET_NUM ("lastWordDrawn", lastWordDrawn);
+ DBG_OBJ_ASSOC_CHILD (&sizeRequestParams);
+
/*
* The initial sizes of lines and words should not be
* too high, since this will waste much memory with tables
@@ -252,7 +234,6 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
- outOfFlowMgr = NULL;
wrapRefLines = wrapRefParagraphs = -1;
@@ -267,9 +248,6 @@ Textblock::Textblock (bool limitTextWidth)
lineBreakWidth = -1;
DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
- verticalOffset = 0;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
-
this->limitTextWidth = limitTextWidth;
for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
@@ -278,15 +256,20 @@ Textblock::Textblock (bool limitTextWidth)
hlStart[layer].nChar = 0;
hlEnd[layer].index = 0;
hlEnd[layer].nChar = 0;
+
+ DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "index", hlStart[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "nChar", hlStart[layer].nChar);
+ DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "index", hlEnd[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "nChar", hlEnd[layer].nChar);
}
+ numSizeReferences = 0;
+
initNewLine ();
}
Textblock::~Textblock ()
{
- _MSG("Textblock::~Textblock\n");
-
/* make sure not to call a free'd tooltip (very fast overkill) */
hoverTooltip = NULL;
@@ -303,17 +286,7 @@ Textblock::~Textblock ()
delete lines;
delete words;
delete anchors;
-
- if(outOfFlowMgr) {
- // I feel more comfortable by letting the textblock delete these
- // widgets, instead of doing this in ~OutOfFlowMgr.
-
- for (int i = 0; i < outOfFlowMgr->getNumWidgets (); i++)
- delete outOfFlowMgr->getWidget (i);
-
- delete outOfFlowMgr;
- }
-
+
/* Make sure we don't own widgets anymore. Necessary before call of
parent class destructor. (???) */
words = NULL;
@@ -326,10 +299,13 @@ Textblock::~Textblock ()
* padding/border/margin. This can be used to align the first lines
* of several textblocks in a horizontal line.
*/
-void Textblock::sizeRequestImpl (core::Requisition *requisition)
+void Textblock::sizeRequestImpl (core::Requisition *requisition, int numPos,
+ Widget **references, int *x, int *y)
{
- DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl");
+ DBG_OBJ_ENTER ("resize", 0, "sizeRequestImpl", "%d, ...", numPos);
+ sizeRequestParams.fill (numPos, references, x, y);
+
int newLineBreakWidth = getAvailWidth (true);
if (newLineBreakWidth != lineBreakWidth) {
lineBreakWidth = newLineBreakWidth;
@@ -347,14 +323,15 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
// Note: the breakSpace of the last line is ignored, so breaks
// at the end of a textblock are not visible.
- requisition->width = lastLine->maxLineWidth + leftInnerPadding
- + getStyle()->boxDiffWidth ();
+ requisition->width =
+ lastLine->maxLineWidth + leftInnerPadding + boxDiffWidth ();
// Also regard collapsing of this widget top margin and the top
// margin of the first line box:
requisition->ascent = calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top
+ + extraSpace.top,
firstLine->borderAscent,
firstLine->marginAscent);
@@ -367,16 +344,14 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
// for this case is not necessary.)
calcVerticalBorder (getStyle()->padding.bottom,
getStyle()->borderWidth.bottom,
- getStyle()->margin.bottom,
+ getStyle()->margin.bottom + extraSpace.bottom,
lastLine->borderDescent, lastLine->marginDescent);
} else {
- requisition->width = leftInnerPadding + getStyle()->boxDiffWidth ();
- requisition->ascent = getStyle()->boxOffsetY ();
- requisition->descent = getStyle()->boxRestHeight ();;
+ requisition->width = leftInnerPadding + boxDiffWidth ();
+ requisition->ascent = boxOffsetY ();
+ requisition->descent = boxRestHeight ();
}
- requisition->ascent += verticalOffset;
-
if (mustBeWidenedToAvailWidth ()) {
DBG_OBJ_MSGF ("resize", 1,
"before considering lineBreakWidth (= %d): %d * (%d + %d)",
@@ -407,31 +382,23 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
// Is this really what we want? An alternative could be that
// OutOfFlowMgr::getSize honours CSS attributes an corrected sizes.
- DBG_OBJ_MSGF ("resize", 1, "before considering OOF widgets: %d * (%d + %d)",
- requisition->width, requisition->ascent, requisition->descent);
-
- if (outOfFlowMgr) {
- int oofWidth, oofHeight;
- outOfFlowMgr->getSize (requisition, &oofWidth, &oofHeight);
-
- // Floats must be within the *content* area, not the *margin*
- // area (which is equivalent to the requisition /
- // allocation). For this reason, boxRestWidth() and
- // boxRestHeight() must be considered.
-
- if (oofWidth + boxRestWidth () > requisition->width)
- requisition->width = oofWidth + boxRestWidth ();
- if (oofHeight + boxRestHeight ()
- > requisition->ascent + requisition->descent)
- requisition->descent =
- oofHeight + boxRestHeight () - requisition->ascent;
- }
+ correctRequisitionByOOF (requisition, core::splitHeightPreserveAscent);
DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)",
requisition->width, requisition->ascent, requisition->descent);
DBG_OBJ_LEAVE ();
}
+int Textblock::numSizeRequestReferences ()
+{
+ return numSizeReferences;
+}
+
+core::Widget *Textblock::sizeRequestReference (int index)
+{
+ return sizeReferences[index];
+}
+
int Textblock::calcVerticalBorder (int widgetPadding, int widgetBorder,
int widgetMargin, int lineBorderTotal,
int lineMarginTotal)
@@ -469,7 +436,7 @@ void Textblock::getWordExtremes (Word *word, core::Extremes *extremes)
word->size.width;
}
-void Textblock::getExtremesImpl (core::Extremes *extremes)
+void Textblock::getExtremesSimpl (core::Extremes *extremes)
{
DBG_OBJ_ENTER0 ("resize", 0, "getExtremesImpl");
@@ -515,7 +482,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
extremes->minWidth, extremes->minWidthIntrinsic,
extremes->maxWidth, extremes->maxWidthIntrinsic);
- int diff = leftInnerPadding + getStyle()->boxDiffWidth ();
+ int diff = leftInnerPadding + boxDiffWidth ();
extremes->minWidth += diff;
extremes->minWidthIntrinsic += diff;
extremes->maxWidth += diff;
@@ -534,22 +501,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
extremes->minWidth, extremes->minWidthIntrinsic,
extremes->maxWidth, extremes->maxWidthIntrinsic);
- if (outOfFlowMgr) {
- int oofMinWidth, oofMaxWidth;
- outOfFlowMgr->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
-
- DBG_OBJ_MSGF ("resize", 1, "OOFM correction: %d / %d",
- oofMinWidth, oofMaxWidth);
-
- extremes->minWidth = misc::max (extremes->minWidth, oofMinWidth);
- extremes->minWidthIntrinsic =
- misc::max (extremes->minWidthIntrinsic, oofMinWidth);
- extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth);
- extremes->maxWidthIntrinsic =
- misc::max (extremes->maxWidthIntrinsic, oofMinWidth);
- extremes->adjustmentWidth =
- misc::max (extremes->adjustmentWidth, oofMinWidth);
- }
+ correctExtremesByOOF (extremes);
DBG_OBJ_MSGF ("resize", 0,
"finally, after considering OOFM: %d (%d) / %d (%d)",
@@ -558,6 +510,46 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
DBG_OBJ_LEAVE ();
}
+int Textblock::numGetExtremesReferences ()
+{
+ return numSizeReferences;
+}
+
+core::Widget *Textblock::getExtremesReference (int index)
+{
+ return sizeReferences[index];
+}
+
+void Textblock::notifySetAsTopLevel ()
+{
+ OOFAwareWidget::notifySetAsTopLevel ();
+
+ numSizeReferences = 0;
+ DBG_OBJ_SET_NUM ("numSizeReferences", numSizeReferences);
+}
+
+void Textblock::notifySetParent ()
+{
+ OOFAwareWidget::notifySetParent ();
+
+ numSizeReferences = 0;
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (oofContainer[i] != this) {
+ // avoid dublicates
+ bool found = false;
+ for (int j = 0; !found && j < numSizeReferences; j++)
+ if (oofContainer[i] == oofContainer[i])
+ found = true;
+
+ if (!found)
+ sizeReferences[numSizeReferences++] = oofContainer[i];
+ }
+ }
+
+ DBG_OBJ_SET_NUM ("numSizeReferences", numSizeReferences);
+ for (int i = 0; i < numSizeReferences; i++)
+ DBG_OBJ_ARRSET_PTR ("sizeReferences", i, sizeReferences[i]);
+}
void Textblock::sizeAllocateImpl (core::Allocation *allocation)
{
@@ -601,10 +593,10 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
(lines->size () > 0 ?
calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top + extraSpace.top,
lines->getRef(0)->borderAscent,
lines->getRef(0)->marginAscent) :
- getStyle()->boxOffsetY ()) + verticalOffset);
+ boxOffsetY ()));
childBaseAllocation.descent =
allocation->ascent + allocation->descent - childBaseAllocation.ascent;
@@ -614,8 +606,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_SET_NUM ("childBaseAllocation.ascent", childBaseAllocation.ascent);
DBG_OBJ_SET_NUM ("childBaseAllocation.descent", childBaseAllocation.descent);
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->sizeAllocateStart (this, allocation);
+ sizeAllocateStart (allocation);
int lineIndex, wordIndex;
Line *line;
@@ -665,29 +656,21 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
"allocating widget in flow: line %d, word %d",
lineIndex, wordIndex);
- childAllocation.x = xCursor + childBaseAllocation.x;
-
- DBG_OBJ_MSGF ("resize", 1, "childAllocation.x = %d + %d = %d",
- xCursor, childBaseAllocation.x, childAllocation.x);
+ // TODO For word->flags & Word::TOPLEFT_OF_LINE, make
+ // allocation consistent with calcSizeOfWidgetInFlow():
+ childAllocation.x = xCursor + childBaseAllocation.x;
+
/** \todo Justification within the line is done here. */
-
/* align=top:
childAllocation.y = line->top + allocation->y;
*/
-
/* align=bottom (base line) */
/* Commented lines break the n2 and n3 test cases at
* http://www.dillo.org/test/img/ */
childAllocation.y = lineYOffsetCanvas (line)
+ (line->borderAscent - word->size.ascent);
- DBG_OBJ_MSGF ("resize", 1,
- "childAllocation.y = %d + (%d - %d) = %d",
- lineYOffsetCanvas (line),
- line->borderAscent, word->size.ascent,
- childAllocation.y);
-
childAllocation.width = word->size.width;
childAllocation.ascent = word->size.ascent;
childAllocation.descent = word->size.descent;
@@ -755,9 +738,8 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_MSG_END ();
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->sizeAllocateEnd (this);
-
+ sizeAllocateEnd ();
+
for (int i = 0; i < anchors->size(); i++) {
Anchor *anchor = anchors->getRef(i);
int y;
@@ -777,32 +759,52 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_LEAVE ();
}
+void Textblock::calcExtraSpaceImpl ()
+{
+ OOFAwareWidget::calcExtraSpaceImpl ();
+
+ int clearPosition = 0;
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (searchOutOfFlowMgr (i))
+ clearPosition =
+ misc::max (clearPosition,
+ searchOutOfFlowMgr(i)->getClearPosition (this));
+
+ extraSpace.top = misc::max (extraSpace.top, clearPosition);
+}
+
int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
{
- DBG_OBJ_ENTER ("resize", 0, "Textblock/getAvailWidthOfChild", "%p, %s",
+ DBG_OBJ_ENTER ("resize", 0, "Textblock::getAvailWidthOfChild", "%p, %s",
child, forceValue ? "true" : "false");
int width;
- if (child->getStyle()->width == core::style::LENGTH_AUTO) {
- // No width specified: similar to standard implementation (see
- // there), but "leftInnerPadding" has to be considered, too.
- DBG_OBJ_MSG ("resize", 1, "no specification");
- if (forceValue)
- width = misc::max (getAvailWidth (true) - boxDiffWidth ()
- - leftInnerPadding,
- 0);
- else
- width = -1;
- } else
- width = Widget::getAvailWidthOfChild (child, forceValue);
-
- if (forceValue && this == child->getContainer () &&
- !mustBeWidenedToAvailWidth ()) {
- core::Extremes extremes;
- getExtremes (&extremes);
- if (width > extremes.maxWidth - boxDiffWidth () - leftInnerPadding)
- width = extremes.maxWidth - boxDiffWidth () - leftInnerPadding;
+ if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ width =
+ getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
+ else {
+ if (child->getStyle()->width == core::style::LENGTH_AUTO) {
+ // No width specified: similar to standard implementation (see
+ // there), but "leftInnerPadding" has to be considered, too.
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ if (forceValue)
+ width = misc::max (getAvailWidth (true) - boxDiffWidth ()
+ - leftInnerPadding,
+ 0);
+ else
+ width = -1;
+ } else
+ width = Widget::getAvailWidthOfChild (child, forceValue);
+
+ if (forceValue && this == child->getContainer () &&
+ !mustBeWidenedToAvailWidth ()) {
+ core::Extremes extremes;
+ getExtremes (&extremes);
+ if (width > extremes.maxWidth - boxDiffWidth () - leftInnerPadding)
+ width = extremes.maxWidth - boxDiffWidth () - leftInnerPadding;
+ }
}
DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
@@ -810,7 +812,15 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
return width;
}
-
+int Textblock::getAvailHeightOfChild (core::Widget *child, bool forceValue)
+{
+ if (isWidgetOOF(child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child,
+ forceValue);
+ else
+ return Widget::getAvailHeightOfChild (child, forceValue);
+}
void Textblock::containerSizeChangedForChildren ()
{
@@ -822,9 +832,8 @@ void Textblock::containerSizeChangedForChildren ()
word->content.widget->containerSizeChanged ();
}
- if (outOfFlowMgr)
- outOfFlowMgr->containerSizeChangedForChildren ();
-
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -833,7 +842,7 @@ bool Textblock::affectsSizeChangeContainerChild (Widget *child)
DBG_OBJ_ENTER ("resize", 0,
"Textblock/affectsSizeChangeContainerChild", "%p", child);
- // See Textblock::getAvailWidthForChild() and Textblock::oofSizeChanged():
+ // See Textblock::getAvailWidthOfChild() and Textblock::oofSizeChanged():
// Extremes changes affect the size of the child, too:
bool ret;
if (!mustBeWidenedToAvailWidth () &&
@@ -876,13 +885,10 @@ void Textblock::markSizeChange (int ref)
{
DBG_OBJ_ENTER ("resize", 0, "markSizeChange", "%d", ref);
- if (OutOfFlowMgr::isRefOutOfFlow (ref)) {
- assert (outOfFlowMgr != NULL);
- outOfFlowMgr->markSizeChange (ref);
- } else {
- PRINTF ("[%p] MARK_SIZE_CHANGE (%d): %d => ...\n",
- this, ref, wrapRefLines);
-
+ if (isParentRefOOF (ref))
+ getParentRefOutOfFlowMgr(ref)
+ ->markSizeChange (getParentRefOOFSubRef (ref));
+ else {
/* By the way: ref == -1 may have two different causes: (i) flush()
calls "queueResize (-1, true)", when no rewrapping is necessary;
and (ii) a word may have parentRef == -1 , when it is not yet
@@ -890,10 +896,10 @@ void Textblock::markSizeChange (int ref)
now, but addLine(...) will do everything necessary. */
if (ref != -1) {
if (wrapRefLines == -1)
- wrapRefLines = OutOfFlowMgr::getLineNoFromRef (ref);
+ wrapRefLines = getParentRefInFlowSubRef (ref);
else
wrapRefLines = misc::min (wrapRefLines,
- OutOfFlowMgr::getLineNoFromRef (ref));
+ getParentRefInFlowSubRef (ref));
}
DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
@@ -913,13 +919,10 @@ void Textblock::markExtremesChange (int ref)
{
DBG_OBJ_ENTER ("resize", 1, "markExtremesChange", "%d", ref);
- if (OutOfFlowMgr::isRefOutOfFlow (ref)) {
- assert (outOfFlowMgr != NULL);
- outOfFlowMgr->markExtremesChange (ref);
- } else {
- PRINTF ("[%p] MARK_EXTREMES_CHANGE (%d): %d => ...\n",
- this, ref, wrapRefParagraphs);
-
+ if (isParentRefOOF (ref))
+ getParentRefOutOfFlowMgr(ref)
+ ->markExtremesChange (getParentRefOOFSubRef (ref));
+ else {
/* By the way: ref == -1 may have two different causes: (i) flush()
calls "queueResize (-1, true)", when no rewrapping is necessary;
and (ii) a word may have parentRef == -1 , when it is not yet
@@ -927,11 +930,10 @@ void Textblock::markExtremesChange (int ref)
now, but addLine(...) will do everything necessary. */
if (ref != -1) {
if (wrapRefParagraphs == -1)
- wrapRefParagraphs = OutOfFlowMgr::getLineNoFromRef (ref);
+ wrapRefParagraphs = getParentRefInFlowSubRef (ref);
else
wrapRefParagraphs =
- misc::min (wrapRefParagraphs,
- OutOfFlowMgr::getLineNoFromRef (ref));
+ misc::min (wrapRefParagraphs, getParentRefInFlowSubRef (ref));
}
DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
@@ -940,61 +942,6 @@ void Textblock::markExtremesChange (int ref)
DBG_OBJ_LEAVE ();
}
-void Textblock::notifySetAsTopLevel()
-{
- PRINTF ("%p becomes toplevel\n", this);
- containingBlock = this;
- PRINTF ("-> %p is its own containing block\n", this);
-}
-
-bool Textblock::isContainingBlock (Widget *widget)
-{
- return
- // Of course, only textblocks are considered as containing
- // blocks.
- widget->instanceOf (Textblock::CLASS_ID) &&
- // The second condition: that this block is "out of flow", in a
- // wider sense.
- (// The toplevel widget is "out of flow", since there is no
- // parent, and so no context.
- widget->getParent() == NULL ||
- // A similar reasoning applies to a widget with another parent
- // than a textblock (typical example: a table cell (this is
- // also a text block) within a table widget).
- !widget->getParent()->instanceOf (Textblock::CLASS_ID) ||
- // Inline blocks are containing blocks, too.
- widget->getStyle()->display == core::style::DISPLAY_INLINE_BLOCK ||
- // Same for blocks with 'overview' set to another value than
- // (the default value) 'visible'.
- widget->getStyle()->overflow != core::style::OVERFLOW_VISIBLE ||
- // Finally, "out of flow" in a narrower sense: floats and
- // absolute positions.
- OutOfFlowMgr::isWidgetOutOfFlow (widget));
-}
-
-void Textblock::notifySetParent ()
-{
- PRINTF ("%p becomes a child of %p\n", this, getParent());
-
- // Search for containing Box.
- containingBlock = NULL;
-
- for (Widget *widget = this; widget != NULL && containingBlock == NULL;
- widget = widget->getParent())
- if (isContainingBlock (widget)) {
- containingBlock = (Textblock*)widget;
-
- if (containingBlock == this) {
- PRINTF ("-> %p is its own containing block\n", this);
- } else {
- PRINTF ("-> %p becomes containing block of %p\n",
- containingBlock, this);
- }
- }
-
- assert (containingBlock != NULL);
-}
-
bool Textblock::isBlockLevel ()
{
return true;
@@ -1084,6 +1031,8 @@ void Textblock::leaveNotifyImpl (core::EventCrossing *event)
bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
core::MousePositionEvent *event)
{
+ DBG_OBJ_ENTER0 ("events", 0, "sendSelectionEvent");
+
core::Iterator *it;
int wordIndex;
int charPos = 0, link = -1;
@@ -1213,11 +1162,17 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
}
}
}
-
- it = new TextblockIterator (this, core::Content::maskForSelection (true),
- false, wordIndex);
+
+ DBG_OBJ_MSGF ("events", 1, "wordIndex = %d", wordIndex);
+ DBG_MSG_WORD ("events", 1, "<i>this is:</i> ", wordIndex, "");
+
+ it = TextblockIterator::createWordIndexIterator
+ (this, core::Content::maskForSelection (true), wordIndex);
r = selectionHandleEvent (eventType, it, charPos, link, event);
it->unref ();
+
+ DBG_OBJ_MSGF ("events", 1, "=> %s", r ? "true" : "false");
+ DBG_OBJ_LEAVE ();
return r;
}
@@ -1234,9 +1189,9 @@ core::Iterator *Textblock::iterator (core::Content::Type mask, bool atEnd)
/*
* Draw the decorations on a word.
*/
-void Textblock::decorateText(core::View *view, core::style::Style *style,
- core::style::Color::Shading shading,
- int x, int yBase, int width)
+void Textblock::decorateText (core::View *view, core::style::Style *style,
+ core::style::Color::Shading shading,
+ int x, int yBase, int width)
{
int y, height;
@@ -1538,24 +1493,29 @@ void Textblock::drawSpace(int wordIndex, core::View *view,
* - area is used always (ev. set it to event->area)
* - event is only used when is_expose
*/
-void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
+void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area,
+ core::DrawingContext *context)
{
- DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., %d, %d, %d * %d",
+ DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., [%d, %d, %d * %d]",
area->x, area->y, area->width, area->height);
-
+
int xWidget = line->textOffset;
int yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)",
line->firstWord, line->lastWord, words->size (),
xWidget, yWidgetBase);
- DBG_MSG_WORD ("draw", 0, "<i>line starts with: </i>", line->firstWord, "");
- DBG_MSG_WORD ("draw", 0, "<i>line ends with: </i>", line->lastWord, "");
+ DBG_MSG_WORD ("draw", 1, "<i>line starts with: </i>", line->firstWord, "");
+ DBG_MSG_WORD ("draw", 1, "<i>line ends with: </i>", line->lastWord, "");
+
+ DBG_OBJ_MSG_START ();
for (int wordIndex = line->firstWord;
wordIndex <= line->lastWord && xWidget < area->x + area->width;
wordIndex++) {
- Word *word = words->getRef(wordIndex);
+ DBG_MSG_WORD ("draw", 2, "<i>drawing: </i>", wordIndex, "");
+
+ Word *word = words->getRef (wordIndex);
int wordSize = word->size.width;
if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) {
@@ -1566,9 +1526,10 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
if (word->content.type == core::Content::WIDGET_IN_FLOW) {
core::Widget *child = word->content.widget;
core::Rectangle childArea;
-
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child) &&
+ child->intersects (this, area, &childArea))
+ child->draw (view, &childArea, context);
} else {
int wordIndex2 = wordIndex;
while (wordIndex2 < line->lastWord &&
@@ -1596,8 +1557,8 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
xWidget + wordSize,
yWidgetBase - line->borderAscent, word->effSpace,
line->borderAscent + line->borderDescent, false);
- drawSpace(wordIndex, view, area, xWidget + wordSize,
- yWidgetBase);
+ drawSpace (wordIndex, view, area, xWidget + wordSize,
+ yWidgetBase);
}
}
@@ -1605,6 +1566,8 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
xWidget += wordSize + word->effSpace;
}
+ DBG_OBJ_MSG_END ();
+
DBG_OBJ_LEAVE ();
}
@@ -1626,7 +1589,8 @@ int Textblock::findLineIndexWhenNotAllocated (int y)
return
findLineIndex (y, calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top
+ + extraSpace.top,
lines->getRef(0)->borderAscent,
lines->getRef(0)->marginAscent));
}
@@ -1772,38 +1736,45 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
return NULL;
}
-void Textblock::draw (core::View *view, core::Rectangle *area)
+void Textblock::drawLevel (core::View *view, core::Rectangle *area,
+ int level, core::DrawingContext *context)
{
- DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
- area->x, area->y, area->width, area->height);
+ DBG_OBJ_ENTER ("draw", 0, "Textblock::drawLevel", "(%d, %d, %d * %d), %s",
+ area->x, area->y, area->width, area->height,
+ stackingLevelText (level));
- int lineIndex;
- Line *line;
-
- // Instead of drawWidgetBox, use drawBox to include verticalOffset.
- if (getParent() == NULL) {
- // The toplevel (parent == NULL) widget is a special case, which
- // we leave to drawWidgetBox; verticalOffset will here always 0.
- assert (verticalOffset == 0);
- drawWidgetBox (view, area, false);
- } else
- drawBox (view, getStyle(), area, 0, verticalOffset, allocation.width,
- getHeight() - verticalOffset, false);
+ switch (level) {
+ case SL_IN_FLOW:
+ for (int lineIndex = findLineIndexWhenAllocated (area->y);
+ lineIndex < lines->size (); lineIndex++) {
+ Line *line = lines->getRef (lineIndex);
+ if (lineYOffsetWidget (line) >= area->y + area->height)
+ break;
- lineIndex = findLineIndexWhenAllocated (area->y);
+ DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
+ drawLine (line, view, area, context);
+ }
+ break;
- for (; lineIndex < lines->size (); lineIndex++) {
- line = lines->getRef (lineIndex);
- if (lineYOffsetWidget (line) >= area->y + area->height)
- break;
+ case SL_OOF_REF:
+ // TODO Inefficient. Perhaps store OOF references in seperate
+ // (much smaller!) list.
+ for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
+ for (int wordIndex = 0; wordIndex < words->size (); wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ getOOFMIndex (word->content.widget) == oofmIndex &&
+ doesWidgetOOFInterruptDrawing (word->content.widget))
+ word->content.widget->drawInterruption (view, area, context);
+ }
+ }
+ break;
- DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
- drawLine (line, view, area);
+ default:
+ OOFAwareWidget::drawLevel (view, area, level, context);
+ break;
}
- if(outOfFlowMgr)
- outOfFlowMgr->draw(view, area);
-
DBG_OBJ_LEAVE ();
}
@@ -1914,6 +1885,7 @@ void Textblock::fillWord (int wordNo, int width, int ascent, int descent,
word->size.width = width;
word->size.ascent = ascent;
word->size.descent = descent;
+ DBG_SET_WORD_SIZE (wordNo);
word->origSpace = word->effSpace = 0;
word->hyphenWidth = 0;
word->badnessAndPenalty.setPenalty (PENALTY_PROHIBIT_BREAK);
@@ -2304,15 +2276,73 @@ void Textblock::calcTextSizes (const char *text, size_t textLen,
}
/**
+ * Calculate the size of a widget, and return whether it has to be
+ * positioned at the top of the line.
+ */
+bool Textblock::calcSizeOfWidgetInFlow (int wordIndex, Widget *widget,
+ core::Requisition *size)
+{
+ DBG_OBJ_ENTER ("resize", 0, "calcSizeOfWidgetInFlow", "%d, %p, ...",
+ wordIndex, widget);
+
+ bool result;
+
+ if ((wordIndex == 0 ||
+ words->getRef(wordIndex - 1)->content.type == core::Content::BREAK) &&
+ (widget->getStyle()->display == core::style::DISPLAY_BLOCK ||
+ widget->getStyle()->display == core::style::DISPLAY_LIST_ITEM ||
+ widget->getStyle()->display == core::style::DISPLAY_TABLE)) {
+ // pass positions
+ int lastWord = lines->empty () ? -1 : lines->getLastRef()->lastWord;
+ assert (wordIndex > lastWord);
+
+ int xRel = boxOffsetX () + leftInnerPadding
+ + (lines->size () == 0 ? line1OffsetEff : 0);
+ int lastMargin, yLine = yOffsetOfLineToBeCreated (&lastMargin);
+ int yRel = yLine - lastMargin
+ + max (lastMargin, widget->getStyle()->margin.top);
+
+ core::SizeParams childParams;
+ DBG_OBJ_ASSOC_CHILD (&childParams);
+
+ sizeRequestParams.forChild (this, widget, xRel, yRel, &childParams);
+ widget->sizeRequest (size, childParams.getNumPos (),
+ childParams.getReferences (), childParams.getX (),
+ childParams.getY ());
+
+ result = true;
+ } else {
+ // do not pass positions (inline elements etc)
+ widget->sizeRequest (size);
+ result = false;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%s", boolToStr (result));
+ return result;
+}
+
+bool Textblock::findSizeRequestReference (Widget *reference, int *xRef,
+ int *yRef)
+{
+ if (reference == this) {
+ if (xRef)
+ *xRef = 0;
+ if (yRef)
+ *yRef = 0;
+ return true;
+ } else
+ return sizeRequestParams.findReference (reference, xRef, yRef);
+}
+
+/**
* Add a word (without hyphens) to the page structure.
*/
void Textblock::addText0 (const char *text, size_t len, short flags,
core::style::Style *style, core::Requisition *size)
{
DBG_OBJ_ENTER ("construct.word", 0, "addText0",
- "..., %d, %s:%s:%s:%s:%s:%s:%s, %p, %d * (%d + %d)",
+ "..., %d, %s:%s:%s:%s:%s:%s:%s:%s, %p, %d * (%d + %d)",
(int)len,
- // Ugly copy&paste from printWordFlags:
(flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--",
(flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--",
(flags & Word::PERM_DIV_CHAR) ? "dp" : "--",
@@ -2320,6 +2350,7 @@ void Textblock::addText0 (const char *text, size_t len, short flags,
(flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--",
(flags & Word::WORD_START) ? "st" : "--",
(flags & Word::WORD_END) ? "en" : "--",
+ (flags & Word::TOPLEFT_OF_LINE) ? "00" : "--",
style, size->width, size->ascent, size->descent);
//printf("[%p] addText0 ('", this);
@@ -2364,22 +2395,26 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
widget->setStyle (style);
- PRINTF ("adding the %s %p to %p (word %d) ...\n",
- widget->getClassName(), widget, this, words->size());
-
- if (containingBlock->outOfFlowMgr == NULL) {
- containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock);
- DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr);
- }
+ initOutOfFlowMgrs ();
- if (OutOfFlowMgr::isWidgetOutOfFlow (widget)) {
- PRINTF (" -> out of flow.\n");
+ if (testWidgetOutOfFlow (widget)) {
+ int oofmIndex = getOOFMIndex (widget);
+ DBG_OBJ_MSGF ("construct.word", 1, "ouf of flow: oofmIndex = %d (%s)",
+ oofmIndex, OOFM_NAME[oofmIndex]);
- widget->setParent (containingBlock);
+ widget->setParent (oofContainer[oofmIndex]);
widget->setGenerator (this);
- containingBlock->outOfFlowMgr->addWidgetOOF (widget, this,
- words->size ());
- Word *word = addWord (0, 0, 0, 0, style);
+
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ int oofmSubRef = oofm->addWidgetOOF (widget, this, words->size ());
+ widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef);
+
+ DBG_OBJ_MSGF ("construct.word", 1, "oofmSubRef = %d => parentRef = %d",
+ oofmSubRef, widget->parentRef);
+
+ core::Requisition size;
+ oofm->calcWidgetRefSize (widget, &size);
+ Word *word = addWord (size.width, size.ascent, size.descent, 0, style);
word->content.type = core::Content::WIDGET_OOF_REF;
word->content.widget = widget;
@@ -2387,18 +2422,22 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
// problems with breaking near float definitions.)
setBreakOption (word, style, 0, 0, false);
} else {
- PRINTF (" -> within flow.\n");
+ DBG_OBJ_MSG ("construct.word", 1, "in flow");
widget->setParent (this);
// TODO Replace (perhaps) later "textblock" by "OOF aware widget".
- if (widget->instanceOf (Textblock::CLASS_ID))
- containingBlock->outOfFlowMgr->addWidgetInFlow ((Textblock*)widget,
- this, words->size ());
+ if (widget->instanceOf (Textblock::CLASS_ID)) {
+ for (int i = 0; i < NUM_OOFM; i++)
+ searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this,
+ words->size ());
+ }
core::Requisition size;
- widget->sizeRequest (&size);
- Word *word = addWord (size.width, size.ascent, size.descent, 0, style);
+ short flags = calcSizeOfWidgetInFlow (words->size (), widget, &size) ?
+ Word::TOPLEFT_OF_LINE : 0;
+ Word *word =
+ addWord (size.width, size.ascent, size.descent, flags, style);
word->content.type = core::Content::WIDGET_IN_FLOW;
word->content.widget = widget;
}
@@ -2632,7 +2671,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
for (Widget *widget = this;
widget->getParent() != NULL &&
widget->getParent()->instanceOf (Textblock::CLASS_ID) &&
- !OutOfFlowMgr::isRefOutOfFlow (widget->parentRef);
+ !isWidgetOOF (widget);
widget = widget->getParent ()) {
Textblock *textblock2 = (Textblock*)widget->getParent ();
int index = textblock2->hasListitemValue ? 1 : 0;
@@ -2643,7 +2682,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
if (!isfirst) {
/* The text block we searched for has been found. */
Word *word2;
- int lineno = OutOfFlowMgr::getLineNoFromRef (widget->parentRef);
+ int lineno = getWidgetInFlowSubRef (widget);
if (lineno > 0 &&
(word2 =
@@ -2652,8 +2691,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
word2->content.type == core::Content::BREAK) {
if (word2->content.breakSpace < space) {
word2->content.breakSpace = space;
- textblock2->queueResize
- (OutOfFlowMgr::createRefNormalFlow (lineno), false);
+ textblock2->queueResize (makeParentRefInFlow (lineno), false);
textblock2->mustQueueResize = false;
}
}
@@ -2752,63 +2790,66 @@ void Textblock::breakAdded ()
words->getRef(words->size () - 2)->effSpace = 0;
}
-/**
- * \brief Search recursively through widget.
- *
- * This is an optimized version of the general
- * dw::core::Widget::getWidgetAtPoint method.
- */
-core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
-{
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
- int lineIndex, wordIndex;
- Line *line;
-
- if (x < allocation.x ||
- y < allocation.y ||
- x > allocation.x + allocation.width ||
- y > allocation.y + getHeight ()) {
- return NULL;
- }
-
- // First, search for widgets out of flow, notably floats, since
- // there are cases where they overlap child textblocks. Should
- // later be refined using z-index.
- Widget *oofWidget =
- outOfFlowMgr ? outOfFlowMgr->getWidgetAtPoint (x, y, level) : NULL;
- if (oofWidget)
- return oofWidget;
-
- lineIndex = findLineIndexWhenAllocated (y - allocation.y);
-
- if (lineIndex < 0 || lineIndex >= lines->size ()) {
- return this;
- }
-
- line = lines->getRef (lineIndex);
-
- for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
- Word *word = words->getRef (wordIndex);
-
- if (word->content.type == core::Content::WIDGET_IN_FLOW) {
- core::Widget * childAtPoint;
- if (word->content.widget->wasAllocated ()) {
- childAtPoint = word->content.widget->getWidgetAtPoint (x, y,
- level + 1);
- if (childAtPoint) {
- return childAtPoint;
+core::Widget *Textblock::getWidgetAtPointLevel (int x, int y, int level,
+ core::GettingWidgetAtPointContext
+ *context)
+{
+ DBG_OBJ_ENTER ("events", 0, "Textblock::getWidgetAtPointLevel", "%d, %d, %s",
+ x, y, stackingLevelText (level));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (level) {
+ case SL_IN_FLOW:
+ {
+ int lineIndex = findLineIndexWhenAllocated (y - allocation.y);
+
+ if (lineIndex >= 0 && lineIndex < lines->size ()) {
+ Line *line = lines->getRef (lineIndex);
+
+ for (int wordIndex = line->lastWord;
+ widgetAtPoint == NULL && wordIndex >= line->firstWord;
+ wordIndex--) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_IN_FLOW &&
+ !core::StackingContextMgr::handledByStackingContextMgr
+ (word->content.widget))
+ widgetAtPoint =
+ word->content.widget->getWidgetAtPoint (x, y, context);
}
}
}
+ break;
+
+ case SL_OOF_REF:
+ // TODO Inefficient. Perhaps store OOF references in seperate
+ // (much smaller!) list.
+ for (int oofmIndex = NUM_OOFM; widgetAtPoint == NULL && oofmIndex >= 0;
+ oofmIndex--) {
+ for (int wordIndex = words->size () - 1;
+ widgetAtPoint == NULL && wordIndex >= 0; wordIndex--) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ getOOFMIndex (word->content.widget) == oofmIndex &&
+ doesWidgetOOFInterruptDrawing (word->content.widget))
+ widgetAtPoint =
+ word->content.widget->getWidgetAtPointInterrupted (x, y,
+ context);
+ }
+ }
+ break;
+
+ default:
+ widgetAtPoint =
+ OOFAwareWidget::getWidgetAtPointLevel (x, y, level, context);
+ break;
}
- return this;
+ DBG_OBJ_MSGF ("events", 1, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
}
-
/**
* This function "hands" the last break of a page "over" to a parent
* page. This is used for "collapsing spaces".
@@ -2909,6 +2950,8 @@ void Textblock::changeWordStyle (int from, int to, core::style::Style *style,
void Textblock::queueDrawRange (int index1, int index2)
{
+ DBG_OBJ_ENTER ("draw", 0, "queueDrawRange", "%d, %d", index1, index2);
+
int from = misc::min (index1, index2);
int to = misc::max (index1, index2);
@@ -2930,18 +2973,6 @@ void Textblock::queueDrawRange (int index1, int index2)
queueDrawArea (0, y, allocation.width, h);
}
-}
-
-void Textblock::setVerticalOffset (int verticalOffset)
-{
- DBG_OBJ_ENTER ("resize", 0, "setVerticalOffset", "%d", verticalOffset);
-
- if (this->verticalOffset != verticalOffset) {
- this->verticalOffset = verticalOffset;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
- mustQueueResize = true;
- queueDraw (); // Could perhaps be optimized.
- }
DBG_OBJ_LEAVE ();
}
@@ -2951,18 +2982,24 @@ bool Textblock::mustBeWidenedToAvailWidth ()
DBG_OBJ_ENTER0 ("resize", 0, "mustBeWidenedToAvailWidth");
bool toplevel = getParent () == NULL,
block = getStyle()->display == core::style::DISPLAY_BLOCK,
- vloat = getStyle()->vloat != core::style::FLOAT_NONE,
- result = toplevel || (block && !vloat);
+ vloat = testWidgetFloat (this),
+ abspos = testWidgetAbsolutelyPositioned (this),
+ fixpos = testWidgetFixedlyPositioned (this),
+ // In detail, this depends on what the respective OOFM does
+ // with the child widget:
+ result = toplevel || (block && !(vloat || abspos || fixpos));
DBG_OBJ_MSGF ("resize", 0,
- "=> %s (toplevel: %s, block: %s, float: %s)",
+ "=> %s (toplevel: %s, block: %s, float: %s, abspos: %s, "
+ "fixpos: %s)",
result ? "true" : "false", toplevel ? "true" : "false",
- block ? "true" : "false", vloat ? "true" : "false");
+ block ? "true" : "false", vloat ? "true" : "false",
+ abspos ? "true" : "false", fixpos ? "true" : "false");
DBG_OBJ_LEAVE ();
return result;
}
/**
- * Called by dw::OutOfFlowMgr when the border has changed due to a
+ * Called by dw::OOFFloatsMgr when the border has changed due to a
* float (or some floats).
*
* "y", which given in widget coordinates, denotes the minimal
@@ -3091,7 +3128,7 @@ void Textblock::borderChanged (int y, Widget *vloat)
minWrapLineIndex, maxWrapLineIndex,
vloat->getGenerator() == this ? "yes" : "no");
- queueResize (OutOfFlowMgr::createRefNormalFlow (realWrapLineIndex), true);
+ queueResize (makeParentRefInFlow (realWrapLineIndex), true);
// Notice that the line no. realWrapLineIndex may not exist yet.
if (realWrapLineIndex == 0)
@@ -3112,6 +3149,13 @@ void Textblock::borderChanged (int y, Widget *vloat)
DBG_OBJ_LEAVE ();
}
+void Textblock::widgetRefSizeChanged (int externalIndex)
+{
+ int lineNo = findLineOfWord (externalIndex);
+ if (lineNo >= 0 && lineNo < lines->size ())
+ queueResize (makeParentRefInFlow (lineNo), true);
+}
+
void Textblock::clearPositionChanged ()
{
DBG_OBJ_ENTER0 ("resize", 0, "clearPositionChanged");
@@ -3127,7 +3171,7 @@ void Textblock::oofSizeChanged (bool extremesChanged)
extremesChanged ? "true" : "false");
queueResize (-1, extremesChanged);
- // See Textblock::getAvailWidthForChild(): Extremes changes may become also
+ // See Textblock::getAvailWidthOfChild(): Extremes changes may become also
// relevant for the children, under certain conditions:
if (extremesChanged && !mustBeWidenedToAvailWidth ())
containerSizeChanged ();
@@ -3135,6 +3179,21 @@ void Textblock::oofSizeChanged (bool extremesChanged)
DBG_OBJ_LEAVE ();
}
+int Textblock::getLineBreakWidth ()
+{
+ return lineBreakWidth;
+}
+
+bool Textblock::isPossibleContainer (int oofmIndex)
+{
+ return true;
+}
+
+bool Textblock::isPossibleContainerParent (int oofmIndex)
+{
+ return true;
+}
+
RegardingBorder *Textblock::getWidgetRegardingBorderForLine (Line *line)
{
return getWidgetRegardingBorderForLine (line->firstWord, line->lastWord);
@@ -3168,16 +3227,10 @@ RegardingBorder *Textblock::getWidgetRegardingBorderForLine (int firstWord,
if (word->content.type == core::Content::WIDGET_IN_FLOW) {
Widget *widget = word->content.widget;
if (widget->instanceOf (RegardingBorder::CLASS_ID) &&
- // Exclude some cases where a widget constitutes a new
- // container (see definition of float container in
- // Textblock::isContainingBlock).
- widget->getStyle()->display != core::style::DISPLAY_INLINE_BLOCK &&
- widget->getStyle()->overflow == core::style::OVERFLOW_VISIBLE)
+ // Exclude cases where a textblock constitutes a new floats
+ // container.
+ !isOOFContainer (widget, OOFM_FLOATS))
widgetRegardingBorder = (RegardingBorder*)widget;
-
- // (TODO: It would look nicer if there is one common place
- // for such definitions. Will be fixed in "dillo_grows", not
- // here.)
}
}
@@ -3189,7 +3242,7 @@ RegardingBorder *Textblock::getWidgetRegardingBorderForLine (int firstWord,
/**
* Includes margin, border, and padding.
*/
-int Textblock::yOffsetOfLineToBeCreated ()
+int Textblock::yOffsetOfLineToBeCreated (int *lastMargin)
{
// This method does not return an exact result: the position of the
// new line, which does not yet exist, cannot be calculated, since
@@ -3209,24 +3262,51 @@ int Textblock::yOffsetOfLineToBeCreated ()
int result;
if (lines->size () == 0) {
- result = verticalOffset + calcVerticalBorder (getStyle()->padding.top,
- getStyle()->borderWidth.top,
- getStyle()->margin.top,
- 0, 0);
- DBG_OBJ_MSGF ("line.yoffset", 1, "first line: ... = %d", result);
+ result = calcVerticalBorder (getStyle()->padding.top,
+ getStyle()->borderWidth.top + extraSpace.top,
+ getStyle()->margin.top, 0, 0);
+ if (lastMargin)
+ *lastMargin = getStyle()->margin.top;
} else {
Line *firstLine = lines->getRef (0), *lastLine = lines->getLastRef ();
- result = verticalOffset + calcVerticalBorder (getStyle()->padding.top,
- getStyle()->borderWidth.top,
- getStyle()->margin.top,
- firstLine->borderAscent,
- firstLine->marginAscent)
+ result = calcVerticalBorder (getStyle()->padding.top,
+ getStyle()->borderWidth.top,
+ getStyle()->margin.top + extraSpace.top,
+ firstLine->borderAscent,
+ firstLine->marginAscent)
- firstLine->borderAscent + lastLine->top + lastLine->totalHeight (0);
- DBG_OBJ_MSGF ("line.yoffset", 1, "other line: ... = %d", result);
+ if (lastMargin)
+ *lastMargin = lastLine->marginDescent - lastLine->borderDescent;
}
- DBG_OBJ_LEAVE ();
+ if (lastMargin)
+ DBG_OBJ_LEAVE_VAL ("%d, %d", result, *lastMargin);
+ else
+ DBG_OBJ_LEAVE_VAL ("%d", result);
+
+ return result;
+}
+
+/**
+ * Includes margin, border, and padding. Can be used without allocation.
+ */
+int Textblock::yOffsetOfLineCreated (Line *line)
+{
+ // Similar applies (regarding exactness) as to yOffsetOfLineToBeCreated.
+
+ DBG_OBJ_ENTER0 ("line.yoffset", 0, "yOffsetOfLineToBeCreated");
+
+ int result;
+
+ Line *firstLine = lines->getRef (0);
+ result = calcVerticalBorder (getStyle()->padding.top,
+ getStyle()->borderWidth.top,
+ getStyle()->margin.top + extraSpace.top,
+ firstLine->borderAscent,
+ firstLine->marginAscent)
+ - firstLine->borderAscent + line->top;
+ DBG_OBJ_LEAVE_VAL ("%d", result);
return result;
}
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 162088dc..ddab6bca 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -4,7 +4,7 @@
#include <limits.h>
#include "regardingborder.hh"
-#include "outofflowmgr.hh"
+#include "tools.hh"
#include "../lout/misc.hh"
// These were used when improved line breaking and hyphenation were implemented.
@@ -24,10 +24,9 @@ namespace dw {
*
* <div style="border: 2px solid #ffff00; margin-top: 0.5em;
* margin-bottom: 0.5em; padding: 0.5em 1em; background-color:
- * #ffffe0"><b>Info:</b> The recent changes (line breaking and
- * hyphenation on one hand, floats on the other hand) have not yet
- * been incorporated into this documentation. See \ref
- * dw-line-breaking and \ref dw-out-of-flow.</div>
+ * #ffffe0"><b>Info:</b> Some (not so) recent changes, line breaking
+ * and hyphenation, have not yet been incorporated into this
+ * documentation. See \ref dw-line-breaking.</div>
*
* <h3>Signals</h3>
*
@@ -164,11 +163,11 @@ namespace dw {
* Anchors associate the anchor name with the index of the next word at
* the point of the anchor.
*
- * <h4>Incremental Resizing</h4>
+ * <h3>Incremental Resizing</h3>
*
* dw::Textblock makes use of incremental resizing as described in \ref
* dw-widget-sizes. The parentRef is, for children of a dw::Textblock, simply
- * the number of the line.
+ * the number of the line. [<b>Update:</b> Incorrect; see \ref dw-out-of-flow.]
*
* Generally, there are three cases which may change the size of the
* widget:
@@ -195,6 +194,12 @@ namespace dw {
* dw::Textblock, which has the value -1 if no rewrapping of lines
* necessary, or otherwise the line from which a rewrap is necessary.
*
+ * <h3>Widgets Ouf Of Flow</h3>
+ *
+ * See
+ *
+ * - dw::oof::OOFAwareWidget (base class) and
+ * - \ref dw-out-of-flow.
*/
class Textblock: public RegardingBorder
{
@@ -272,7 +277,6 @@ private:
int compareTo (int penaltyIndex, BadnessAndPenalty *other);
void intoStringBuffer(lout::misc::StringBuffer *sb);
- void print ();
};
enum { PENALTY_HYPHEN, PENALTY_EM_DASH_LEFT, PENALTY_EM_DASH_RIGHT,
@@ -290,10 +294,8 @@ private:
static const char *hyphenDrawChar;
- Textblock *containingBlock;
- OutOfFlowMgr *outOfFlowMgr;
-
protected:
+
/**
* \brief Implementation used for words.
*/
@@ -316,8 +318,6 @@ protected:
void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
core::style::Style *getStyle ();
void draw (int x, int y, int width, int height);
-
- virtual void print ();
};
class SpaceImgRenderer: public WordImgRenderer
@@ -328,8 +328,6 @@ protected:
void getBgArea (int *x, int *y, int *width, int *height);
core::style::Style *getStyle ();
-
- void print ();
};
struct Paragraph
@@ -452,8 +450,13 @@ protected:
WORD_START = 1 << 5,
/* If a word represents a "real" text word, or (after
* hyphenation) the last part of a "real" text word, this
- * flag is set. Analogue to WORD_START. */
- WORD_END = 1 << 6
+ * flag is set. Analogue to WORD_START. */
+ WORD_END = 1 << 6,
+ /* This word is put at the top of the line, and at the
+ * left. This is necessary if the size of a child widget
+ * depends on the position, which, on the other hand, cannot
+ * be determined before the whole line is broken. */
+ TOPLEFT_OF_LINE = 1 << 7
};
/* TODO: perhaps add a xLeft? */
@@ -496,38 +499,30 @@ protected:
SpaceImgRenderer *spaceImgRenderer;
};
- void printWordShort (Word *word);
- void printWordFlags (short flags);
- void printWordWithFlags (Word *word);
- void printWord (Word *word);
-
struct Anchor
{
char *name;
int wordIndex;
};
- class TextblockIterator: public core::Iterator
+ class TextblockIterator: public OOFAwareWidgetIterator
{
- private:
- bool oofm;
- int index;
+ protected:
+ int numContentsInFlow ();
+ void getContentInFlow (int index, core::Content *content);
public:
TextblockIterator (Textblock *textblock, core::Content::Type mask,
bool atEnd);
- TextblockIterator (Textblock *textblock, core::Content::Type mask,
- bool oofm, int index);
+
+ static TextblockIterator *createWordIndexIterator
+ (Textblock *textblock, core::Content::Type mask, int wordIndex);
lout::object::Object *clone();
- int compareTo(lout::object::Comparable *other);
- bool next ();
- bool prev ();
void highlight (int start, int end, core::HighlightLayer layer);
void unhighlight (int direction, core::HighlightLayer layer);
void getAllocation (int start, int end, core::Allocation *allocation);
- void print ();
};
friend class TextblockIterator;
@@ -582,12 +577,11 @@ protected:
int redrawY;
int lastWordDrawn;
- /* This value is (currently) set by setAscent(). */
+ core::SizeParams sizeRequestParams;
+
+ /* This value is currently) set by setAscent(). */
int lineBreakWidth;
- // Additional vertical offset, used for the "clear" attribute.
- int verticalOffset;
-
int wrapRefLines, wrapRefParagraphs; /* 0-based. Important: Both
are the line numbers, not
the value stored in
@@ -623,10 +617,13 @@ protected:
int hoverLink; /* The link under the mouse pointer */
+ int numSizeReferences;
+ Widget *sizeReferences[NUM_OOFM];
+
void queueDrawRange (int index1, int index2);
int calcVerticalBorder (int widgetPadding, int widgetBorder,
int widgetMargin, int lineBorderTotal,
- int lineMarginTotal);
+ int lineMarginTotal);
void getWordExtremes (Word *word, core::Extremes *extremes);
void justifyLine (Line *line, int diff);
Line *addLine (int firstWord, int lastWord, int newLastOofPos,
@@ -637,7 +634,6 @@ protected:
void calcBorders (int lastOofRef, int height);
void showMissingLines ();
void removeTemporaryLines ();
- void setVerticalOffset (int verticalOffset);
void decorateText (core::View *view, core::style::Style *style,
core::style::Color::Shading shading,
@@ -654,7 +650,9 @@ protected:
core::Rectangle *area, int xWidget, int yWidgetBase);
void drawSpace (int wordIndex, core::View *view, core::Rectangle *area,
int xWidget, int yWidgetBase);
- void drawLine (Line *line, core::View *view, core::Rectangle *area);
+ void drawLine (Line *line, core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
+
int findLineIndex (int y);
int findLineIndexWhenNotAllocated (int y);
int findLineIndexWhenAllocated (int y);
@@ -684,6 +682,13 @@ protected:
core::style::Style *style, bool isStart, bool isEnd);
void calcTextSize (const char *text, size_t len, core::style::Style *style,
core::Requisition *size, bool isStart, bool isEnd);
+ bool calcSizeOfWidgetInFlow (int wordIndex, Widget *widget,
+ core::Requisition *size);
+ bool findSizeRequestReference (Widget *reference, int *xRef = NULL,
+ int *yRef = NULL);
+ bool findSizeRequestReference (int oofmIndex, int *xRef = NULL,
+ int *yRef = NULL)
+ { return findSizeRequestReference (oofContainer[oofmIndex], xRef, yRef); }
/**
* Of nested text blocks, only the most inner one must regard the
@@ -767,7 +772,8 @@ protected:
int lastWord);
void printBorderChangedErrorAndAbort (int y, Widget *vloat,
int wrapLineIndex);
- int yOffsetOfLineToBeCreated ();
+ int yOffsetOfLineToBeCreated (int *lastMargin = NULL);
+ int yOffsetOfLineCreated (Line *line);
bool sendSelectionEvent (core::SelectionState::EventType eventType,
core::MousePositionEvent *event);
@@ -775,6 +781,7 @@ protected:
void processWord (int wordIndex);
virtual int wordWrap (int wordIndex, bool wrapAll);
int wrapWordInFlow (int wordIndex, bool wrapAll);
+ int wrapWordOofRef (int wordIndex, bool wrapAll);
void balanceBreakPosAndHeight (int wordIndex, int firstIndex,
int *searchUntil, bool tempNewLine,
int penaltyIndex, bool borderIsCalculated,
@@ -809,10 +816,32 @@ protected:
void alignLine (int lineIndex);
void calcTextOffset (int lineIndex, int totalWidth);
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void drawLevel (core::View *view, core::Rectangle *area, int level,
+ core::DrawingContext *context);
+
+ Widget *getWidgetAtPointLevel (int x, int y, int level,
+ core::GettingWidgetAtPointContext *context);
+
+ void sizeRequestImpl (core::Requisition *requisition, int numPos,
+ Widget **references, int *x, int *y);
+ int numSizeRequestReferences ();
+ Widget *sizeRequestReference (int index);
+
+ void getExtremesSimpl (core::Extremes *extremes);
+
+ int numGetExtremesReferences ();
+ Widget *getExtremesReference (int index);
+
+ void notifySetAsTopLevel ();
+ void notifySetParent ();
+
void sizeAllocateImpl (core::Allocation *allocation);
- int getAvailWidthOfChild (Widget *child, bool forceValue);
+
+ void calcExtraSpaceImpl ();
+
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
void containerSizeChangedForChildren ();
bool affectsSizeChangeContainerChild (Widget *child);
bool usesAvailWidth ();
@@ -821,13 +850,8 @@ protected:
void markSizeChange (int ref);
void markExtremesChange (int ref);
- void notifySetAsTopLevel();
- void notifySetParent();
-
bool isBlockLevel ();
- void draw (core::View *view, core::Rectangle *area);
-
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
bool motionNotifyImpl (core::EventMotion *event);
@@ -842,7 +866,6 @@ protected:
core::style::Style *style,
int numBreaks, int *breakPos,
core::Requisition *wordSize);
- static bool isContainingBlock (Widget *widget);
public:
static int CLASS_ID;
@@ -854,8 +877,12 @@ public:
static void setPenaltyEmDashRight2 (int penaltyRightEmDash2);
static void setStretchabilityFactor (int stretchabilityFactor);
- Textblock(bool limitTextWidth);
- ~Textblock();
+ static inline bool mustAddBreaks (core::style::Style *style)
+ { return !testStyleOutOfFlow (style) ||
+ testStyleRelativelyPositioned (style); }
+
+ Textblock (bool limitTextWidth);
+ ~Textblock ();
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
@@ -864,8 +891,6 @@ public:
void addText (const char *text, size_t len, core::style::Style *style);
inline void addText (const char *text, core::style::Style *style)
{ addText (text, strlen(text), style); }
- static bool isStyleOutOfFlow (core::style::Style *style)
- { return OutOfFlowMgr::isStyleOutOfFlow (style); }
void addWidget (core::Widget *widget, core::style::Style *style);
bool addAnchor (const char *name, core::style::Style *style);
void addSpace (core::style::Style *style);
@@ -873,21 +898,22 @@ public:
void addParbreak (int space, core::style::Style *style);
void addLinebreak (core::style::Style *style);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
void handOverBreak (core::style::Style *style);
void changeLinkColor (int link, int newColor);
void changeWordStyle (int from, int to, core::style::Style *style,
bool includeFirstSpace, bool includeLastSpace);
- virtual bool mustBeWidenedToAvailWidth ();
-
+ bool mustBeWidenedToAvailWidth ();
void borderChanged (int y, core::Widget *vloat);
+ void widgetRefSizeChanged (int externalIndex);
void clearPositionChanged ();
void oofSizeChanged (bool extremesChanged);
- inline int getLineBreakWidth () { return lineBreakWidth; }
+ int getLineBreakWidth ();
+ bool isPossibleContainer (int oofmIndex);
+ bool isPossibleContainerParent (int oofmIndex);
};
-#define DBG_SET_WORD_PENALTY(n, i, is) \
+#define DBG_SET_WORD_PENALTY(n, i, is) \
D_STMT_START { \
if (words->getRef(n)->badnessAndPenalty.getPenalty (i) == INT_MIN) \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "penalty." is, "-inf"); \
@@ -896,7 +922,7 @@ public:
else \
DBG_OBJ_ARRATTRSET_NUM ("words", n, "penalty." is, \
words->getRef(n)->badnessAndPenalty \
- .getPenalty (i)); \
+ .getPenalty (i)); \
} D_STMT_END
#define DBG_SET_WORD(n) \
@@ -930,6 +956,16 @@ public:
DBG_SET_WORD_PENALTY (n, 1, "1"); \
} D_STMT_END
+#define DBG_SET_WORD_SIZE(n) \
+ D_STMT_START { \
+ DBG_OBJ_ARRATTRSET_NUM ("words", n, "size.width", \
+ words->getRef(n)->size.width); \
+ DBG_OBJ_ARRATTRSET_NUM ("words", n, "size.ascent", \
+ words->getRef(n)->size.ascent); \
+ DBG_OBJ_ARRATTRSET_NUM ("words", n, "size.descent", \
+ words->getRef(n)->size.descent); \
+ } D_STMT_END
+
#define DBG_MSG_WORD(aspect, prio, prefix, n, suffix) \
D_STMT_START { \
if ((n) < 0 || (n) >= words->size ()) \
diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc
index b6423a29..14631eba 100644
--- a/dw/textblock_iterator.cc
+++ b/dw/textblock_iterator.cc
@@ -33,173 +33,48 @@ namespace dw {
Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
core::Content::Type mask,
bool atEnd):
- core::Iterator (textblock, mask, atEnd)
+ OOFAwareWidgetIterator (textblock, mask, atEnd, textblock->words->size ())
{
- if (atEnd) {
- if (textblock->outOfFlowMgr) {
- oofm = true;
- index = textblock->outOfFlowMgr->getNumWidgets();
- } else {
- oofm = false;
- index = textblock->words->size();
- }
- } else {
- oofm = false;
- index = -1;
- }
-
- content.type = atEnd ? core::Content::END : core::Content::START;
}
-Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
- core::Content::Type mask,
- bool oofm, int index):
- core::Iterator (textblock, mask, false)
+Textblock::TextblockIterator
+ *Textblock::TextblockIterator::createWordIndexIterator (Textblock *textblock,
+ core::Content::Type
+ mask,
+ int wordIndex)
{
- this->oofm = oofm;
- this->index = index;
-
- // TODO To be completely exact, oofm should be considered here.
- if (index < 0)
- content.type = core::Content::START;
- else if (index >= textblock->words->size())
- content.type = core::Content::END;
- else
- content = textblock->words->getRef(index)->content;
+ TextblockIterator *tbIt = new TextblockIterator (textblock, mask, false);
+ tbIt->setValues (0, wordIndex);
+ return tbIt;
}
object::Object *Textblock::TextblockIterator::clone()
{
- return
- new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index);
-}
-
-int Textblock::TextblockIterator::compareTo(object::Comparable *other)
-{
- TextblockIterator *otherTI = (TextblockIterator*)other;
-
- if (oofm && !otherTI->oofm)
- return +1;
- else if (!oofm && otherTI->oofm)
- return -1;
- else
- return index - otherTI->index;
-}
-
-bool Textblock::TextblockIterator::next ()
-{
- Textblock *textblock = (Textblock*)getWidget();
-
- if (content.type == core::Content::END)
- return false;
-
- short type;
-
- do {
- index++;
-
- if (oofm) {
- // Iterating over OOFM.
- if (index >= textblock->outOfFlowMgr->getNumWidgets()) {
- // End of OOFM list reached.
- content.type = core::Content::END;
- return false;
- }
- type = core::Content::WIDGET_OOF_CONT;
- } else {
- // Iterating over words list.
- if (index < textblock->words->size ())
- // Still words left.
- type = textblock->words->getRef(index)->content.type;
- else {
- // End of words list reached.
- if (textblock->outOfFlowMgr) {
- oofm = true;
- index = 0;
- if (textblock->outOfFlowMgr->getNumWidgets() > 0)
- // Start with OOFM widgets.
- type = core::Content::WIDGET_OOF_CONT;
- else {
- // No OOFM widgets (number is 0).
- content.type = core::Content::END;
- return false;
- }
- } else {
- // No OOFM widgets (no OOFM agt all).
- content.type = core::Content::END;
- return false;
- }
- }
- }
- } while ((type & getMask()) == 0);
-
- if (oofm) {
- content.type = core::Content::WIDGET_OOF_CONT;
- content.widget = textblock->outOfFlowMgr->getWidget (index);
- } else
- content = textblock->words->getRef(index)->content;
-
- return true;
-}
-
-bool Textblock::TextblockIterator::prev ()
-{
- Textblock *textblock = (Textblock*)getWidget();
-
- if (content.type == core::Content::START)
- return false;
-
- short type;
-
- do {
- index--;
-
- if (oofm) {
- // Iterating over OOFM.
- if (index >= 0)
- // Still widgets left.
- type = core::Content::WIDGET_OOF_CONT;
- else {
- // Beginning of OOFM list reached. Continue with words.
- oofm = false;
- index = textblock->words->size() - 1;
- if (index < 0) {
- // There are no words. (Actually, this case should not
- // happen: When there are OOF widgets, ther must be OOF
- // references, or widgets in flow, which contain
- // references.
- content.type = core::Content::END;
- return false;
- }
- type = textblock->words->getRef(index)->content.type;
- }
- } else {
- // Iterating over words list.
- if (index < 0) {
- // Beginning of words list reached.
- content.type = core::Content::START;
- return false;
- }
- type = textblock->words->getRef(index)->content.type;
- }
- } while ((type & getMask()) == 0);
-
- if (oofm) {
- content.type = core::Content::WIDGET_OOF_CONT;
- content.type = false;
- content.widget = textblock->outOfFlowMgr->getWidget (index);
- } else
- content = textblock->words->getRef(index)->content;
-
- return true;
+ TextblockIterator *tbIt =
+ new TextblockIterator ((Textblock*)getWidget(), getMask(), false);
+ cloneValues (tbIt);
+ return tbIt;
}
void Textblock::TextblockIterator::highlight (int start, int end,
core::HighlightLayer layer)
{
- if (!oofm) {
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget (), "TextblockIterator::highlight",
+ "..., %d, %d, %d", start, end, layer);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s",
+ sb.getChars ());
+ }
+
+ if (inFlow ()) {
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d",
+ getInFlowIndex ());
+
Textblock *textblock = (Textblock*)getWidget();
- int index1 = index, index2 = index;
+ int index = getInFlowIndex (), index1 = index, index2 = index;
int oldStartIndex = textblock->hlStart[layer].index;
int oldStartChar = textblock->hlStart[layer].nChar;
@@ -224,22 +99,46 @@ void Textblock::TextblockIterator::highlight (int start, int end,
textblock->hlEnd[layer].nChar = end;
}
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index",
+ textblock->hlStart[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar",
+ textblock->hlStart[layer].nChar);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index",
+ textblock->hlEnd[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar",
+ textblock->hlEnd[layer].nChar);
+
if (oldStartIndex != textblock->hlStart[layer].index ||
oldStartChar != textblock->hlStart[layer].nChar ||
oldEndIndex != textblock->hlEnd[layer].index ||
oldEndChar != textblock->hlEnd[layer].nChar)
textblock->queueDrawRange (index1, index2);
- }
+ } else
+ highlightOOF (start, end, layer);
- // TODO What about OOF widgets?
+ DBG_OBJ_LEAVE_O (getWidget ());
}
void Textblock::TextblockIterator::unhighlight (int direction,
core::HighlightLayer layer)
{
- if (!oofm) {
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget (),
+ "TextblockIterator/unhighlight", "..., %d, %d",
+ direction, layer);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s",
+ sb.getChars ());
+ }
+
+ if (inFlow ()) {
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d",
+ getInFlowIndex ());
+
Textblock *textblock = (Textblock*)getWidget();
- int index1 = index, index2 = index;
+ int index = getInFlowIndex (), index1 = index, index2 = index;
if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index)
return;
@@ -264,26 +163,33 @@ void Textblock::TextblockIterator::unhighlight (int direction,
textblock->hlEnd[layer].nChar = INT_MAX;
}
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index",
+ textblock->hlStart[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar",
+ textblock->hlStart[layer].nChar);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index",
+ textblock->hlEnd[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar",
+ textblock->hlEnd[layer].nChar);
+
if (oldStartIndex != textblock->hlStart[layer].index ||
oldStartChar != textblock->hlStart[layer].nChar ||
oldEndIndex != textblock->hlEnd[layer].index ||
oldEndChar != textblock->hlEnd[layer].nChar)
textblock->queueDrawRange (index1, index2);
- }
+ } else
+ unhighlightOOF (direction, layer);
- // TODO What about OOF widgets?
+ DBG_OBJ_LEAVE_O (getWidget ());
}
void Textblock::TextblockIterator::getAllocation (int start, int end,
core::Allocation *allocation)
{
- Textblock *textblock = (Textblock*)getWidget();
+ if (inFlow ()) {
+ Textblock *textblock = (Textblock*)getWidget();
- if (oofm) {
- // TODO Consider start and end?
- *allocation =
- *(textblock->outOfFlowMgr->getWidget(index)->getAllocation());
- } else {
+ int index = getInFlowIndex ();
Word *word = textblock->words->getRef (index);
int firstWordOfLine, textOffset, lineYOffsetCanvas, lineBorderAscent;
@@ -360,14 +266,19 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
}
allocation->ascent = word->size.ascent;
allocation->descent = word->size.descent;
- }
+ } else
+ getAllocationOOF (start, end, allocation);
}
-void Textblock::TextblockIterator::print ()
+int Textblock::TextblockIterator::numContentsInFlow ()
{
- Iterator::print ();
- printf (", oofm = %s, index = %d", oofm ? "true" : "false", index);
+ return ((Textblock*)getWidget())->words->size ();
+}
+void Textblock::TextblockIterator::getContentInFlow (int index,
+ core::Content *content)
+{
+ *content = ((Textblock*)getWidget())->words->getRef(index)->content;
}
} // namespace dw
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index 3c181388..03933830 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -75,7 +75,7 @@ void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
this->totalShrinkability = totalShrinkability;
#endif
- ratio = 0; // because this is used in print()
+ ratio = 0;
if (totalWidth == idealWidth) {
badnessState = BADNESS_VALUE;
@@ -191,13 +191,6 @@ int Textblock::BadnessAndPenalty::compareTo (int penaltyIndex,
return 0;
}
-void Textblock::BadnessAndPenalty::print ()
-{
- misc::StringBuffer sb;
- intoStringBuffer(&sb);
- printf ("%s", sb.getChars ());
-}
-
void Textblock::BadnessAndPenalty::intoStringBuffer(misc::StringBuffer *sb)
{
switch (badnessState) {
@@ -247,42 +240,6 @@ void Textblock::BadnessAndPenalty::intoStringBuffer(misc::StringBuffer *sb)
sb->append (")");
}
-void Textblock::printWordShort (Word *word)
-{
- core::Content::print (&(word->content));
-}
-
-void Textblock::printWordFlags (short flags)
-{
- printf ("%s:%s:%s:%s:%s:%s:%s",
- (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--",
- (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--",
- (flags & Word::PERM_DIV_CHAR) ? "dp" : "--",
- (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--",
- (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--",
- (flags & Word::WORD_START) ? "st" : "--",
- (flags & Word::WORD_END) ? "en" : "--");
-}
-
-void Textblock::printWordWithFlags (Word *word)
-{
- printWordShort (word);
- printf (" (flags = ");
- printWordFlags (word->flags);
- printf (")");
-}
-
-void Textblock::printWord (Word *word)
-{
- printWordWithFlags (word);
-
- printf (" [%d / %d + %d - %d => %d + %d - %d] => ",
- word->size.width, word->origSpace, getSpaceStretchability(word),
- getSpaceShrinkability(word), word->totalWidth,
- word->totalSpaceStretchability, word->totalSpaceShrinkability);
- word->badnessAndPenalty.print ();
-}
-
/*
* ...
*
@@ -495,20 +452,33 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
mustQueueResize = true;
- //printWordShort (words->getRef (line->firstWord));
- //printf (" ... ");
- //printWordShort (words->getRef (line->lastWord));
- //printf (": ");
- //words->getRef(line->lastWord)->badnessAndPenalty.print ();
- //printf ("\n");
-
int xWidget = line->textOffset;
+ int yLine = yOffsetOfLineCreated (line);
for (int i = firstWord; i <= lastWord; i++) {
Word *word = words->getRef (i);
if (word->wordImgRenderer)
word->wordImgRenderer->setData (xWidget, lines->size () - 1);
if (word->spaceImgRenderer)
word->spaceImgRenderer->setData (xWidget, lines->size () - 1);
+
+ if (word->content.type == core::Content::WIDGET_OOF_REF) {
+ Widget *widget = word->content.widget;
+ int oofmIndex = getWidgetOOFIndex (widget);
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ // See also Textblock::sizeAllocate, and notes there about
+ // vertical alignment. Calculating the vertical position
+ // should probably be centralized.
+ if (oofm) {
+ int xRel = xWidget;
+ int yRel = yLine + (line->borderAscent - word->size.ascent);
+ int xRef, yRef;
+ if (findSizeRequestReference (oofmIndex, &xRef, &yRef))
+ oofm->tellPosition2 (widget, xRef + xRel, yRef + yRel);
+ else
+ oofm->tellIncompletePosition2 (widget, this, xRel, yRel);
+ }
+ }
+
xWidget += word->size.width + word->effSpace;
}
@@ -601,7 +571,7 @@ int Textblock::wordWrap (int wordIndex, bool wrapAll)
int n;
if (word->content.type == core::Content::WIDGET_OOF_REF)
- n = 0;
+ n = wrapWordOofRef (wordIndex, wrapAll);
else
n = wrapWordInFlow (wordIndex, wrapAll);
@@ -764,14 +734,15 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
startSearch, breakPos);
for (int i = startSearch; newFloatPos == -1 && i <= breakPos; i++) {
core::Content *content = &(words->getRef(i)->content);
- if (content->type == core::Content::WIDGET_OOF_REF &&
- // Later, absolutepositioned elements (which do not affect
- // borders) can be ignored at this point.
- (containingBlock->outOfFlowMgr->affectsLeftBorder
- (content->widget) ||
- containingBlock->outOfFlowMgr->affectsRightBorder
- (content->widget)))
- newFloatPos = i;
+ if (content->type == core::Content::WIDGET_OOF_REF) {
+ for (int j = 0; newFloatPos == -1 && j < NUM_OOFM; j++) {
+ if ((searchOutOfFlowMgr(j)->affectsLeftBorder(content
+ ->widget) ||
+ searchOutOfFlowMgr(j)->affectsRightBorder (content
+ ->widget)))
+ newFloatPos = i;
+ }
+ }
}
DBG_OBJ_MSGF ("construct.word", 2, "newFloatPos = %d", newFloatPos);
@@ -782,10 +753,22 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
floatHandled = true;
// Step 2: position the float and re-calculate the line.
- lastFloatPos = newFloatPos;
- containingBlock->outOfFlowMgr->tellPosition
- (words->getRef(lastFloatPos)->content.widget, yNewLine);
+ // TODO "x" is not quite correct, but this does not matter
+ // (currently?).
+
+ lastFloatPos = newFloatPos;
+
+ Widget *widget = words->getRef(lastFloatPos)->content.widget;
+ int oofmIndex = getWidgetOOFIndex (widget);
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ if (oofm && oofm->mayAffectBordersAtAll ()) {
+ int xRel = boxOffsetX (), yRel = yNewLine, xRef, yRef;
+ if (findSizeRequestReference (oofmIndex, &xRef, &yRef))
+ oofm->tellPosition1 (widget, xRef + xRel, yRef + yRel);
+ else
+ oofm->tellIncompletePosition1 (widget, this, xRel, yRel);
+ }
balanceBreakPosAndHeight (wordIndex, firstIndex, &searchUntil,
tempNewLine, penaltyIndex, false,
@@ -851,8 +834,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
firstWordWithoutLine = lines->getLastRef()->lastWord + 1;
if (wordIndex >= firstWordWithoutLine) {
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lines->size ());
+ word->content.widget->parentRef = makeParentRefInFlow (lines->size ());
DBG_OBJ_SET_NUM_O (word->content.widget, "parentRef",
word->content.widget->parentRef);
}
@@ -863,6 +845,36 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
return diffWords;
}
+int Textblock::wrapWordOofRef (int wordIndex, bool wrapAll)
+{
+ DBG_OBJ_ENTER ("construct.word", 0, "wrapWordOofRef", "%d, %s",
+ wordIndex, wrapAll ? "true" : "false");
+
+ Word *word = words->getRef (wordIndex);
+ Widget *widget = word->content.widget;
+ int yNewLine = yOffsetOfLineToBeCreated ();
+
+ // Floats, which affect either border, are handled in wrapWordInFlow; this
+ // is rather for positioned elements (but only for completeness:
+ // tellPosition1 is not implemented for positioned elements).
+ int oofmIndex = getWidgetOOFIndex (widget);
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ DBG_OBJ_MSGF ("construct.word", 1, "parentRef = %d, oofm = %p",
+ widget->parentRef, oofm);
+ if (oofm && !oofm->mayAffectBordersAtAll ()) {
+ // TODO Again, "x" is not correct (see above).
+ int xRel = boxOffsetX (), yRel = yNewLine, xRef, yRef;
+ if (findSizeRequestReference (oofmIndex, &xRef, &yRef))
+ oofm->tellPosition1 (widget, xRef + xRel, yRef + yRel);
+ else
+ oofm->tellIncompletePosition1 (widget, this, xRel, yRel);
+ }
+
+ DBG_OBJ_LEAVE ();
+
+ return 0; // Words list not changed.
+}
+
// *height must be initialized, but not *breakPos.
// *wordIndexEnd must be initialized (initially to wordIndex)
void Textblock::balanceBreakPosAndHeight (int wordIndex, int firstIndex,
@@ -1469,8 +1481,9 @@ void Textblock::moveWordIndices (int wordIndex, int num, int *addIndex1)
DBG_OBJ_ENTER ("construct.word", 0, "moveWordIndices", "%d, %d",
wordIndex, num);
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->moveExternalIndices (this, wordIndex, num);
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (searchOutOfFlowMgr(i))
+ searchOutOfFlowMgr(i)->moveExternalIndices (this, wordIndex, num);
for (int i = lines->size () - 1; i >= 0; i--) {
Line *line = lines->getRef (i);
@@ -1542,8 +1555,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
borderDescent =
marginDescent - word->content.widget->getStyle()->margin.bottom;
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lineIndex);
+ word->content.widget->parentRef = makeParentRefInFlow (lineIndex);
DBG_OBJ_SET_NUM_O (word->content.widget, "parentRef",
word->content.widget->parentRef);
} else {
@@ -1669,8 +1681,7 @@ int Textblock::calcLineBreakWidth (int lineIndex)
if (limitTextWidth &&
layout->getUsesViewport () &&
// margin/border/padding will be subtracted later, via OOFM.
- lineBreakWidth - getStyle()->boxDiffWidth()
- > layout->getWidthViewport () - 10)
+ lineBreakWidth - boxDiffWidth() > layout->getWidthViewport () - 10)
lineBreakWidth = layout->getWidthViewport () - 10;
if (lineIndex == 0)
lineBreakWidth -= line1OffsetEff;
@@ -1682,8 +1693,8 @@ int Textblock::calcLineBreakWidth (int lineIndex)
} else
leftBorder = rightBorder = 0;
- leftBorder = misc::max (leftBorder, getStyle()->boxOffsetX());
- rightBorder = misc::max (rightBorder, getStyle()->boxRestWidth());
+ leftBorder = misc::max (leftBorder, boxOffsetX());
+ rightBorder = misc::max (rightBorder, boxRestWidth());
lineBreakWidth -= (leftBorder + rightBorder);
@@ -1885,8 +1896,24 @@ void Textblock::rewrap ()
for (int i = firstWord; i < words->size (); i++) {
Word *word = words->getRef (i);
- if (word->content.type == core::Content::WIDGET_IN_FLOW)
- word->content.widget->sizeRequest (&word->size);
+ switch (word->content.type) {
+ case core::Content::WIDGET_IN_FLOW:
+ calcSizeOfWidgetInFlow (i, word->content.widget, &word->size);
+ DBG_SET_WORD_SIZE (i);
+ break;
+
+ case core::Content::WIDGET_OOF_REF:
+ {
+ int oofmIndex = getOOFMIndex (word->content.widget);
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ oofm->calcWidgetRefSize (word->content.widget, &(word->size));
+ DBG_SET_WORD_SIZE (i);
+ }
+ break;
+
+ default:
+ break;
+ }
wordWrap (i, false);
@@ -1972,17 +1999,6 @@ void Textblock::initNewLine ()
{
DBG_OBJ_ENTER0 ("construct.line", 0, "initNewLine");
- // At the very beginning, in Textblock::Textblock, where this
- // method is called, containingBlock is not yet defined.
-
- if (containingBlock && containingBlock->outOfFlowMgr) {
- if (lines->size () == 0) {
- int clearPosition =
- containingBlock->outOfFlowMgr->getClearPosition (this);
- setVerticalOffset (misc::max (clearPosition, 0));
- }
- }
-
calcBorders (lines->size() > 0 ?
lines->getLastRef()->lastOofRefPositionedBeforeThisLine : -1,
1);
@@ -2000,81 +2016,99 @@ void Textblock::calcBorders (int lastOofRef, int height)
DBG_OBJ_ENTER ("construct.line", 0, "calcBorders", "%d, %d",
lastOofRef, height);
- if (containingBlock && containingBlock->outOfFlowMgr) {
- // Consider the example:
- //
- // <div>
- // Some text A ...
- // <p> Some text B ... <img style="float:right" ...> </p>
- // Some more text C ...
- // </div>
- //
- // If the image is large enough, it should float around the last
- // paragraph, "Some more text C ...":
- //
- // Some more text A ...
- //
- // Some more ,---------.
- // text B ... | |
- // | <img> |
- // Some more | | <---- Consider this line!
- // text C ... '---------'
- //
- // Since this float is generated in the <p> element, not in the-
- // <div> element, and since they are represented by different
- // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine,
- // and so lastOofRef, is -1 for the line marked with an arrow;
- // this would result in ignoring the float, because -1 is
- // equivalent to the very beginning of the <div> element ("Some
- // more text A ..."), which is not affected by the float.
- //
- // On the other hand, the only relevant values of
- // Line::lastOofRefPositionedBeforeThisLine are those greater
- // than the first word of the new line, so a solution is to use
- // the maximum of both.
+ newLineHasFloatLeft = newLineHasFloatRight = false;
+ newLineLeftBorder = newLineRightBorder = 0;
+ newLineLeftFloatHeight = newLineRightFloatHeight = 0;
+ bool oofmDefined = false;
+ for (int i = 0; i < NUM_OOFM && !oofmDefined; i++)
+ if (findSizeRequestReference (i))
+ oofmDefined = true;
- int firstWordOfLine = lines->size() > 0 ?
- lines->getLastRef()->lastWord + 1 : 0;
+ if (oofmDefined) {
+ int firstWordOfLine =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
int effOofRef = misc::max (lastOofRef, firstWordOfLine - 1);
-
- int y = yOffsetOfLineToBeCreated ();
-
- newLineHasFloatLeft =
- containingBlock->outOfFlowMgr->hasFloatLeft (this, y, height, this,
- effOofRef);
- newLineHasFloatRight =
- containingBlock->outOfFlowMgr->hasFloatRight (this, y, height, this,
- effOofRef);
- newLineLeftBorder =
- containingBlock->outOfFlowMgr->getLeftBorder (this, y, height, this,
- effOofRef);
- newLineRightBorder =
- containingBlock->outOfFlowMgr->getRightBorder (this, y, height, this,
- effOofRef);
- newLineLeftFloatHeight = newLineHasFloatLeft ?
- containingBlock->outOfFlowMgr->getLeftFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
- newLineRightFloatHeight = newLineHasFloatRight ?
- containingBlock->outOfFlowMgr->getRightFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
-
- DBG_OBJ_MSGF ("construct.line", 1,
- "%d * %d (%s) / %d * %d (%s), at %d (%d), until %d = "
- "max (%d, %d - 1)",
- newLineLeftBorder, newLineLeftFloatHeight,
- newLineHasFloatLeft ? "true" : "false",
- newLineRightBorder, newLineRightFloatHeight,
- newLineHasFloatRight ? "true" : "false",
- y, height, effOofRef, lastOofRef, firstWordOfLine);
- } else {
- newLineHasFloatLeft = newLineHasFloatRight = false;
- newLineLeftBorder = newLineRightBorder = 0;
- newLineLeftFloatHeight = newLineRightFloatHeight = 0;
-
- DBG_OBJ_MSG ("construct.line", 0, "<i>no CB of OOFM</i>");
+ int yRel = yOffsetOfLineToBeCreated (), yRef;
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oof::OutOfFlowMgr *oofm;
+ if ((oofm = searchOutOfFlowMgr (i)) &&
+ findSizeRequestReference (i, NULL, &yRef)) {
+ // Consider the example:
+ //
+ // <div>
+ // Some text A ...
+ // <p> Some text B ... <img style="float:right" ...> </p>
+ // Some more text C ...
+ // </div>
+ //
+ // If the image is large enough, it should float around the last
+ // paragraph, "Some more text C ...":
+ //
+ // Some more text A ...
+ //
+ // Some more ,---------.
+ // text B ... | |
+ // | <img> |
+ // Some more | | <---- Consider this line!
+ // text C ... '---------'
+ //
+ // Since this float is generated in the <p> element, not in the-
+ // <div> element, and since they are represented by different
+ // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine,
+ // and so lastOofRef, is -1 for the line marked with an arrow;
+ // this would result in ignoring the float, because -1 is
+ // equivalent to the very beginning of the <div> element ("Some
+ // more text A ..."), which is not affected by the float.
+ //
+ // On the other hand, the only relevant values of
+ // Line::lastOofRefPositionedBeforeThisLine are those greater
+ // than the first word of the new line, so a solution is to use
+ // the maximum of both.
+
+ int y = yRef + yRel;
+ bool thisHasLeft, thisHasRight;
+
+ thisHasLeft = oofm->hasFloatLeft (this, y, height, this, effOofRef);
+ newLineHasFloatLeft = newLineHasFloatLeft || thisHasLeft;
+ thisHasRight = oofm->hasFloatRight (this, y, height, this,
+ effOofRef);
+ newLineHasFloatRight = newLineHasFloatRight || thisHasRight;
+
+ newLineLeftBorder =
+ misc::max (newLineLeftBorder,
+ oofm->getLeftBorder (this, y, height, this,
+ effOofRef));
+ newLineRightBorder =
+ misc::max (newLineRightBorder,
+ oofm->getRightBorder (this, y, height, this,
+ effOofRef));
+
+ // TODO "max" is not really correct for the heights. (Does
+ // not matter, since only one, the float manager, returns
+ // meaningful values.)
+ if (thisHasLeft)
+ newLineLeftFloatHeight =
+ misc::max (newLineLeftFloatHeight,
+ oofm->getLeftFloatHeight (this, y, height, this,
+ effOofRef));
+ if (thisHasRight)
+ newLineRightFloatHeight =
+ misc::max (newLineRightFloatHeight,
+ oofm->getRightFloatHeight (this, y, height, this,
+ effOofRef));
+
+ DBG_OBJ_MSGF ("construct.line", 1,
+ "OOFM #%d: %d * %d (%s) / %d * %d (%s), at %d (%d), "
+ "until %d = max (%d, %d - 1)",
+ i, newLineLeftBorder, newLineLeftFloatHeight,
+ newLineHasFloatLeft ? "true" : "false",
+ newLineRightBorder, newLineRightFloatHeight,
+ newLineHasFloatRight ? "true" : "false",
+ y, height, effOofRef, lastOofRef, firstWordOfLine);
+ }
+ }
}
DBG_OBJ_SET_BOOL ("newLineHasFloatLeft", newLineHasFloatLeft);
diff --git a/dw/tools.cc b/dw/tools.cc
new file mode 100644
index 00000000..65734900
--- /dev/null
+++ b/dw/tools.cc
@@ -0,0 +1,132 @@
+#include "tools.hh"
+
+namespace dw {
+namespace core {
+
+SizeParams::SizeParams ()
+{
+ DBG_OBJ_CREATE ("dw::core::SizeParams");
+ init ();
+ debugPrint ();
+}
+
+SizeParams::~SizeParams ()
+{
+ cleanup ();
+ DBG_OBJ_DELETE ();
+}
+
+void SizeParams::init ()
+{
+ numPos = 0;
+ references = NULL;
+ x = y = NULL;
+}
+
+void SizeParams::cleanup ()
+{
+ if (references)
+ delete[] references;
+ if (x)
+ delete[] x;
+ if (y)
+ delete[] y;
+
+ init ();
+}
+
+void SizeParams::fill (int numPos, Widget **references, int *x, int *y)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "fill");
+
+ cleanup ();
+
+ this->numPos = numPos;
+
+ this->references = new Widget*[numPos];
+ this->x = new int[numPos];
+ this->y = new int[numPos];
+
+ for (int i = 0; i < numPos; i++) {
+ this->references[i] = references[i];
+ this->x[i] = x[i];
+ this->y[i] = y[i];
+ }
+
+ debugPrint ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void SizeParams::forChild (Widget *parent, Widget *child, int xRel, int yRel,
+ SizeParams *childParams)
+{
+ DBG_OBJ_ENTER ("resize", 0, "forChild", "%p, %p, %d, %d, %p",
+ parent, child, xRel, yRel, childParams);
+
+ int numChildReferences = child->numSizeRequestReferences ();
+
+ childParams->numPos = 0;
+ childParams->references = new Widget*[numChildReferences];
+ childParams->x = new int[numChildReferences];
+ childParams->y = new int[numChildReferences];
+
+ for (int i = 0; i < numChildReferences; i++) {
+ Widget *childReference = child->sizeRequestReference (i);
+ if (childReference == parent) {
+ childParams->references[numPos] = childReference;
+ childParams->x[numPos] = xRel;
+ childParams->y[numPos] = yRel;
+ numPos++;
+ } else {
+ bool found = false;
+ for (int j = 0; !found && j < numPos; j++) {
+ if (childReference == references[j]) {
+ found = true;
+ references[numPos] = childReference;
+ childParams->x[numPos] = x[j] + xRel;
+ childParams->y[numPos] = y[j] + yRel;
+ numPos++;
+ }
+ }
+ }
+ }
+
+ childParams->debugPrint ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool SizeParams::findReference (Widget *reference, int *x, int *y)
+{
+ DBG_OBJ_ENTER ("resize", 0, "findReference", "%p", reference);
+
+ bool found = false;
+ for (int i = 0; i < numPos && !found; i++) {
+ if (reference == references[i]) {
+ if (x)
+ *x = this->x[i];
+ if (y)
+ *y = this->y[i];
+ found = true;
+ }
+ }
+
+ if (found) {
+ if (x && y)
+ DBG_OBJ_LEAVE_VAL ("true, x = %d, y = %d", *x, *y);
+ else if (x)
+ DBG_OBJ_LEAVE_VAL ("true, x = %d", *x);
+ else if (y)
+ DBG_OBJ_LEAVE_VAL ("true, y = %d", *y);
+ else
+ DBG_OBJ_LEAVE_VAL ("%s", "true");
+ } else
+ DBG_OBJ_LEAVE_VAL ("%s", "false");
+
+ return found;
+}
+
+
+} // namespace core
+} // namespace dw
diff --git a/dw/tools.hh b/dw/tools.hh
new file mode 100644
index 00000000..973881af
--- /dev/null
+++ b/dw/tools.hh
@@ -0,0 +1,56 @@
+#ifndef __DW_TOOLS_HH__
+#define __DW_TOOLS_HH__
+
+#include "core.hh"
+#include "../lout/debug.hh"
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Hold arguments passed to dw::core::Widget::sizeRequest and
+ * dw::core::Widget::getExtremes, as described in \ref dw-size-request-pos.
+ */
+class SizeParams
+{
+private:
+ int numPos;
+ Widget **references;
+ int *x, *y;
+
+ void init ();
+ void cleanup ();
+
+ inline void debugPrint () {
+ DBG_IF_RTFL {
+ DBG_OBJ_SET_NUM ("numPos", numPos);
+ for (int i = 0; i < numPos; i++) {
+ DBG_OBJ_ARRSET_PTR ("references", i, references[i]);
+ DBG_OBJ_ARRSET_NUM ("x", i, x[i]);
+ DBG_OBJ_ARRSET_NUM ("y", i, y[i]);
+ }
+ }
+ }
+
+public:
+ SizeParams ();
+ ~SizeParams ();
+
+ void fill (int numPos, Widget **references, int *x, int *y);
+ void forChild (Widget *parent, Widget *child, int xRel, int yRel,
+ SizeParams *childParams);
+ bool findReference (Widget *reference, int *x, int *y);
+
+ inline int getNumPos () { return numPos; }
+ inline Widget **getReferences () { return references; }
+ inline int *getX () { return x; }
+ inline int *getY () { return y; }
+ inline Widget *getReference (int i) { return references[i]; }
+ inline int getX (int i) { return x[i]; }
+ inline int getY (int i) { return y[i]; }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_TOOLS_HH__
diff --git a/dw/types.hh b/dw/types.hh
index b6b4ca0b..481f4804 100644
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -208,6 +208,10 @@ struct Content
WIDGET_OOF_REF = 1 << 5,
BREAK = 1 << 6,
+ /** \brief can be used internally, but should never be exposed,
+ e. g. by iterators */
+ INVALID = 1 << 7,
+
ALL = 0xff,
REAL_CONTENT = 0xff ^ (START | END),
SELECTION_CONTENT = TEXT | BREAK, // WIDGET_* must be set additionally
@@ -233,6 +237,67 @@ struct Content
static void printMask (Type mask);
};
+/**
+ * \brief Base class for dw::core::DrawingContext and
+ * dw::core::GettingWidgetAtPointContext.
+ *
+ * Not to be confused with the *stacking context* as defined by CSS.
+ */
+class StackingProcessingContext
+{
+private:
+ lout::container::typed::HashSet<lout::object::TypedPointer<Widget> >
+ *widgetsProcessedAsInterruption;
+
+public:
+ inline StackingProcessingContext () {
+ widgetsProcessedAsInterruption =
+ new lout::container::typed::HashSet<lout::object::
+ TypedPointer<Widget> > (true);
+ }
+
+ inline ~StackingProcessingContext ()
+ { delete widgetsProcessedAsInterruption; }
+
+ inline bool hasWidgetBeenProcessedAsInterruption (Widget *widget) {
+ lout::object::TypedPointer<Widget> key (widget);
+ return widgetsProcessedAsInterruption->contains (&key);
+ }
+
+ inline void addWidgetProcessedAsInterruption (Widget *widget) {
+ lout::object::TypedPointer<Widget> *key =
+ new lout::object::TypedPointer<Widget> (widget);
+ return widgetsProcessedAsInterruption->put (key);
+ }
+};
+
+/**
+ * \brief Set at the top when drawing.
+ *
+ * See \ref dw-interrupted-drawing for details.
+ */
+class DrawingContext: public StackingProcessingContext
+{
+private:
+ Rectangle toplevelArea;
+
+public:
+ inline DrawingContext (Rectangle *toplevelArea) {
+ this->toplevelArea = *toplevelArea;
+ }
+
+ inline Rectangle *getToplevelArea () { return &toplevelArea; }
+};
+
+/**
+ * \brief Set at the top when getting the widget at the point.
+ *
+ * Similar to dw::core::DrawingContext.
+ */
+class GettingWidgetAtPointContext: public StackingProcessingContext
+{
+};
+
} // namespace core
} // namespace dw
diff --git a/dw/ui.cc b/dw/ui.cc
index 1ea10ebc..c95160a4 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -48,12 +48,12 @@ Embed::~Embed()
DBG_OBJ_DELETE ();
}
-void Embed::sizeRequestImpl (Requisition *requisition)
+void Embed::sizeRequestSimpl (Requisition *requisition)
{
resource->sizeRequest (requisition);
}
-void Embed::getExtremesImpl (Extremes *extremes)
+void Embed::getExtremesSimpl (Extremes *extremes)
{
resource->getExtremes (extremes);
correctExtremes (extremes, false);
@@ -131,10 +131,10 @@ void Embed::setEnabled (bool enabled)
resource->setEnabled (enabled);
}
-void Embed::draw (View *view, Rectangle *area)
+void Embed::draw (View *view, Rectangle *area, DrawingContext *context)
{
drawWidgetBox (view, area, false);
- resource->draw (view, area);
+ resource->draw (view, area, context);
}
Iterator *Embed::iterator (Content::Type mask, bool atEnd)
@@ -266,7 +266,7 @@ void Resource::setDisplayed (bool displayed)
{
}
-void Resource::draw (View *view, Rectangle *area)
+void Resource::draw (View *view, Rectangle *area, DrawingContext *context)
{
}
@@ -317,7 +317,7 @@ Iterator *LabelButtonResource::iterator (Content::Type mask, bool atEnd)
void ComplexButtonResource::LayoutReceiver::resizeQueued (bool extremesChanged)
{
- DBG_OBJ_ENTER ("resize", 0, "LayoutReceiver/resizeQueued", "%s",
+ DBG_OBJ_ENTER ("resize", 0, "LayoutReceiver::resizeQueued", "%s",
extremesChanged ? "true" : "false");
resource->queueResize (extremesChanged);
DBG_OBJ_LEAVE ();
diff --git a/dw/ui.hh b/dw/ui.hh
index c64880b4..62ffe3a6 100644
--- a/dw/ui.hh
+++ b/dw/ui.hh
@@ -228,8 +228,8 @@ private:
Resource *resource;
protected:
- void sizeRequestImpl (Requisition *requisition);
- void getExtremesImpl (Extremes *extremes);
+ void sizeRequestSimpl (Requisition *requisition);
+ void getExtremesSimpl (Extremes *extremes);
void sizeAllocateImpl (Allocation *allocation);
int getAvailWidthOfChild (Widget *child, bool forceValue);
@@ -254,7 +254,7 @@ public:
void setDisplayed (bool displayed);
void setEnabled (bool enabled);
- void draw (View *view, Rectangle *area);
+ void draw (View *view, Rectangle *area, DrawingContext *context);
Iterator *iterator (Content::Type mask, bool atEnd);
void setStyle (style::Style *style);
@@ -369,7 +369,7 @@ public:
virtual void containerSizeChangedForChildren ();
virtual void setDisplayed (bool displayed);
- virtual void draw (View *view, Rectangle *area);
+ virtual void draw (View *view, Rectangle *area, DrawingContext *context);
virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
virtual void setStyle (style::Style *style);
diff --git a/dw/widget.cc b/dw/widget.cc
index 464459ba..1e538eb0 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -91,6 +91,8 @@ Widget::Widget ()
deleteCallbackFunc = NULL;
widgetImgRenderer = NULL;
+
+ stackingContextMgr = NULL;
}
Widget::~Widget ()
@@ -104,6 +106,9 @@ Widget::~Widget ()
delete widgetImgRenderer;
}
+ if (stackingContextMgr)
+ delete stackingContextMgr;
+
if (style)
style->unref ();
@@ -117,35 +122,111 @@ Widget::~Widget ()
/**
- * \brief Calculates the intersection of widget->allocation and area, returned
- * in intersection (in widget coordinates!).
+ * \brief Calculates the intersection of the visible allocation
+ * (i. e. the intersection with the visible parent allocation) and
+ * "area" (in widget coordinates referring to "refWidget"),
+ * returned in intersection (in widget coordinates).
*
- * Typically used by containers when
- * drawing their children. Returns whether intersection is not empty.
+ * Typically used by containers when drawing their children (passing
+ * "this" as "refWidget"). Returns whether intersection is not empty.
*/
-bool Widget::intersects (Rectangle *area, Rectangle *intersection)
+bool Widget::intersects (Widget *refWidget, Rectangle *area,
+ Rectangle *intersection)
{
- Rectangle parentArea, childArea;
+ DBG_OBJ_ENTER ("draw", 0, "intersects", "%p, [%d, %d, %d * %d]",
+ refWidget, area->x, area->y, area->width, area->height);
+ bool r;
- parentArea = *area;
- parentArea.x += parent->allocation.x;
- parentArea.y += parent->allocation.y;
+ if (wasAllocated ()) {
+ *intersection = *area;
+ intersection->x += refWidget->allocation.x;
+ intersection->y += refWidget->allocation.y;
+
+ r = true;
+ // "RefWidget" is excluded; it is assumed that "area" its already within
+ // its allocation.
+ for (Widget *widget = this; r && widget != refWidget;
+ widget = widget->parent) {
+ assert (widget != NULL); // refWidget must be ancestor.
+
+ Rectangle widgetArea, newIntersection;
+ widgetArea.x = widget->allocation.x;
+ widgetArea.y = widget->allocation.y;
+ widgetArea.width = widget->allocation.width;
+ widgetArea.height = widget->getHeight ();
+
+ if (intersection->intersectsWith (&widgetArea, &newIntersection)) {
+ DBG_OBJ_MSGF ("draw", 1, "new intersection: %d, %d, %d * %d",
+ newIntersection.x, newIntersection.y,
+ newIntersection.width, newIntersection.height);
+ *intersection = newIntersection;
+ } else {
+ DBG_OBJ_MSG ("draw", 1, "no new intersection");
+ r = false;
+ }
+ }
- childArea.x = allocation.x;
- childArea.y = allocation.y;
- childArea.width = allocation.width;
- childArea.height = getHeight ();
+ if (r) {
+ intersection->x -= allocation.x;
+ intersection->y -= allocation.y;
- if (parentArea.intersectsWith (&childArea, intersection)) {
- intersection->x -= allocation.x;
- intersection->y -= allocation.y;
- return true;
- } else
- return false;
+ DBG_OBJ_MSGF ("draw", 1, "final intersection: %d, %d, %d * %d",
+ intersection->x, intersection->y,
+ intersection->width, intersection->height);
+ }
+ } else {
+ r = false;
+ DBG_OBJ_MSG ("draw", 1, "not allocated");
+ }
+
+ if (r)
+ DBG_OBJ_MSGF ("draw", 1, "=> true: %d, %d, %d * %d",
+ intersection->x, intersection->y,
+ intersection->width, intersection->height);
+ else
+ DBG_OBJ_MSG ("draw", 1, "=> false");
+
+ DBG_OBJ_LEAVE ();
+ return r;
+}
+
+/**
+ * See \ref dw-interrupted-drawing for details.
+ */
+void Widget::drawInterruption (View *view, Rectangle *area,
+ DrawingContext *context)
+{
+ Rectangle thisArea;
+ if (intersects (layout->topLevel, context->getToplevelArea (), &thisArea))
+ draw (view, &thisArea, context);
+
+ context->addWidgetProcessedAsInterruption (this);
+}
+
+Widget *Widget::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context)
+{
+ // Suitable for simple widgets, without children.
+
+ if (inAllocation (x, y))
+ return this;
+ else
+ return NULL;
+}
+
+Widget *Widget::getWidgetAtPointInterrupted (int x, int y,
+ GettingWidgetAtPointContext
+ *context)
+{
+ Widget *widgetAtPoint = getWidgetAtPoint (x, y, context);
+ context->addWidgetProcessedAsInterruption (this);
+ return widgetAtPoint;
}
void Widget::setParent (Widget *parent)
{
+ DBG_OBJ_ENTER ("construct", 0, "setParent", "%p", parent);
+
this->parent = parent;
layout = parent->layout;
@@ -170,7 +251,21 @@ void Widget::setParent (Widget *parent)
// Textblock.
DBG_OBJ_SET_PTR ("container", container);
+ // If at all, stackingContextMgr should have set *before*, see also
+ // Widget::setStyle() and Layout::addWidget().
+ if (stackingContextMgr) {
+ Widget *stackingContextWidget = parent;
+ while (stackingContextWidget &&
+ stackingContextWidget->stackingContextMgr == NULL)
+ stackingContextWidget = stackingContextWidget->parent;
+ assert (stackingContextWidget);
+ stackingContextWidget->stackingContextMgr->addChildSCWidget (this);
+ } else
+ stackingContextWidget = parent->stackingContextWidget;
+
notifySetParent();
+
+ DBG_OBJ_LEAVE ();
}
void Widget::setQuasiParent (Widget *quasiParent)
@@ -472,11 +567,12 @@ bool Widget::usesAvailHeight ()
* \brief This method is a wrapper for Widget::sizeRequestImpl(); it calls
* the latter only when needed.
*/
-void Widget::sizeRequest (Requisition *requisition)
+void Widget::sizeRequest (Requisition *requisition, int numPos,
+ Widget **references, int *x, int *y)
{
assert (!queueResizeEntered ());
- DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+ DBG_OBJ_ENTER ("resize", 0, "sizeRequest", "%d, ...", numPos);
enterSizeRequest ();
@@ -490,8 +586,9 @@ void Widget::sizeRequest (Requisition *requisition)
}
if (needsResize ()) {
+ calcExtraSpace ();
/** \todo Check requisition == &(this->requisition) and do what? */
- sizeRequestImpl (requisition);
+ sizeRequestImpl (requisition, numPos, references, x, y);
this->requisition = *requisition;
unsetFlags (NEEDS_RESIZE);
@@ -519,7 +616,7 @@ int Widget::getMinWidth (Extremes *extremes, bool forceValue)
{
DBG_IF_RTFL {
if (extremes)
- DBG_OBJ_ENTER ("resize", 0, "getMinWidth", "[%d (%d) / %d (%d), %s",
+ DBG_OBJ_ENTER ("resize", 0, "getMinWidth", "[%d (%d) / %d (%d)], %s",
extremes->minWidth, extremes->minWidthIntrinsic,
extremes->maxWidth, extremes->maxWidthIntrinsic,
forceValue ? "true" : "false");
@@ -627,7 +724,7 @@ int Widget::getAvailHeight (bool forceValue)
} else if (style::isPerLength (getStyle()->height)) {
DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
100 * style::perLengthVal_useThisOnlyForDebugging
- (getStyle()->height));
+ (getStyle()->height));
// Notice that here -- unlike getAvailWidth() --
// layout->hScrollbarThickness is not considered here;
// something like canvasWidthGreater (analogue to
@@ -891,7 +988,8 @@ int Widget::calcHeight (style::Length cssValue, bool usePercentage,
/**
* \brief Wrapper for Widget::getExtremesImpl().
*/
-void Widget::getExtremes (Extremes *extremes)
+void Widget::getExtremes (Extremes *extremes, int numPos, Widget **references,
+ int *x, int *y)
{
assert (!queueResizeEntered ());
@@ -909,10 +1007,12 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ calcExtraSpace ();
+
// For backward compatibility (part 1/2):
extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
- getExtremesImpl (extremes);
+ getExtremesImpl (extremes, numPos, references, x, y);
// For backward compatibility (part 2/2):
if (extremes->minWidthIntrinsic == -1)
@@ -939,6 +1039,45 @@ void Widget::getExtremes (Extremes *extremes)
}
/**
+ * \brief Calculates dw::core::Widget::extraSpace.
+ *
+ * Delegated to dw::core::Widget::calcExtraSpaceImpl. Called both from
+ * dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes.
+ */
+void Widget::calcExtraSpace ()
+{
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+ calcExtraSpaceImpl ();
+
+ DBG_OBJ_SET_NUM ("extraSpace.top", extraSpace.top);
+ DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom);
+ DBG_OBJ_SET_NUM ("extraSpace.left", extraSpace.left);
+ DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right);
+}
+
+int Widget::numSizeRequestReferences ()
+{
+ return 0;
+}
+
+Widget *Widget::sizeRequestReference (int index)
+{
+ misc::assertNotReached ();
+ return NULL;
+}
+
+int Widget::numGetExtremesReferences ()
+{
+ return 0;
+}
+
+Widget *Widget::getExtremesReference (int index)
+{
+ misc::assertNotReached ();
+ return NULL;
+}
+
+/**
* \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when
* needed.
*/
@@ -1082,6 +1221,16 @@ void Widget::setStyle (style::Style *style)
layout->updateCursor ();
}
+ // After Layout::addWidget() (as toplevel widget) or Widget::setParent()
+ // (which also sets layout), changes of the style cannot be considered
+ // anymore. (Should print a warning?)
+ if (layout == NULL &&
+ StackingContextMgr::isEstablishingStackingContext (this)) {
+ stackingContextMgr = new StackingContextMgr (this);
+ DBG_OBJ_ASSOC_CHILD (stackingContextMgr);
+ stackingContextWidget = this;
+ }
+
if (sizeChanged)
queueResize (0, true);
else
@@ -1196,7 +1345,7 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area,
// TODO Handle inverse drawing the same way as in drawWidgetBox?
// Maybe this method (drawBox) is anyway obsolete when extraSpace
- // is fully supported (as in the "dillo_grows" repository).
+ // is fully supported (as here, in the "dillo_grows" repository).
int xPad, yPad, widthPad, heightPad;
getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
@@ -1226,8 +1375,10 @@ void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse)
canvasArea.width = area->width;
canvasArea.height = area->height;
- style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y,
- allocation.width, getHeight (), style, inverse);
+ int xMar, yMar, widthMar, heightMar;
+ getMarginArea (&xMar, &yMar, &widthMar, &heightMar);
+ style::drawBorder (view, layout, &canvasArea, xMar, yMar, widthMar,
+ heightMar, style, inverse);
int xPad, yPad, widthPad, heightPad;
getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
@@ -1363,53 +1514,6 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
return widget1;
}
-
-/**
- * \brief Search recursively through widget.
- *
- * Used by dw::core::Layout:getWidgetAtPoint.
- */
-Widget *Widget::getWidgetAtPoint (int x, int y, int level)
-{
- Iterator *it;
- Widget *childAtPoint;
-
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
- if (x >= allocation.x &&
- y >= allocation.y &&
- x <= allocation.x + allocation.width &&
- y <= allocation.y + getHeight ()) {
- //_MSG ("%*s -> inside\n", 3 * level, "");
- /*
- * Iterate over the children of this widget. Test recursively, whether
- * the point is within the child (or one of its children...). If there
- * is such a child, it is returned. Otherwise, this widget is returned.
- */
- childAtPoint = NULL;
- it = iterator ((Content::Type)
- (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
- false);
-
- while (childAtPoint == NULL && it->next ()) {
- Widget *child = it->getContent()->widget;
- if (child->wasAllocated ())
- childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
- }
-
- it->unref ();
-
- if (childAtPoint)
- return childAtPoint;
- else
- return this;
- } else
- return NULL;
-}
-
-
void Widget::scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height)
{
@@ -1417,6 +1521,24 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos,
x + allocation.x, y + allocation.y, width, height);
}
+void Widget::getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar)
+{
+ *xMar = allocation.x + extraSpace.left;
+ *yMar = allocation.y + extraSpace.top;
+ *widthMar = allocation.width - (extraSpace.left + extraSpace.right);
+ *heightMar = getHeight () - (extraSpace.top + extraSpace.bottom);
+}
+
+void Widget::getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor)
+{
+ getMarginArea (xBor, yBor, widthBor, heightBor);
+
+ *xBor += style->margin.left;
+ *yBor += style->margin.top;
+ *widthBor -= style->margin.left + style->margin.right;
+ *heightBor -= style->margin.top + style->margin.bottom;
+}
+
/**
* \brief Return the padding area (content plus padding).
*
@@ -1426,18 +1548,57 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos,
void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad,
int *heightPad)
{
- *xPad = allocation.x + style->margin.left + style->borderWidth.left;
- *yPad = allocation.y + style->margin.top + style->borderWidth.top;
- *widthPad = allocation.width - style->margin.left - style->borderWidth.left
- - style->margin.right - style->borderWidth.right;
- *heightPad = getHeight () - style->margin.top - style->borderWidth.top
- - style->margin.bottom - style->borderWidth.bottom;
+ getBorderArea (xPad, yPad, widthPad, heightPad);
+
+ *xPad += style->borderWidth.left;
+ *yPad += style->borderWidth.top;
+ *widthPad -= style->borderWidth.left + style->borderWidth.right;
+ *heightPad -= style->borderWidth.top + style->borderWidth.bottom;
+}
+
+void Widget::sizeRequestImpl (Requisition *requisition, int numPos,
+ Widget **references, int *x, int *y)
+{
+ // Use the simple variant.
+ sizeRequestSimpl (requisition);
+}
+
+void Widget::sizeRequestSimpl (Requisition *requisition)
+{
+ // Either variant should be implemented.
+ misc::assertNotReached ();
+}
+
+void Widget::getExtremesImpl (Extremes *extremes, int numPos,
+ Widget **references, int *x, int *y)
+{
+ // Use the simple variant.
+ getExtremesSimpl (extremes);
+}
+
+void Widget::getExtremesSimpl (Extremes *extremes)
+{
+ // Either variant should be implemented.
+ misc::assertNotReached ();
}
void Widget::sizeAllocateImpl (Allocation *allocation)
{
}
+/**
+ * \brief The actual implementation for calculating
+ * dw::core::Widget::extraSpace.
+ *
+ * The implementation gets a clean value of
+ * dw::core::Widget::extraSpace, which is only corrected. To make sure
+ * all possible influences are considered, the implementation of the
+ * base class should be called, too.
+ */
+void Widget::calcExtraSpaceImpl ()
+{
+}
+
void Widget::markSizeChange (int ref)
{
}
@@ -1753,6 +1914,7 @@ void Widget::leaveNotifyImpl (EventCrossing *)
tooltip->onLeave();
}
+
void Widget::removeChild (Widget *child)
{
// Should be implemented.
diff --git a/dw/widget.hh b/dw/widget.hh
index f9d1293c..5db9aa33 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -180,19 +180,36 @@ protected:
Allocation allocation;
inline int getHeight () { return allocation.ascent + allocation.descent; }
- inline int getContentWidth() { return allocation.width
- - style->boxDiffWidth (); }
- inline int getContentHeight() { return getHeight ()
- - style->boxDiffHeight (); }
+ inline int getContentWidth() { return allocation.width - boxDiffWidth (); }
+ inline int getContentHeight() { return getHeight () - boxDiffHeight (); }
Layout *layout;
/**
* \brief Space around the margin box. Allocation is extraSpace +
- * margin + border + padding + contents;
+ * margin + border + padding + contents.
+ *
+ * See also dw::core::Widget::calcExtraSpace and
+ * dw::core::Widget::calcExtraSpaceImpl. Also, it is feasible to
+ * correct this value within dw::core::Widget::sizeRequestImpl.
*/
style::Box extraSpace;
+ /**
+ * \brief Set iff this widget constitutes a stacking context, as defined by
+ * CSS.
+ */
+ StackingContextMgr *stackingContextMgr;
+
+ /**
+ * \brief The bottom-most ancestor (or this) for which stackingContextMgr is
+ * set.
+ */
+ Widget *stackingContextWidget;
+
+ inline StackingContextMgr *getNextStackingContextMgr ()
+ { return stackingContextWidget->stackingContextMgr; }
+
/*inline void printFlags () {
DBG_IF_RTFL {
char buf[10 * 3 - 1 + 1];
@@ -254,7 +271,6 @@ protected:
inline void unsetFlags (Flags f)
{ flags = (Flags)(flags & ~f); printFlag (f); }
-
inline void queueDraw ()
{ queueDrawArea (0, 0, allocation.width, getHeight()); }
void queueDrawArea (int x, int y, int width, int height);
@@ -264,12 +280,28 @@ protected:
/**
* \brief See \ref dw-widget-sizes.
*/
- virtual void sizeRequestImpl (Requisition *requisition) = 0;
+ virtual void sizeRequestImpl (Requisition *requisition, int numPos,
+ Widget **references, int *x, int *y);
+
+ /**
+ * \brief Simple variant, to be implemented by widgets with sizes
+ * not depending on positions.
+ */
+ virtual void sizeRequestSimpl (Requisition *requisition);
/**
* \brief See \ref dw-widget-sizes.
*/
- virtual void getExtremesImpl (Extremes *extremes) = 0;
+ virtual void getExtremesImpl (Extremes *extremes, int numPos,
+ Widget **references, int *x, int *y);
+
+ /**
+ * \brief Simple variant, to be implemented by widgets with
+ * extremes not depending on positions.
+ */
+ virtual void getExtremesSimpl (Extremes *extremes);
+
+ virtual void calcExtraSpaceImpl ();
/**
* \brief See \ref dw-widget-sizes.
@@ -292,8 +324,6 @@ protected:
*/
virtual void markExtremesChange (int ref);
- int getMinWidth (Extremes *extremes, bool forceValue);
-
virtual int getAvailWidthOfChild (Widget *child, bool forceValue);
virtual int getAvailHeightOfChild (Widget *child, bool forceValue);
virtual void correctRequisitionOfChild (Widget *child,
@@ -410,6 +440,11 @@ public:
inline style::Style *getStyle () { return style; }
/** \todo I do not like this. */
inline Allocation *getAllocation () { return &allocation; }
+ inline bool inAllocation (int x, int y) {
+ return wasAllocated () && x >= allocation.x && y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ();
+ }
inline int boxOffsetX ()
{ return extraSpace.left + getStyle()->boxOffsetX (); }
@@ -421,11 +456,35 @@ public:
inline int boxRestHeight ()
{ return extraSpace.bottom + getStyle()->boxRestHeight (); }
inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
+
+ /**
+ * \brief See \ref dw-widget-sizes (or \ref dw-size-request-pos).
+ */
+ virtual int numSizeRequestReferences ();
+
+ /**
+ * \brief See \ref dw-widget-sizes (or \ref dw-size-request-pos).
+ */
+ virtual Widget *sizeRequestReference (int index);
+
+ /**
+ * \brief See \ref dw-widget-sizes (or \ref dw-size-request-pos).
+ */
+ virtual int numGetExtremesReferences ();
- void sizeRequest (Requisition *requisition);
- void getExtremes (Extremes *extremes);
+ /**
+ * \brief See \ref dw-widget-sizes (or \ref dw-size-request-pos).
+ */
+ virtual Widget *getExtremesReference (int index);
+
+ void sizeRequest (Requisition *requisition, int numPos = 0,
+ Widget **references = NULL, int *x = NULL, int *y = NULL);
+ void getExtremes (Extremes *extremes, int numPos = 0,
+ Widget **references = NULL, int *x = NULL, int *y = NULL);
void sizeAllocate (Allocation *allocation);
+ void calcExtraSpace ();
+
int getAvailWidth (bool forceValue);
int getAvailHeight (bool forceValue);
virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; }
@@ -442,15 +501,24 @@ public:
virtual int applyPerWidth (int containerWidth, style::Length perWidth);
virtual int applyPerHeight (int containerHeight, style::Length perHeight);
+ int getMinWidth (Extremes *extremes, bool forceValue);
+
virtual bool isBlockLevel ();
virtual bool isPossibleContainer ();
void containerSizeChanged ();
- bool intersects (Rectangle *area, Rectangle *intersection);
+ bool intersects (Widget *refWidget, Rectangle *area,
+ Rectangle *intersection);
/** Area is given in widget coordinates. */
- virtual void draw (View *view, Rectangle *area) = 0;
+ virtual void draw (View *view, Rectangle *area, DrawingContext *context) = 0;
+ void drawInterruption (View *view, Rectangle *area, DrawingContext *context);
+
+ virtual Widget *getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context);
+ Widget *getWidgetAtPointInterrupted (int x, int y,
+ GettingWidgetAtPointContext *context);
bool buttonPress (EventButton *event);
bool buttonRelease (EventButton *event);
@@ -481,11 +549,11 @@ public:
inline Layout *getLayout () { return layout; }
- virtual Widget *getWidgetAtPoint (int x, int y, int level);
-
void scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height);
+ void getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar);
+ void getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor);
void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad);
/**
@@ -502,6 +570,7 @@ public:
* dw::core::Iterator::prev in this case.
*/
virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+
virtual void removeChild (Widget *child);
};
diff --git a/lout/debug.hh b/lout/debug.hh
index e2839196..5c0169e3 100644
--- a/lout/debug.hh
+++ b/lout/debug.hh
@@ -29,359 +29,7 @@
# define DEBUG_MSG(level, ...)
# endif /* DEBUG_LEVEL */
-
-
-/*
- * See <http://home.gna.org/rtfl/>.
- */
-
-#ifdef DBG_RTFL
-
-#include <unistd.h>
-#include <stdio.h>
-
-#define DBG_IF_RTFL if(1)
-
-// "\n" at the beginning just in case that the previous line is not finished
-// yet.
-#define RTFL_PREFIX_FMT "\n[rtfl]%s:%d:%d:"
-#define RTFL_PREFIX_ARGS CUR_WORKING_DIR "/" __FILE__, __LINE__, getpid()
-
-#define DBG_OBJ_MSG(aspect, prio, msg) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, msg); \
- fflush (stdout); \
- } D_STMT_END
-
-// Variant which does not use "this", but an explicitly passed
-// object. Should be applied to other macros. (Also, for use in C.)
-#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, msg); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, __VA_ARGS__); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, __VA_ARGS__); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSG_START() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSG_START_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSG_END() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSG_END_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER0(aspect, prio, funname) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, funname); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, funname); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
- D_STMT_START { \
- fflush (stdout); \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, funname, __VA_ARGS__); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
- D_STMT_START { \
- fflush (stdout); \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, funname, __VA_ARGS__); \
- } D_STMT_END
-
-#define DBG_OBJ_LEAVE() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_LEAVE_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_CREATE(klass) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-create:%p:%s\n", \
- RTFL_PREFIX_ARGS, this, klass); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_DELETE() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-delete:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_BASECLASS(klass) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-ident:%p:%p\n", \
- RTFL_PREFIX_ARGS, this, (klass*)this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC(parent, child) \
- D_STMT_START { \
- if (child) { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, parent, child); \
- fflush (stdout); \
- } \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC_PARENT(parent) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, parent, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC_CHILD(child) \
- D_STMT_START { \
- if (child) { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, this, child); \
- fflush (stdout); \
- } \
- } D_STMT_END
-
-#define DBG_OBJ_SET_NUM(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_NUM_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
- RTFL_PREFIX_ARGS, obj, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_SYM(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_STR(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_PTR(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_PTR_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
- RTFL_PREFIX_ARGS, obj, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_BOOL(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, obj, var, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_COL(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:#%06x\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%d\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_STR(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%p\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%d\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%p\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_COLOR(klass, color) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-color:%s:%s\n", \
- RTFL_PREFIX_ARGS, color, klass); \
- fflush (stdout); \
- } D_STMT_END
-
-#else /* DBG_RTFL */
-
-#define DBG_IF_RTFL if(0)
-
-#define DBG_OBJ_MSG(aspect, prio, msg) D_STMT_NOP
-#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) D_STMT_NOP
-#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_MSG_START() D_STMT_NOP
-#define DBG_OBJ_MSG_START_O(obj) D_STMT_NOP
-#define DBG_OBJ_MSG_END() D_STMT_NOP
-#define DBG_OBJ_MSG_END_O(obj) D_STMT_NOP
-#define DBG_OBJ_ENTER0(aspect, prio, funname) D_STMT_NOP
-#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) D_STMT_NOP
-#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_LEAVE() D_STMT_NOP
-#define DBG_OBJ_LEAVE_O(obj) D_STMT_NOP
-#define DBG_OBJ_CREATE(klass) D_STMT_NOP
-#define DBG_OBJ_DELETE() D_STMT_NOP
-#define DBG_OBJ_BASECLASS(klass) D_STMT_NOP
-#define DBG_OBJ_ASSOC_PARENT(parent) D_STMT_NOP
-#define DBG_OBJ_ASSOC_CHILD(child) D_STMT_NOP
-#define DBG_OBJ_ASSOC(parent, child) D_STMT_NOP
-#define DBG_OBJ_SET_NUM(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_NUM_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_SYM(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_STR(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_PTR(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_PTR_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_BOOL(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_BOOL_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_COL(var, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_NUM(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_SYM(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_STR(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_PTR(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_BOOL(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_COLOR(klass, color) D_STMT_NOP
-
-#endif /* DBG_RTFL */
+#include "debug_rtfl.hh"
#endif /* __LOUT_DEBUG_H__ */
diff --git a/lout/debug_rtfl.hh b/lout/debug_rtfl.hh
new file mode 100644
index 00000000..616424c2
--- /dev/null
+++ b/lout/debug_rtfl.hh
@@ -0,0 +1,410 @@
+// WARNING: This file has been generated. Do not edit!
+
+/*
+ * This file is part of RTFL, see <http://home.gna.org/rtfl/>
+ * for details.
+ *
+ * This file (but not RTFL itself) is in the public domain, since it is only a
+ * simple implementation of a protocol, containing nothing more than trivial
+ * work. However, it would be nice to keep this notice, along with the URL
+ * above.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Defines macros for printing RTFL commands. See documentation for detail
+ * (online at <http://home.gna.org/rtfl/doc/rtfl.html>). These macros are only
+ * active, when the pre-processor variable DBG_RTFL is defined. If not,
+ * alternatives are defined, which have no effect.
+ *
+ * This variant assumes that __FILE__ is only the base of the source file name,
+ * so, to get the full path, CUR_WORKING_DIR has to be defined. See RTFL
+ * documentation for more details.
+ */
+
+#ifndef __DEBUG_RTFL_HH__
+#define __DEBUG_RTFL_HH__
+
+#ifdef DBG_RTFL
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define DBG_IF_RTFL if(1)
+
+#define STMT_START do
+#define STMT_END while (0)
+
+// Prints an RTFL message to stdout. "fmt" contains simple format
+// characters how to deal with the additional arguments (no "%"
+// preceeding, as in printf), or "c" (short for "#%06x" and used for
+// colors), or other characters, which are simply printed. No quoting:
+// this function cannot be used to print the characters "d", "p", and
+// "s" directly.
+
+inline void rtfl_print (const char *module, const char *version,
+ const char *file, int line, const char *fmt, ...)
+{
+ // "\n" at the beginning just in case that the previous line is not
+ // finished yet.
+ printf ("\n[rtfl-%s-%s]%s:%d:%d:", module, version, file, line, getpid ());
+
+ va_list args;
+ va_start (args, fmt);
+
+ for (int i = 0; fmt[i]; i++) {
+ int n;
+ void *p;
+ char *s;
+
+ switch (fmt[i]) {
+ case 'd':
+ n = va_arg(args, int);
+ printf ("%d", n);
+ break;
+
+ case 'p':
+ p = va_arg(args, void*);
+ printf ("%p", p);
+ break;
+
+ case 's':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ putchar (s[j]);
+ }
+ break;
+
+ case 'c':
+ n = va_arg(args, int);
+ printf ("#%06x", n);
+ break;
+
+ default:
+ putchar (fmt[i]);
+ break;
+ }
+ }
+
+ va_end (args);
+
+ putchar ('\n');
+ fflush (stdout);
+}
+
+#define RTFL_PRINT(module, version, cmd, fmt, ...) \
+ rtfl_print (module, version, CUR_WORKING_DIR "/" __FILE__, __LINE__, \
+ "s:" fmt, cmd, __VA_ARGS__)
+
+#define RTFL_OBJ_VERSION "1.0"
+
+#define RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("obj", RTFL_OBJ_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) \
+ DBG_OBJ_MSG_O (aspect, prio, this, msg)
+
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
+ RTFL_OBJ_PRINT ("msg", "p:s:d:s", obj, aspect, prio, msg)
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG (aspect, prio, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG_O (aspect, prio, obj, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MARK(aspect, prio, mark) \
+ DBG_OBJ_MARK_O (aspect, prio, this, mark)
+
+#define DBG_OBJ_MARK_O(aspect, prio, obj, mark) \
+ RTFL_OBJ_PRINT ("mark", "p:s:d:s", obj, aspect, prio, mark)
+
+#define DBG_OBJ_MARKF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK (aspect, prio, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MARKF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK_O (aspect, prio, obj, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MSG_START() \
+ DBG_OBJ_MSG_START_O (this)
+
+#define DBG_OBJ_MSG_START_O(obj) \
+ RTFL_OBJ_PRINT ("msg-start", "p", obj)
+
+#define DBG_OBJ_MSG_END() \
+ DBG_OBJ_MSG_END_O (this)
+
+#define DBG_OBJ_MSG_END_O(obj) \
+ RTFL_OBJ_PRINT ("msg-end", "p", obj)
+
+#define DBG_OBJ_ENTER0(aspect, prio, funname) \
+ DBG_OBJ_ENTER0_O (aspect, prio, this, funname)
+
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:", obj, aspect, prio, funname);
+
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", this, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", obj, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE() \
+ DBG_OBJ_LEAVE_O (this)
+
+#define DBG_OBJ_LEAVE_O(obj) \
+ RTFL_OBJ_PRINT ("leave", "p", obj);
+
+#define DBG_OBJ_LEAVE_VAL(fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", this, vals); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_VAL_O(obj, fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", obj, vals); \
+ } STMT_END
+
+#define DBG_OBJ_CREATE(klass) \
+ DBG_OBJ_CREATE_O (this, klass)
+
+#define DBG_OBJ_CREATE_O(obj, klass) \
+ RTFL_OBJ_PRINT ("create", "p:s", obj, klass);
+
+#define DBG_OBJ_DELETE() \
+ DBG_OBJ_DELETE_O (this)
+
+#define DBG_OBJ_DELETE_O(obj) \
+ RTFL_OBJ_PRINT ("delete", "p", obj);
+
+#define DBG_OBJ_BASECLASS(klass) \
+ RTFL_OBJ_PRINT ("ident", "p:p", this, (klass*)this);
+
+#define DBG_OBJ_ASSOC(parent, child) \
+ RTFL_OBJ_PRINT ("assoc", "p:p", parent, child); \
+
+#define DBG_OBJ_ASSOC_PARENT(parent) \
+ DBG_OBJ_ASSOC (parent, this);
+
+#define DBG_OBJ_ASSOC_CHILD(child) \
+ DBG_OBJ_ASSOC (this, child);
+
+#define DBG_OBJ_SET_NUM(var, val) \
+ DBG_OBJ_SET_NUM_O (this, var, val)
+
+#define DBG_OBJ_SET_NUM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:d", obj, var, val)
+
+#define DBG_OBJ_SET_SYM(var, val) \
+ DBG_OBJ_SET_SYM_O (this, var, val)
+
+#define DBG_OBJ_SET_SYM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, val)
+
+#define DBG_OBJ_SET_BOOL(var, val) \
+ DBG_OBJ_SET_BOOL_O (this, var, val)
+
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, (val) ? "true" : "false")
+
+#define DBG_OBJ_SET_STR(var, val) \
+ DBG_OBJ_SET_STR_O (this, var, val)
+
+#define DBG_OBJ_SET_STR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:\"s\"", obj, var, val)
+
+#define DBG_OBJ_SET_PTR(var, val) \
+ DBG_OBJ_SET_PTR_O (this, var, val)
+
+#define DBG_OBJ_SET_PTR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:p", obj, var, val)
+
+#define DBG_OBJ_SET_COL(var, val) \
+ DBG_OBJ_SET_COL_O (this, var, val)
+
+#define DBG_OBJ_SET_COL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:c", obj, var, val)
+
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
+ DBG_OBJ_ARRSET_NUM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:d", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
+ DBG_OBJ_ARRSET_SYM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
+ DBG_OBJ_ARRSET_BOOL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRSET_STR(var, ind, val) \
+ DBG_OBJ_ARRSET_STR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:\"s\"", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
+ DBG_OBJ_ARRSET_PTR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:p", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL(var, ind, val) \
+ DBG_OBJ_ARRSET_COL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:c", obj, var, ind, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_NUM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:d", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_SYM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_BOOL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, \
+ (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_STR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:\"s\"", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_PTR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:p", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_COL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:c", obj, var, ind, attr, val)
+
+#define DBG_OBJ_CLASS_COLOR(klass, color) \
+ RTFL_OBJ_PRINT ("class-color", "s:s", klass, color)
+
+#else /* DBG_RTFL */
+
+#define STMT_NOP do { } while (0)
+
+#define DBG_IF_RTFL if(0)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) STMT_NOP
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) STMT_NOP
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_MARK(aspect, prio, mark) STMT_NOP
+#define DBG_OBJ_MARK_O(aspect, prio, obj, mark) STMT_NOP
+#define DBG_OBJ_MARKF(aspect, prio, fmt, ...) STMT_NOP
+#define DBG_OBJ_MARKF_O(aspect, prio, obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSG_START() STMT_NOP
+#define DBG_OBJ_MSG_START_O(obj) STMT_NOP
+#define DBG_OBJ_MSG_END() STMT_NOP
+#define DBG_OBJ_MSG_END_O(obj) STMT_NOP
+#define DBG_OBJ_ENTER0(aspect, prio, funname) STMT_NOP
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) STMT_NOP
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE() STMT_NOP
+#define DBG_OBJ_LEAVE_O(obj) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL(fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL_O(obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_CREATE(klass) STMT_NOP
+#define DBG_OBJ_CREATE_O(obj, klass) STMT_NOP
+#define DBG_OBJ_DELETE() STMT_NOP
+#define DBG_OBJ_DELETE_O(obj) STMT_NOP
+#define DBG_OBJ_BASECLASS(klass) STMT_NOP
+#define DBG_OBJ_ASSOC(parent, child) STMT_NOP
+#define DBG_OBJ_ASSOC_PARENT(parent) STMT_NOP
+#define DBG_OBJ_ASSOC_CHILD(child) STMT_NOP
+#define DBG_OBJ_SET_NUM(var, val) STMT_NOP
+#define DBG_OBJ_SET_NUM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM(var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL(var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_STR(var, val) STMT_NOP
+#define DBG_OBJ_SET_STR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR(var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_COL(var, val) STMT_NOP
+#define DBG_OBJ_SET_COL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_CLASS_COLOR(klass, color) STMT_NOP
+
+#endif /* DBG_RTFL */
+
+#endif /* __DEBUG_RTFL_HH__ */
diff --git a/lout/misc.hh b/lout/misc.hh
index 0a05db31..946ed821 100644
--- a/lout/misc.hh
+++ b/lout/misc.hh
@@ -64,6 +64,8 @@ inline int AsciiStrcasecmp(const char *s1, const char *s2)
return ret;
}
+inline const char *boolToStr (bool b) { return b ? "true" : "false"; }
+
/**
* \brief Simple (simpler than container::untyped::Vector and
* container::typed::Vector) template based vector.
@@ -118,6 +120,8 @@ public:
*/
inline int size() const { return this->num; }
+ inline bool empty() const { return size() == 0; }
+
inline T* getArray() const { return array; }
inline T* detachArray() {
@@ -378,6 +382,8 @@ public:
inline int size() const { return this->numMain + this->numExtra; }
+ inline bool empty() const { return size() == 0; }
+
inline void increase() { setSize(size() + 1); }
inline void setSize(int newSize)
diff --git a/src/cssparser.cc b/src/cssparser.cc
index 1487a605..b4a6a305 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -19,7 +19,6 @@
#include <stdlib.h>
#include <stdio.h>
-#include "lout/debug.hh"
#include "msg.h"
#include "colors.h"
#include "html_common.hh"
@@ -198,7 +197,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
Css_border_style_enum_vals},
{"border-top-width", {CSS_TYPE_ENUM, CSS_TYPE_LENGTH, CSS_TYPE_UNUSED},
Css_border_width_enum_vals},
- {"bottom", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"bottom", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"caption-side", {CSS_TYPE_UNUSED}, NULL},
{"clear", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_clear_enum_vals},
{"clip", {CSS_TYPE_UNUSED}, NULL},
@@ -222,7 +221,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"font-weight", {CSS_TYPE_ENUM, CSS_TYPE_FONT_WEIGHT, CSS_TYPE_UNUSED},
Css_font_weight_enum_vals},
{"height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
- {"left", {CSS_TYPE_UNUSED}, NULL},
+ {"left", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"letter-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_letter_spacing_enum_vals},
{"line-height",
@@ -261,7 +260,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"padding-top", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"position", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_position_enum_vals},
{"quotes", {CSS_TYPE_UNUSED}, NULL},
- {"right", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"right", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"text-align", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_text_align_enum_vals},
{"text-decoration", {CSS_TYPE_MULTI_ENUM, CSS_TYPE_UNUSED},
Css_text_decoration_enum_vals},
@@ -269,7 +268,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"text-shadow", {CSS_TYPE_UNUSED}, NULL},
{"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
Css_text_transform_enum_vals},
- {"top", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"top", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"unicode-bidi", {CSS_TYPE_UNUSED}, NULL},
{"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals},
{"visibility", {CSS_TYPE_UNUSED}, NULL},
@@ -277,7 +276,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
{"word-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_word_spacing_enum_vals},
- {"z-index", {CSS_TYPE_UNUSED}, NULL},
+ {"z-index", {CSS_TYPE_INTEGER, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
/* These are extensions, for internal used, and never parsed. */
{"x-link", {CSS_TYPE_INTEGER, CSS_TYPE_UNUSED}, NULL},
@@ -793,9 +792,12 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
return true;
break;
- case CSS_TYPE_UNUSED:
case CSS_TYPE_INTEGER:
- /* Not used for parser values. */
+ if (ttype == CSS_TK_DECINT)
+ return true;
+ break;
+
+ case CSS_TYPE_UNUSED:
default:
assert(false);
break;
@@ -1174,12 +1176,18 @@ bool CssParser::parseValue(CssPropertyName prop,
}
break;
+ case CSS_TYPE_INTEGER:
+ if (ttype == CSS_TK_DECINT) {
+ val->intVal = strtol(tval, NULL, 10);
+ ret = true;
+ nextToken();
+ }
+ break;
+
case CSS_TYPE_UNUSED:
/* nothing */
break;
- case CSS_TYPE_INTEGER:
- /* Not used for parser values. */
default:
assert(false); /* not reached */
}
diff --git a/src/dillo.cc b/src/dillo.cc
index 24271103..c7ae62c2 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -56,7 +56,6 @@
#include "auth.h"
#include "styleengine.hh"
-#include "lout/debug.hh"
#include "dw/fltkcore.hh"
#include "dw/widget.hh"
#include "dw/textblock.hh"
@@ -381,19 +380,6 @@ static DilloUrl *makeStartUrl(char *str, bool local)
*/
int main(int argc, char **argv)
{
- DBG_OBJ_COLOR ("dw::*", "#c0ff80");
- DBG_OBJ_COLOR ("dw::fltk::*", "#c0c0ff");
- DBG_OBJ_COLOR ("dw::core::*", "#ffa0a0");
- DBG_OBJ_COLOR ("dw::core::style::*", "#ffe0a0");
-
- DBG_OBJ_COLOR ("dw::Image", "#80ffa0");
- DBG_OBJ_COLOR ("dw::Textblock", "#f0ff80");
- DBG_OBJ_COLOR ("dw::OutOfFlowMgr", "#d0ff80");
- DBG_OBJ_COLOR ("dw::AlignedTextblock", "#e0ff80");
- DBG_OBJ_COLOR ("dw::ListItem", "#b0ff80");
- DBG_OBJ_COLOR ("dw::TableCell", "#80ff80");
- DBG_OBJ_COLOR ("dw::Table", "#80ffc0");
-
uint_t opt_id;
uint_t options_got = 0;
uint32_t xid = 0;
diff --git a/src/html.cc b/src/html.cc
index 75d1820f..e8d84738 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -380,9 +380,9 @@ static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace,
S_TOP(html)->hand_over_break = true;
}
-static bool Html_will_textblock_be_out_of_flow(DilloHtml *html)
+static bool Html_must_add_breaks(DilloHtml *html)
{
- return HT2TB(html)->isStyleOutOfFlow (html->style ());
+ return HT2TB(html)->mustAddBreaks (html->style ());
}
/*
@@ -3913,7 +3913,7 @@ static void Html_check_html5_obsolete(DilloHtml *html, int ni)
static void Html_display_block(DilloHtml *html)
{
- Html_add_textblock(html, !Html_will_textblock_be_out_of_flow (html), 0,
+ Html_add_textblock(html, Html_must_add_breaks (html), 0,
false /* Perhaps true for widgets oof? */);
}
diff --git a/src/styleengine.cc b/src/styleengine.cc
index c005f881..97ca417e 100644
--- a/src/styleengine.cc
+++ b/src/styleengine.cc
@@ -726,6 +726,12 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props,
case CSS_PROPERTY_MAX_HEIGHT:
computeLength (&attrs->maxHeight, p->value.intVal, attrs->font);
break;
+ case CSS_PROPERTY_Z_INDEX:
+ if (p->type == CSS_LENGTH_TYPE_AUTO)
+ attrs->zIndex = dw::core::style::Z_INDEX_AUTO;
+ else
+ attrs->zIndex = p->value.intVal;
+ break;
case PROPERTY_X_LINK:
attrs->x_link = p->value.intVal;
break;
diff --git a/test/Makefile.am b/test/Makefile.am
index 3b474466..fd3252dc 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -25,6 +25,7 @@ noinst_PROGRAMS = \
dw-resource-test \
dw-ui-test \
containers \
+ identity \
shapes \
cookies \
liang \
@@ -191,6 +192,9 @@ shapes_LDADD = \
containers_SOURCES = containers.cc
containers_LDADD = $(top_builddir)/lout/liblout.a
+identity_SOURCES = identity.cc
+identity_LDADD = $(top_builddir)/lout/liblout.a
+
cookies_SOURCES = cookies.c
cookies_LDADD = \
$(top_builddir)/dpip/libDpip.a \
diff --git a/test/dw_simple_container.cc b/test/dw_simple_container.cc
index ed7849dc..923642b1 100644
--- a/test/dw_simple_container.cc
+++ b/test/dw_simple_container.cc
@@ -32,7 +32,7 @@ int SimpleContainer::CLASS_ID = -1;
// ----------------------------------------------------------------------
SimpleContainer::SimpleContainerIterator::SimpleContainerIterator
- (SimpleContainer *simpleContainer, Content::Type mask, bool atEnd) :
+(SimpleContainer *simpleContainer, Content::Type mask, bool atEnd) :
Iterator (simpleContainer, mask, atEnd)
{
content.type = atEnd ? Content::END : Content::START;
@@ -63,7 +63,7 @@ int SimpleContainer::SimpleContainerIterator::index ()
}
int SimpleContainer::SimpleContainerIterator::compareTo
- (lout::object::Comparable *other)
+(lout::object::Comparable *other)
{
return index () - ((SimpleContainerIterator*)other)->index ();
}
@@ -160,7 +160,7 @@ SimpleContainer::~SimpleContainer ()
delete child;
}
-void SimpleContainer::sizeRequestImpl (Requisition *requisition)
+void SimpleContainer::sizeRequestSimpl (Requisition *requisition)
{
Requisition childReq;
if (child)
@@ -176,7 +176,7 @@ void SimpleContainer::sizeRequestImpl (Requisition *requisition)
}
-void SimpleContainer::getExtremesImpl (Extremes *extremes)
+void SimpleContainer::getExtremesSimpl (Extremes *extremes)
{
Extremes childExtr;
if (child)
@@ -208,12 +208,13 @@ void SimpleContainer::sizeAllocateImpl (Allocation *allocation)
}
}
-void SimpleContainer::draw (View *view, Rectangle *area)
+void SimpleContainer::draw (View *view, Rectangle *area,
+ DrawingContext *context)
{
drawWidgetBox (view, area, false);
Rectangle childArea;
- if (child && child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ if (child && child->intersects (this, area, &childArea))
+ child->draw (view, &childArea, context);
}
Iterator *SimpleContainer::iterator (Content::Type mask, bool atEnd)
diff --git a/test/dw_simple_container.hh b/test/dw_simple_container.hh
index fdb67bec..bd40b41e 100644
--- a/test/dw_simple_container.hh
+++ b/test/dw_simple_container.hh
@@ -34,8 +34,8 @@ private:
Widget *child;
protected:
- void sizeRequestImpl (core::Requisition *requisition);
- void getExtremesImpl (core::Extremes *extremes);
+ void sizeRequestSimpl (core::Requisition *requisition);
+ void getExtremesSimpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
public:
@@ -44,7 +44,8 @@ public:
SimpleContainer ();
~SimpleContainer ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::DrawingContext *context);
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
void removeChild (Widget *child);
diff --git a/test/identity.cc b/test/identity.cc
new file mode 100644
index 00000000..a1a136eb
--- /dev/null
+++ b/test/identity.cc
@@ -0,0 +1,55 @@
+/*
+ * This small program tests how IdentifiableObject works with multiple
+ * inheritance ("diamond" inheritance, more precisely, since all
+ * classes have there root in IdentifiableObject.)
+ *
+ * Current status: With virtual superclasses, you get a class
+ * hierarchie "root -> A -> B -> C", so that the first part of this
+ * example works actually (C is a subclass of A and of B), but the
+ * second fails (it should print "false", but it is erroneously
+ * assumed that B is a subclass of A.)
+ */
+
+#include "../lout/identity.hh"
+
+using namespace lout::identity;
+
+class A: virtual public IdentifiableObject
+{
+public:
+ static int CLASS_ID;
+ inline A () { registerName ("A", &CLASS_ID); }
+};
+
+class B: virtual public IdentifiableObject
+{
+public:
+ static int CLASS_ID;
+ inline B () { registerName ("B", &CLASS_ID); }
+};
+
+class C: public A, public B
+{
+public:
+ static int CLASS_ID;
+ inline C () { registerName ("C", &CLASS_ID); }
+};
+
+int A::CLASS_ID = -1, B::CLASS_ID = -1, C::CLASS_ID = -1;
+
+int main (int argc, char *argv[])
+{
+ printf ("A: %d, B: %d, C: %d\n", A::CLASS_ID, B::CLASS_ID, C::CLASS_ID);
+
+ C x;
+ assert (x.instanceOf (A::CLASS_ID));
+ assert (x.instanceOf (B::CLASS_ID));
+ assert (x.instanceOf (C::CLASS_ID));
+ printf ("x: %d\n", x.getClassId ());
+
+ B y;
+ printf ("y: %d; instance of A: %s\n",
+ y.getClassId (), y.instanceOf (B::CLASS_ID) ? "true" : "false");
+
+ return 0;
+}