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.doc49
-rw-r--r--devdoc/dw-out-of-flow-2.doc69
-rw-r--r--devdoc/dw-out-of-flow-floats.doc164
-rw-r--r--devdoc/dw-out-of-flow-positioned.doc66
-rw-r--r--devdoc/dw-out-of-flow.doc220
-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.doc171
-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.cc21
-rw-r--r--dw/alignedtablecell.hh4
-rw-r--r--dw/bullet.cc7
-rw-r--r--dw/bullet.hh7
-rw-r--r--dw/core.hh6
-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/imgbuf.hh4
-rw-r--r--dw/iterator.cc18
-rw-r--r--dw/iterator.hh2
-rw-r--r--dw/layout.cc42
-rw-r--r--dw/layout.hh7
-rw-r--r--dw/listitem.cc2
-rw-r--r--dw/listitem.hh2
-rw-r--r--dw/oofawarewidget.cc623
-rw-r--r--dw/oofawarewidget.hh306
-rw-r--r--dw/oofawarewidget_iterator.cc261
-rw-r--r--dw/ooffloatsmgr.cc1350
-rw-r--r--dw/ooffloatsmgr.hh287
-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.cc395
-rw-r--r--dw/oofpositionedmgr.hh139
-rw-r--r--dw/oofposrelmgr.cc249
-rw-r--r--dw/oofposrelmgr.hh50
-rw-r--r--dw/outofflowmgr.cc2261
-rw-r--r--dw/outofflowmgr.hh509
-rw-r--r--dw/regardingborder.hh7
-rw-r--r--dw/ruler.cc28
-rw-r--r--dw/ruler.hh14
-rw-r--r--dw/selection.cc102
-rw-r--r--dw/simpletablecell.cc17
-rw-r--r--dw/simpletablecell.hh4
-rw-r--r--dw/stackingcontextmgr.cc195
-rw-r--r--dw/stackingcontextmgr.hh76
-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.hh4
-rw-r--r--dw/textblock.cc1178
-rw-r--r--dw/textblock.hh241
-rw-r--r--dw/textblock_iterator.cc249
-rw-r--r--dw/textblock_linebreaking.cc513
-rw-r--r--dw/tools.cc192
-rw-r--r--dw/tools.hh66
-rw-r--r--dw/types.cc6
-rw-r--r--dw/types.hh80
-rw-r--r--dw/ui.cc20
-rw-r--r--dw/ui.hh8
-rw-r--r--dw/widget.cc384
-rw-r--r--dw/widget.hh112
-rw-r--r--lout/debug.hh354
-rw-r--r--lout/debug_rtfl.hh410
-rw-r--r--lout/misc.hh26
-rw-r--r--src/cssparser.cc28
-rw-r--r--src/dillo.cc14
-rw-r--r--src/html.cc21
-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
92 files changed, 9077 insertions, 4844 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 f90ea30b..9b7be947 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 (currently deactivated).
+ - Fixedly positioned elements (incomplete: referring to the canvas instead to
+ the viewport) (currently deactivated).
+ - "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..97e944d7
--- /dev/null
+++ b/devdoc/dw-miscellaneous.doc
@@ -0,0 +1,49 @@
+/** \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).
+
+Extra space
+-----------
+Should dw::core::Widget::calcExtraSpace be called from
+dw::core::Widget::getExtremes?
+
+*/
diff --git a/devdoc/dw-out-of-flow-2.doc b/devdoc/dw-out-of-flow-2.doc
deleted file mode 100644
index d9d70565..00000000
--- a/devdoc/dw-out-of-flow-2.doc
+++ /dev/null
@@ -1,69 +0,0 @@
-/** \page dw-out-of-flow-2 Handling Elements Out Of Flow (notes 2)
-
-This has to be integrated into \ref dw-out-of-flow.
-
-Constructing a page with floats
--------------------------------
-When a page is constructed (dw::Textblock::addWord), the *generating*
-block tells the positions of floats (or, generally, widgets out of
-flow) via dw::OutOfFlowMgr::tellPosition. This method considers
-already collisions with other floats (only previous floats; floats
-following this float are not considered); after the call,
-dw::OutOfFlowMgr::getBorder will return correct values.
-
-dw::OutOfFlowMgr::tellPosition also checks for overlaps of this float
-with other textblocks, except this textblock (the *generator*, which
-is just constructed, so nothing has to be done). The fact that the
-position of the float is the top, and so the float has only an
-allocation below this position, leads to the effect that only the
-textblocks following the generator are affected. (**Check:** Can the
-search be limited here?) When a page is constructed, no textblocks
-should be following the generating block, so no textblocks are
-affected.
-
-**Todo:** Clarify details of line breaking (\ref dw-line-breaking).
-
-Float changes its size
-----------------------
-The float itself will call queueResize, which will result in a call of
-markSizeChange for the *containing* block, which will then call
-dw::OutOfFlowMgr::markSizeChange. Here, the vloat is only *marked* as
-dirty; the size will be calculated later (in
-dw::OutOfFlowMgr::ensureFloatSize).
-
-This will trigger the resize idle function, so sizeRequest and
-sizeAllocate for all floats and textblocks. In this run,
-dw::OutOfFlowMgr::hasRelationChanged will return *true*, and so result
-in a call of dw::Textblock::borderChanged, and trigger a second run of
-the resize idle function, dealing correctly with the new size.
-
-(This case is handles in a not perfectly optimal way, since two runs
-of the resize idle function are neccessary; but size changes of floats
-is not a very common case.
-
-When a page is constructed (see above), a changing size of a float
-currently constructed typically only affects the most bottom
-textblock; the other textblocks are not covered by this float.)
-
-**Error:** In this case, new collisions are not yet considered.
-
-
-Changing the width of the page
-------------------------------
-
-When the page width is changed, this will result in a reconstruction
-of the page; see *Constructing a page with floats*. Anyway, checking
-for overlaps will play a more important role. This is handled in an
-optimal way by dw::OutOfFlowMgr::hasRelationChanged.
-
-**Check:** Are "cascades" avoided, like this:
-
-1. All textblocks are constructed. A float in textblock 1 overlaps
- with textblock 2, so dw::Textblock::borderChanged is called for
- textblock 2.
-2. In another resize idle run, textblock 2 is constructed again. A
- float in textblock 2 overlaps with textblock 3, so that
- dw::Textblock::borderChanged is called for textblock 3.
-3. Etc.
-
-*/ \ No newline at end of file
diff --git a/devdoc/dw-out-of-flow-floats.doc b/devdoc/dw-out-of-flow-floats.doc
index 53c6b220..2f92a5c6 100644
--- a/devdoc/dw-out-of-flow-floats.doc
+++ b/devdoc/dw-out-of-flow-floats.doc
@@ -1,73 +1,9 @@
/** \page dw-out-of-flow-floats Handling Elements Out Of Flow: Floats
-(Note: Bases on work at <http://flpsed.org/hgweb/dillo_grows>, I plan
-to split the documentation on elements out of flow into different
-parts: general part, floats, positioned elements. In this document,
-informations about floats are collected.)
+TODO: Much missing.
-
-GB lists and CB lists
-=====================
-
-Floats generated by a block which is not yet allocated are initially
-put into a list related to the *generator*:
-
-- dw::OutOfFlowMgr::TBInfo::leftFloatsGB or
-- dw::OutOfFlowMgr::TBInfo::rightFloatsGB.
-
-These lists are also called GB lists.
-
-Floats of allocated generators are put into lists related to the
-*container* (called CB lists):
-
-- dw::OutOfFlowMgr::leftFloatsCB or
-- dw::OutOfFlowMgr::rightFloatsCB.
-
-As soon as the container is allocated, all floats are moved from the
-GB lists to the CB lists (dw::OutOfFlowMgr::sizeAllocateStart →
-dw::OutOfFlowMgr::moveFromGBToCB).
-
-Here, it is important to preserve the *generation order* (for reasons,
-see below: *Sorting floats*), i. e. the order in which floats have
-been added (dw::OutOfFlowMgr::addWidgetOOF). This may become a bit
-more complicated in a case like this:
-
- <head>
- <style>
- \#fl-1, \#fl-2, \#fl-3 { float: right }
- </style>
- </head>
- <body>
- <div id="bl-1">
- <div id="fl-1">float 1</div>
- <div id="bl-2">
- <div id="fl-2">float 2</div>
- </div>
- <div id="fl-3">float 3</div>
- </div>
- </body>
-
-The floats are generated in this order:
-
-- \#fl-1 (generated by \#bl-1),
-- \#fl-2 (generated by \#bl-2),
-- \#fl-3 (generated by \#bl-1).
-
-Since the floats must be moved into the CB list in this order, it
-becomes clear that the floats from one GB list cannot be moved at
-once. For this reason, each float is assigned a "mark", which is
-different from the last one as soon as the generator is *before* the
-generator of the float added before. In the example above, there are
-three generators: body, \#bl-1, and \#bl-2 (in this order), and floats
-are assigned these marks:
-
-- \#fl-1: 0,
-- \#fl-2: also 0,
-- \#fl-3 is assigned 1, since its generator (\#bl-1) lies before the
- last generator (\#bl-2).
-
-dw::OutOfFlowMgr::moveFromGBToCB will then iterate over all marks, so
-that the generation order is preserved.
+(Historical) Note: Floats make use of dw-size-request-pos, which reduces the
+complexity of a previous design.
Sorting floats
@@ -118,4 +54,98 @@ block, for both floats and child blocks.
dw::OutOfFlowMgr::Float::ComparePosition ...
+
+Miscellaneous notes
+===================
+
+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?
+
+<b>Real-world cases:</b> *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.
+
+<b>Priority:</b> Since this is not a regression, compared to not
+supporting floats at all, a fix is not urgent for a new release.
+
+Resizing
+--------
+Has the case that a float changes its position to be regarded? Probably yes, but
+cases where no other mechanisms come into play are rather unlikely.
+
+<b>Priority:</b> If this plays a role, this means a regression compared to not
+supporting floats at all.
+
*/
diff --git a/devdoc/dw-out-of-flow-positioned.doc b/devdoc/dw-out-of-flow-positioned.doc
new file mode 100644
index 00000000..4f49b411
--- /dev/null
+++ b/devdoc/dw-out-of-flow-positioned.doc
@@ -0,0 +1,66 @@
+/** \page dw-out-of-flow-positioned Handling Elements Out Of Flow: Positioned Elements
+
+<div style="border: 2px solid #ffff00; margin: 1em 0; padding: 0.5em
+ 1em; background-color: #ffffe0">Positioned elements have been
+ deactivated, during the development of \ref dw-size-request-pos, to
+ focus on floats. See dw::core::IMPL_POS in file dw/core.hh.</div>
+
+
+Miscellaneous notes
+===================
+
+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..3dc7163b 100644
--- a/devdoc/dw-out-of-flow.doc
+++ b/devdoc/dw-out-of-flow.doc
@@ -1,14 +1,9 @@
/** \page dw-out-of-flow Handling Elements Out Of Flow
-
-<div style="border: 2px solid #ffff00; margin-bottom: 0.5em;
-padding: 0.5em 1em; background-color: #ffffe0"><b>Info:</b>
-Should be incorporated into dw::Textblock.</div>
-
Introduction
============
-This texts deals with both floats and absolute positions, which have
+This texts deals with both floats and positioned elements, which have
in common that there is a distinction between generating block and
containing block (we are here using the same notation as in the
CSS&nbsp;2 specification). Consider this snippet (regarding floats):
@@ -46,169 +41,58 @@ their borders, and so their size. In this example, the following list
item (green) must consider the position of the float. This is
discussed in detail in the next section.)
-Both in this text and the code, generating and containing block are
-abbreviated with **GB** and **CB**, respectively.
-
Implementation overview
=======================
-Widget level
-------------
-The terms *generating block* and *containing block* have been raised
-to a higher level, the one of dw::core::Widget, and are here called
-*generating widget* and *containing widget*. To represent the
-distinction, the type of dw::core::Content has been split into three
-parts:
-
-- If a widget is out of flow, the generating widget keeps a reference
- with the type dw::core::Content::WIDGET_OOF_REF, while the
- containing block refers to it as dw::core::Content::WIDGET_OOF_CONT.
-- For widgets within flow, dw::core::Content::WIDGET_IN_FLOW is used.
-
-Notice that in the first case, there are two pieces of content
-referring to the same widget.
-
-An application of this distinction is iterators. [TODO: more. And
-still missing: DeepIterator may need the generating parent widget in
-some cases.]
-
-
-Textblock level
----------------
-Both dw::Textblock::notifySetAsTopLevel and
-dw::Textblock::notifySetParent set the member
-dw::Textblock::containingBlock appropriately, (according to rules
-which should be defined in this document).
-
-Handling widgets out of flow is partly the task of the new class
-dw::OutOfFlowMgr, which is stored by dw::Textblock::outOfFlowMgr, but
-only for containing blocks. Generating blocks should refer to
-*containingBlock->outOfFlowMgr*. (Perhaps dw::OutOfFlowMgr may become
-independent of dw::Textblock.)
-
-dw::Textblock::addWidget is extended, so that floats and absolutely
-positioned elements can be added. Notice that not *this* widget, but
-the containing block becomes the parent of the newly added child, if
-it is out of flow. dw::Textblock::addWidget decides this by calling
-dw::OutOfFlowMgr::isOutOfFlow. (See new content types above.)
-
-dw::core::Widget::parentRef has become a new representation. Before,
-it represented the line numer. Now (least signifant bit left):
-
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
- | line number | 0 |
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
-
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
- | left float index | 0 | 0 | 1 |
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
-
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
- | right float index | 1 | 0 | 1 |
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
-
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
- | absolutely positioned index | 1 | 1 |
- +---+ - - - +---+---+- - - - - -+---+---+---+---+
-
-Details are hidden by static inline methods of dw::OutOfFlowMgr.
-
-
-The sizeRequest/sizeAllocate problem
-========================================
-
-*See also:* \ref dw-widget-sizes, especially the section *Rules for
-Methods Related to Resizing*.
-
-The size/position model of ::dw consists mainly of the following two
-steps:
-
-1. First, the size of the toplevel widget is calculated. Size
- calculation typically depends on the sizes of the widgets, which
- are calculated recursively, but not more.
-2. After this, the toplevel widget is allocated at position (0, 0),
- with the previosly calculated size. Each widget must allocate its
- children; here, the condition for the toplevel widget (allocated
- size equals requested size) is not necessary; instead, each widget
- may be allocated at every size.
-
-Especially for floats, this model becomes a bit difficult, for reasons
-described below. For the solutions, much is centralized at the level
-of the containing block, which delegates most to an instance of
-dw::OutOfFlowMgr (details below).
-
-**The size of a widget depends on the size not only of the children.**
-In the example above, the last list item (green, following the
-generating list item) must know the size of the the float (which is
-not a child or, generally, descendant) to determine the borders, which
-is done in dw::Textblock::sizeRequestImpl.
-
-For this, the size model has been extended (see \ref dw-widget-sizes,
-section *Rules for Methods Related to Resizing*): *sizeRequest* can be
-called within *sizeRequestImpl* for other widgets that children (with
-some caution). Namely, dw::Textblock::sizeRequestImpl calls
-dw::core::Widget::sizeRequest for the float, via
-dw::OutOfFlowMgr::getBorder and dw::OutOfFlowMgr::ensureFloatSize.
-
-**The size of a widget depends on the allocation of another widget.**
-In the example above, both list items (blue and green) must know the
-position of the float widget, within dw::Textblock::sizeRequestImpl,
-to calculate the borders. The position, however, is stored in the
-allocation, which is typically calculated later.
-
-Here, two cases must be distinguished. The position of a float is
-always **relative to its generating block**, so for calculating the
-borders for the generating block, the allocation needs not to be
-know. For other textblocks, it needs to be known, so the calculation
-of the borders will ignore floats generated by other textblocks, until
-all widgets are allocated. The latter will call (when neccessary)
-dw::core::Widget::queueResize, so that all border calculations are
-repeated. See below (*hasRelationChanged*) for details.
-
-Generally, this pattern (distinguishing between GB and CB) can be
-found everywhere in dw::OutOfFlowMgr.
-
-For details see:
-
-- dw::OutOfFlowMgr::getLeftBorder, dw::OutOfFlowMgr::getRightBorder,
- dw::OutOfFlowMgr::getBorder (called by the first two), and
- especially, dw::OutOfFlowMgr::getFloatsListForTextblock (called by
- the latter), where these three cases are distinguished;
-- dw::OutOfFlowMgr::sizeAllocateStart,
- dw::OutOfFlowMgr::sizeAllocateEnd which are called by the containing
- block.
-
-(This could be solved in a more simple, elegant way, when
-*sizeRequest* would depend on the position. This is, however, only a
-vague idea, perhaps not even feasible, and for which there are no
-concrete plans, certainly not in \ref dw-grows.)
-
-
-Implementation details
-======================
-
-- CB and GB lists (general pattern) (see previous section)
-- binary search; different search criteria, how they accord
-- lastLeftTBIndex, lastRightTBIndex etc.
-- limitiation of search; extIndex etc.
-
-
-How *hasRelationChanged* works
-==============================
-
-...
-
-
-Integration of line breaking and floats
-=======================================
-
-(Positioning of floats, loop, recent works.)
-
-
-Absolute and fixed positiones
-=============================
-
-See <http://flpsed.org/hgweb/dillo_grows>.
-
-*/ \ No newline at end of file
+- dw::oof::OOFAwareWidget is the base for both generators and containers.
+ dw::Textblock and dw::Table are based on this, but dw::Table is only relevant
+ for positioned elements, so much simpler than dw::Textblock.
+- Different containers for floats, absolutely positioned elements etc.
+- If a widget is out of flow, the generating widget keeps a reference with the
+ type dw::core::Content::WIDGET_OOF_REF, while the containing block refers to
+ it as dw::core::Content::WIDGET_OOF_CONT. For widgets within flow,
+ dw::core::Content::WIDGET_IN_FLOW is used. Notice that in the first case,
+ there are two pieces of content referring to the same widget. An application
+ of this distinction is iterators. (For selection and searching, the generating
+ hierarchy is used, whih is different from the widget hierarchy.)
+
+Handling widgets out of flow is partly the task of class implementing
+dw::oof::OutOfFlowMgr, which is stored by dw::oof::OOFAwareWidget::outOfFlowMgr,
+but only for containing blocks. Generating blocks should refer
+to *container->outOfFlowMgr[...]*.
+
+Overview of the dw::oof::OutOfFlowMgr hierarchy;
+
+\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>
+
+
+Further details
+===============
+
+- \ref dw-out-of-flow-floats
+- \ref dw-out-of-flow-positioned
+
+*/
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..5db97c7f
--- /dev/null
+++ b/devdoc/dw-size-request-pos.doc
@@ -0,0 +1,171 @@
+/** \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>
+
+
+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.
+
+<div style="border: 2px solid #ffff00; margin: 1em 0; padding: 0.5em 1em;
+ background-color: #ffffe0">This approach works very well for floats, but not
+ for positioned elements, which means that calling
+ dw::core::Widget::queueResize is still needed for the latter. On the other
+ hand, dw::oof::OOFFloatsMgr (which is much more complex than
+ dw::oof::OOFPositionedMgr) can be simplified quite much.</div>
+
+
+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.
+
+<div style="border: 2px solid #ffff00; margin: 1em 0;
+ padding: 0.5em 1em; background-color: #ffffe0">It is not sufficient
+ to work with *absolute* positions, since there may be an
+ interruption passing the positions so that absolute positions are
+ often not known.</div>
+
+All positions passed to dw::core::Widget::sizeRequest must constitute
+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. See beginning of
+dw::core::Widget::sizeRequest.
+
+An implementation may have to consider, this too, especially when implementing
+incremental resizing (see \ref dw-widget-sizes); see
+dw::Textblock::sizeRequestImpl as an example.
+
+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. Instead, this is handled by dw::oof::OutOfFlowMgr::markSizeChange
+(and likewise dw::oof::OutOfFlowMgr::markExtremesChange), which is called by the
+implementation of `markSizeChange` (or `markExtremesChange`, respectively) of
+the OOF container. (See also the end of the comment of dw::oof::OOFAwareWidget.)
+
+
+Plan
+====
+
+1. General design (dw::core::Widget::sizeRequestReference, changes to
+ dw::core::Widget::sizeRequest). Completed.
+
+2. Implementation for dw::Textblock. Completed.
+
+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). **MOSTLY
+ COMPLETED.**
+
+6. Implement step 3 for positioned elements (affects only
+ dw::oof::OOFPositionedMgr). **INCOMPLETE.** (But positioned elements are
+ currently deactivated.)
+
+
+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.
+
+- As an alternative, passing the references may be done in a new method, which
+ is called *before* dw::core::Widget::sizeRequestImpl. This makes even more
+ sense, after dw::core::Widget::calcExtraSpace and
+ dw::core::Widget::calcExtraSpaceImpl have been extended by references.
+
+- There may be inconsistencies for widget styles; see
+ [revision f797436687fe](http://flpsed.org/hgweb/dillo_grows/rev/f797436687fe)
+ as an example for a fix. Perhaps a different approach, where breaks are added,
+ _if `display` has the value `block`_ (or analogue), will work better.
+
+*/
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..25fca497 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"
@@ -58,14 +56,14 @@ bool AlignedTableCell::isBlockLevel ()
return tablecell::isBlockLevel ();
}
-bool AlignedTableCell::mustBeWidenedToAvailWidth ()
+bool AlignedTableCell::usesMaxGeneratorWidth ()
{
- return tablecell::mustBeWidenedToAvailWidth ();
+ return tablecell::usesMaxGeneratorWidth ();
}
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..0bcdbb5c 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 ();
@@ -39,7 +41,7 @@ public:
bool isBlockLevel ();
- bool mustBeWidenedToAvailWidth ();
+ bool usesMaxGeneratorWidth ();
};
} // namespace dw
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..fe6d79e6 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -12,6 +12,9 @@
*/
namespace dw {
+/** Used (temporally) for code related to positioned elements. */
+enum { IMPL_POS = false };
+
/**
* \brief The core of Dw is defined in this namespace.
*
@@ -25,6 +28,7 @@ class Layout;
class View;
class Widget;
class Iterator;
+class StackingContextMgr;
// Nothing yet to free.
inline void freeall () { }
@@ -41,6 +45,7 @@ class ResourceFactory;
#include "../lout/container.hh"
#include "../lout/signal.hh"
+#include "tools.hh"
#include "types.hh"
#include "events.hh"
#include "imgbuf.hh"
@@ -53,6 +58,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/imgbuf.hh b/dw/imgbuf.hh
index f9870bcf..e2b592e5 100644
--- a/dw/imgbuf.hh
+++ b/dw/imgbuf.hh
@@ -169,6 +169,10 @@ public:
DBG_OBJ_BASECLASS (lout::signal::ObservedObject);
}
+ inline ~Imgbuf () {
+ DBG_OBJ_DELETE ();
+ }
+
/*
* Methods called from the image decoding
*/
diff --git a/dw/iterator.cc b/dw/iterator.cc
index 0edb580b..51b49125 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
// -------------------
@@ -370,7 +362,7 @@ Iterator *DeepIterator::searchDownward (Iterator *it, Content::Type mask,
// indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it));
assert (it->getContent()->type & Content::ANY_WIDGET);
- it2 = it->getContent()->widget->iterator (mask, fromEnd);
+ it2 = it->getContent()->getWidget()->iterator (mask, fromEnd);
if (it2 == NULL) {
// Moving downwards failed.
@@ -450,7 +442,7 @@ Iterator *DeepIterator::searchSideward (Iterator *it, Content::Type mask,
misc::assertNotReached ();
if (it2->getContent()->type & Content::ANY_WIDGET &&
- it2->getContent()->widget == it->getWidget ()) {
+ it2->getContent()->getWidget () == it->getWidget ()) {
it3 = searchSideward (it2, mask, fromEnd);
it2->unref ();
//DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n",
@@ -579,7 +571,7 @@ DeepIterator::DeepIterator (Iterator *it)
assert (hasNext);
if (it->getContent()->type & Content::ANY_WIDGET &&
- it->getContent()->widget == w)
+ it->getContent()->getWidget () == w)
break;
}
@@ -683,7 +675,7 @@ bool DeepIterator::next ()
if (it->next ()) {
if (it->getContent()->type & Content::ANY_WIDGET) {
// Widget: new iterator on stack, to search in this widget.
- stack.push (it->getContent()->widget->iterator (mask, false));
+ stack.push (it->getContent()->getWidget()->iterator (mask, false));
return next ();
} else {
// Simply return the content of the iterartor.
@@ -716,7 +708,7 @@ bool DeepIterator::prev ()
if (it->prev ()) {
if (it->getContent()->type & Content::ANY_WIDGET) {
// Widget: new iterator on stack, to search in this widget.
- stack.push (it->getContent()->widget->iterator (mask, true));
+ stack.push (it->getContent()->getWidget()->iterator (mask, true));
return prev ();
} else {
// Simply return the content of the iterartor.
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..ee58f7ee 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 && IMPL_POS) {
+ 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/listitem.cc b/dw/listitem.cc
index 8bd2a93a..4d6794d8 100644
--- a/dw/listitem.cc
+++ b/dw/listitem.cc
@@ -40,7 +40,7 @@ ListItem::~ListItem()
DBG_OBJ_DELETE ();
}
-bool ListItem::mustBeWidenedToAvailWidth ()
+bool ListItem::usesMaxGeneratorWidth ()
{
return true;
}
diff --git a/dw/listitem.hh b/dw/listitem.hh
index 20fa6e9d..49a3c3a4 100644
--- a/dw/listitem.hh
+++ b/dw/listitem.hh
@@ -18,7 +18,7 @@ public:
ListItem(ListItem *ref, bool limitTextWidth);
~ListItem();
- bool mustBeWidenedToAvailWidth ();
+ bool usesMaxGeneratorWidth ();
void initWithWidget (core::Widget *widget, core::style::Style *style);
void initWithText (const char *text, core::style::Style *style);
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
new file mode 100644
index 00000000..f33df546
--- /dev/null
+++ b/dw/oofawarewidget.cc
@@ -0,0 +1,623 @@
+/*
+ * 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)->isPossibleOOFContainer (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())
+ ->isPossibleOOFContainerParent (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], 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);
+
+ bool result;
+ if (IMPL_POS) {
+ // 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 ();
+ result = cl < gl;
+
+ DBG_OBJ_MSGF ("draw", 1,"%d < %d => %s", cl, gl, boolToStr (result));
+ } else
+ result = false;
+
+ DBG_OBJ_LEAVE_VAL ("%s", boolToStr (result));
+ return result;
+}
+
+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;
+
+ default:
+ fprintf (stderr, "OOFAwareWidget::drawLevel: invalid level %s (%d)",
+ stackingLevelText (level), level);
+ 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 ("getWidgetAtPoint (SL_IN_FLOW) for %s",
+ getClassName ());
+ 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:
+ fprintf (stderr,
+ "OOFAwareWidget::getWidgetAtPointLevel: invalid level %s (%d)",
+ stackingLevelText (level), level);
+ break;
+ }
+
+ 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));
+}
+
+void OOFAwareWidget::updateReference (int ref)
+{
+ notImplemented ("OOFAwareWidget::updateReference");
+}
+
+void OOFAwareWidget::widgetRefSizeChanged (int externalIndex)
+{
+ notImplemented ("OOFAwareWidget::widgetRefSizeChanged");
+}
+
+void OOFAwareWidget::clearPositionChanged ()
+{
+ notImplemented ("OOFAwareWidget::clearPositionChanged");
+}
+
+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::getGeneratorX (int oofmIndex)
+{
+ notImplemented ("OOFAwareWidget::getGeneratorX");
+ return 0;
+}
+
+int OOFAwareWidget::getGeneratorY (int oofmIndex)
+{
+ notImplemented ("OOFAwareWidget::getGeneratorY");
+ return 0;
+}
+
+int OOFAwareWidget::getGeneratorWidth ()
+{
+ notImplemented ("OOFAwareWidget::getGeneratorWidth");
+ return 0;
+}
+
+int OOFAwareWidget::getMaxGeneratorWidth ()
+{
+ notImplemented ("OOFAwareWidget::getMaxGeneratorWidth");
+ return 0;
+}
+
+bool OOFAwareWidget::usesMaxGeneratorWidth ()
+{
+ notImplemented ("OOFAwareWidget::usesMaxGeneratorWidth");
+ return false;
+}
+
+bool OOFAwareWidget::isPossibleOOFContainer (int oofmIndex)
+{
+ return oofmIndex != OOFM_FLOATS;
+}
+
+bool OOFAwareWidget::isPossibleOOFContainerParent (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..9d5fa38a
--- /dev/null
+++ b/dw/oofawarewidget.hh
@@ -0,0 +1,306 @@
+#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);
+
+ virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
+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 IMPL_POS && style->position == core::style::POSITION_ABSOLUTE; }
+ static inline bool testStyleFixedlyPositioned (core::style::Style *style)
+ { return IMPL_POS && style->position == core::style::POSITION_FIXED; }
+ static inline bool testStyleRelativelyPositioned (core::style::Style *style)
+ { return IMPL_POS && 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 void updateReference (int ref);
+
+ /**
+ * Called by an implementation of dw::oof::OutOfFlowMgr (actually only
+ * OOFPosRelMgr) for the generator of a widget out of flow, when the
+ * reference size has changed. (The size of the reference is 0 * 0 for all
+ * other implementations of dw::oof::OutOfFlowMgr.)
+ */
+ virtual void widgetRefSizeChanged (int externalIndex);
+
+ /**
+ * TODO Needed after SRDOP?
+ */
+ virtual void clearPositionChanged ();
+
+ /**
+ * Called by an implementation of dw::oof::OutOfFlowMgr when the size of the
+ * container has changed, typically in sizeAllocateEnd.
+ */
+ virtual void oofSizeChanged (bool extremesChanged);
+
+ /**
+ * Return position relative to container, not regarding
+ * margin/border/padding, Called by OOFFloatsMgr to position floats.
+ */
+ virtual int getGeneratorX (int oofmIndex);
+
+ /**
+ * Return position relative to container, not regarding
+ * margin/border/padding, Called by OOFFloatsMgr to position floats.
+ */
+ virtual int getGeneratorY (int oofmIndex);
+
+ /**
+ * Return width including margin/border/padding Called by OOFFloatsMgr to
+ * position floats.
+ */
+ virtual int getGeneratorWidth ();
+
+ virtual int getMaxGeneratorWidth ();
+
+ virtual bool usesMaxGeneratorWidth ();
+
+ virtual bool isPossibleOOFContainer (int oofmIndex);
+
+ virtual bool isPossibleOOFContainerParent (int oofmIndex);
+};
+
+} // 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..0f9a6faa
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,1350 @@
+/*
+ * 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;
+}
+
+// ----------------------------------------------------------------------
+
+OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex)
+ : WidgetInfo (oofm, widget)
+{
+ this->generator = generatingBlock;
+ this->externalIndex = externalIndex;
+
+ yReq = yReal = size.width = size.ascent = size.descent = 0;
+ dirty = true;
+ index = -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);
+ }
+}
+
+void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ sb->appendPointer (getWidget ());
+
+ if (getWidget ()) {
+ sb->append (" (");
+ sb->append (getWidget()->getClassName ());
+ sb->append (")");
+ }
+
+ sb->append (", index = ");
+ sb->appendInt (index);
+ sb->append (", sideSpanningIndex = ");
+ sb->appendInt (sideSpanningIndex);
+ sb->append (", generator = ");
+ sb->appendPointer (generator);
+ 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->append (" }");
+}
+
+/**
+ * `y` is given relative to the container.
+ */
+bool OOFFloatsMgr::Float::covers (int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%d, %d [vloat: %p]", y, h, getWidget ());
+
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ bool b = yReal + size.ascent + size.descent > y && yReal < y + h;
+
+ DBG_OBJ_LEAVE_VAL_O (getOOFFloatsMgr (), "%s", b ? "true" : "false");
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ return ((Float*)o1)->yReal - ((Float*)o2)->yReal;
+}
+
+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->index, f1->generator, f1->externalIndex,
+ f2->index, f2->generator, f2->externalIndex);
+
+ if (f1->generator == f2->generator) {
+ 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->generator),
+ *t2 = oofm->getOOFAwareWidget (f2->generator);
+ 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.index = -1; // for debugging
+ Float::CompareGBAndExtIndex comparator (oofm);
+ 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;
+}
+
+/**
+ * `y` is given relative to the container.
+ */
+int OOFFloatsMgr::SortedFloatsVector::find (int y, int start, int end)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%d, %d, %d", y, start, end);
+
+ Float key (oofm, NULL, NULL, 0);
+ key.yReal = y;
+ Float::ComparePosition comparator;
+ int result = bsearch (&key, false, start, end, &comparator);
+
+ DBG_OBJ_LEAVE_VAL_O (oofm, "%d", result);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFirst (int y, int h,
+ OOFAwareWidget *lastGB,
+ int lastExtIndex,
+ int *lastReturn)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%d, %d, %p, %d",
+ y, h, lastGB, lastExtIndex);
+
+ 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 (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 (y, h))
+ result = i - 1;
+ else if (i <= last && get(i)->covers (y, h))
+ result = i;
+ else
+ result = -1;
+
+ DBG_OBJ_LEAVE_VAL_O (oofm, "%d", result);
+ 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->index = size() - 1;
+}
+
+int OOFFloatsMgr::TBInfo::ComparePosition::compare (Object *o1, Object *o2)
+{
+ TBInfo *tbInfo1 = (TBInfo*)o1, *tbInfo2 = (TBInfo*)o2;
+ int y1 = tbInfo1->getOOFAwareWidget () == NULL ? tbInfo1->y :
+ tbInfo1->getOOFAwareWidget()->getGeneratorY (oofmIndex);
+ int y2 = tbInfo2->getOOFAwareWidget () == NULL ? tbInfo2->y :
+ tbInfo2->getOOFAwareWidget()->getGeneratorY (oofmIndex);
+ return y1 - y2;
+}
+
+OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex) :
+ WidgetInfo (oofm, textblock)
+{
+ this->parent = parent;
+ this->parentExtIndex = parentExtIndex;
+
+ leftFloats = new Vector<Float> (1, false);
+ rightFloats = new Vector<Float> (1, false);
+}
+
+OOFFloatsMgr::TBInfo::~TBInfo ()
+{
+ delete leftFloats;
+ delete rightFloats;
+}
+
+OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container, int oofmIndex)
+{
+ DBG_OBJ_CREATE ("dw::oof::OOFFloatsMgr");
+
+ this->container = container;
+ this->oofmIndex = oofmIndex;
+
+ leftFloats = new SortedFloatsVector (this, LEFT);
+ rightFloats = new SortedFloatsVector (this, RIGHT);
+
+ DBG_OBJ_SET_NUM ("leftFloats.size", leftFloats->size());
+ DBG_OBJ_SET_NUM ("rightFloats.size", rightFloats->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;
+
+ containerAllocation = *(container->getAllocation());
+
+ addWidgetInFlow (this->container, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ // Order is important: tbInfosByOOFAwareWidget is owner of the instances
+ // of TBInfo.tbInfosByOOFAwareWidget. Also, leftFloats and rightFloats are
+ // owners of the floats.
+ delete tbInfos;
+ delete tbInfosByOOFAwareWidget;
+
+ delete leftFloats;
+ delete rightFloats;
+
+ delete floatsByWidget;
+
+ 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);
+
+ if (caller == container)
+ containerAllocation = *allocation;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == container) {
+ sizeAllocateFloats (LEFT);
+ sizeAllocateFloats (RIGHT);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < leftFloats->size (); i++)
+ leftFloats->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloats->size (); i++)
+ rightFloats->get(i)->getWidget()->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateFloats (Side side)
+{
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ for (int i = 0; i < list->size (); i++) {
+ Float *vloat = list->get(i);
+ ensureFloatSize (vloat);
+
+ Allocation childAllocation;
+ childAllocation.x = containerAllocation.x + calcFloatX (vloat);
+ childAllocation.y = containerAllocation.y + vloat->yReal;
+ childAllocation.width = vloat->size.width;
+ childAllocation.ascent = vloat->size.ascent;
+ childAllocation.descent = vloat->size.descent;
+
+ vloat->getWidget()->sizeAllocate (&childAllocation);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Return position of a float relative to the container.
+ */
+int OOFFloatsMgr::calcFloatX (Float *vloat)
+{
+ DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p", vloat->getWidget ());
+ int x, effGeneratorWidth;
+ OOFAwareWidget *generator = vloat->generator;
+
+ ensureFloatSize (vloat);
+
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ // Left floats are always aligned on the left side of the generator
+ // (content, not allocation) ...
+ x = generator->getGeneratorX (oofmIndex)
+ + generator->getStyle()->boxOffsetX();
+
+ // ... 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 (x + vloat->size.width > container->getMaxGeneratorWidth ())
+ x = max (0, container->getMaxGeneratorWidth () - vloat->size.width);
+ break;
+
+ case FLOAT_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).
+
+ // (The following code for calculating effGeneratorWidth, is quite
+ // specific for textblocks; this also applies for the comments. Both may
+ // be generalized, but actually, only textblocks play a role here.)
+
+ if (vloat->generator->usesMaxGeneratorWidth ())
+ // 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.)
+ effGeneratorWidth = vloat->generator->getMaxGeneratorWidth ();
+ 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.
+ effGeneratorWidth =
+ min (vloat->generator->getGeneratorWidth () + vloat->size.width,
+ vloat->generator->getMaxGeneratorWidth ());
+
+ x = max (generator->getGeneratorX (oofmIndex) + effGeneratorWidth
+ - vloat->size.width - generator->getStyle()->boxRestWidth(),
+ // Do not exceed container allocation:
+ 0);
+ break;
+
+ default:
+ assertNotReached ();
+ x = 0;
+ break;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", x);
+ 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 (leftFloats, view, area, context);
+ drawFloats (rightFloats, 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:
+ leftFloats->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloats.size", leftFloats->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloats", leftFloats->size() - 1,
+ "widget", vloat->getWidget ());
+ tbInfo->leftFloats->put (vloat);
+
+ subRef = createSubRefLeftFloat (leftFloats->size() - 1);
+
+ break;
+
+ case FLOAT_RIGHT:
+ rightFloats->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloats.size", rightFloats->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloats", rightFloats->size() - 1,
+ "widget", vloat->getWidget ());
+ tbInfo->rightFloats->put (vloat);
+
+ subRef = createSubRefRightFloat (rightFloats->size() - 1);
+ break;
+
+ default:
+ assertNotReached();
+ }
+
+ // "sideSpanningIndex" is only compared, so this simple assignment
+ // is sufficient; differenciation between GB and CB lists is not
+ // neccessary.
+ vloat->sideSpanningIndex =
+ leftFloats->size() + rightFloats->size() - 1;
+
+ floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
+
+ DBG_OBJ_LEAVE_VAL ("%d", subRef);
+ 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->leftFloats, oldStartIndex, diff);
+ moveExternalIndices (tbInfo->rightFloats, oldStartIndex, diff);
+}
+
+void OOFFloatsMgr::moveExternalIndices (Vector<Float> *list, int oldStartIndex,
+ int diff)
+{
+ // Could be faster with binary search, but the number of floats per generator
+ // 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 = leftFloats->get (getFloatIndexFromSubRef (ref));
+ else if (isSubRefRightFloat (ref))
+ vloat = rightFloats->get (getFloatIndexFromSubRef (ref));
+ else {
+ assertNotReached();
+ vloat = NULL; // compiler happiness
+ }
+
+ vloat->dirty = true;
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+
+ assert (vloat->getWidget()->getWidgetReference() != NULL);
+
+ int first = findTBInfo (vloat->yReal);
+ // The determination of the last element could perhaps be optimized, but we
+ // do not yet know the *new* height of the float.
+ int last = tbInfos->size () - 1;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "updating from %d to %d", first, last);
+
+ if (first <= last)
+ tbInfos->get(first)->getOOFAwareWidget()
+ ->updateReference (vloat->getWidget()->getWidgetReference()
+ ->parentRef);
+
+ for (int i = first + 1; i <= last; i++)
+ tbInfos->get(first)->getOOFAwareWidget()->updateReference(0);
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * `y` is given relative to the container.
+ */
+int OOFFloatsMgr::findTBInfo (int y)
+{
+ DBG_OBJ_ENTER ("findTBInfo", 0, "findTBInfo", "%d", y);
+
+ TBInfo key (this, NULL, NULL, 0);
+ key.y = y;
+ TBInfo::ComparePosition comparator (oofmIndex);
+ int index = tbInfos->bsearch (&key, false, &comparator);
+
+ // "bsearch" returns next greater, but we are interrested in the last which
+ // is less or equal.
+ int result = index > 0 ? index - 1 : index;
+
+ DBG_OBJ_LEAVE_VAL ("%d", result);
+ return result;
+}
+
+
+void OOFFloatsMgr::markExtremesChange (int ref)
+{
+ // Nothing to do here.
+}
+
+Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context)
+{
+ Widget *widgetAtPoint = NULL;
+
+ widgetAtPoint = getFloatWidgetAtPoint (rightFloats, x, y, context);
+ if (widgetAtPoint == NULL)
+ widgetAtPoint = getFloatWidgetAtPoint (leftFloats, 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 yRealNew;
+ if (vloat->index >= 1 &&
+ collidesV (vloat, listSame->get (vloat->index - 1), &yRealNew)) {
+ 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), &yRealNew);
+ oppFloatIndex--) {
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, listOpp->get (oppFloatIndex))) {
+ 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)
+{
+ notImplemented ("OOFFloatsMgr::tellIncompletePosition1");
+}
+
+void OOFFloatsMgr::tellIncompletePosition2 (Widget *generator, Widget *widget,
+ int x, int y)
+{
+ notImplemented ("OOFFloatsMgr::tellIncompletePosition2");
+}
+
+bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, int *yReal)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
+ vloat->index, vloat->getWidget (), other->index,
+ other->getWidget ());
+
+ bool result;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
+
+ ensureFloatSize (other);
+ int otherBottomGB = other->yReal + other->size.ascent + other->size.descent;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "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;
+
+ if (result)
+ DBG_OBJ_LEAVE_VAL ("%s, %d", "true", *yReal);
+ else
+ DBG_OBJ_LEAVE_VAL ("%s", "false");
+
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generator == other->generator)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generator->boxDiffWidth()
+ > vloat->generator->getGeneratorWidth ();
+ 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 {
+ int vloatX = calcFloatX (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)
+{
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ if (listSame) *listSame = leftFloats;
+ if (listOpp) *listOpp = rightFloats;
+ if (side) *side = LEFT;
+ break;
+
+ case FLOAT_RIGHT:
+ if (listSame) *listSame = rightFloats;
+ if (listOpp) *listOpp = leftFloats;
+ 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 = side == LEFT ? leftFloats : rightFloats;
+
+ *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->generator, container);
+
+ ensureFloatSize (vloat);
+
+ *width = max (*width, calcFloatX (vloat) + vloat->size.width);
+ *height = max (*height,
+ vloat->yReal + vloat->size.ascent + vloat->size.descent);
+ }
+
+ 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 = side == LEFT ? leftFloats : rightFloats;
+ 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->generator,
+ container);
+
+ 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.
+ *maxWidth = max (*maxWidth,
+ extr.maxWidth
+ + vloat->generator->getStyle()->boxDiffWidth(),
+ + max (container->getGeneratorWidth ()
+ - vloat->generator->getGeneratorWidth (),
+ 0));
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d / %d => %d / %d",
+ extr.minWidth, extr.maxWidth, *minWidth, *maxWidth);
+ }
+
+ 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 (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ int b = getBorder (LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "left border (%d, %d, %p, %d) => %d",
+ y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getRightBorder (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ int b = getBorder (RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "right border (%d, %d, %p, %d) => %d",
+ y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getBorder (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getBorder", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int last;
+ int first = list->findFirst (y, h, lastGB, lastExtIndex, &last);
+ int border = 0;
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+
+ if (first != -1) {
+ // 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.
+ 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 (y, h);
+ DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
+ i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
+
+ if (covers) {
+ int d;
+ switch (side) {
+ case LEFT:
+ d = vloat->generator->getGeneratorX (oofmIndex)
+ + vloat->generator->getStyle()->boxOffsetX ();
+ break;
+
+ case RIGHT:
+ // There is no simple possibility to get the difference between
+ // container and generator at the right border (as it is at the
+ // left border, see above). We have to calculate the difference
+ // between the maximal widths.
+ d = container->getMaxGeneratorWidth ()
+ - (vloat->generator->getGeneratorX (oofmIndex)
+ + vloat->generator->getMaxGeneratorWidth ())
+ + vloat->generator->getStyle()->boxRestWidth ();
+ break;
+
+ default:
+ assertNotReached ();
+ d = 0;
+ break;
+ }
+
+ int thisBorder = vloat->size.width + d;
+ DBG_OBJ_MSGF ("border", 1, "thisBorder = %d + %d = %d",
+ vloat->size.width, d, thisBorder);
+
+ border = max (border, thisBorder);
+ }
+ }
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", border);
+ return border;
+}
+
+bool OOFFloatsMgr::hasFloatLeft (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ bool b = hasFloat (LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float left (%d, %d, %p, %d) => %s",
+ y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloatRight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ bool b = hasFloat (RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float right (%d, %d, %p, %d) => %s",
+ y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloat (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "hasFloat", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int first = list->findFirst (y, h, lastGB, lastExtIndex, NULL);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+ DBG_OBJ_LEAVE ();
+ return first != -1;
+}
+
+int OOFFloatsMgr::getLeftFloatHeight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ return getFloatHeight (LEFT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getRightFloatHeight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ return getFloatHeight (RIGHT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getFloatHeight (Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int first = list->findFirst (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 = y - vloat->yReal;
+ DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
+ y, vloat->yReal, 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;
+}
+
+int OOFFloatsMgr::getClearPosition (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", widget);
+
+ int pos;
+
+ if (widget->getStyle()) {
+ bool left = false, right = false;
+ switch (widget->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 ? getClearPosition (widget, LEFT) : 0,
+ right ? getClearPosition (widget, RIGHT) : 0);
+ } else
+ pos = 0;
+
+ DBG_OBJ_LEAVE_VAL ("%d", pos);
+ 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::getClearPosition (OOFAwareWidget *widget, Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s",
+ widget, side == LEFT ? "LEFT" : "RIGHT");
+
+ int pos;
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+
+ // Search the last float before (therfore -1) this widget.
+ int i = list->findFloatIndex (widget, -1);
+ if (i < 0)
+ pos = 0;
+ else {
+ Float *vloat = list->get(i);
+ assert (vloat->generator != widget);
+ ensureFloatSize (vloat);
+ int yRel = widget->getGeneratorY (oofmIndex);
+ pos = max (vloat->yReal + vloat->size.ascent + vloat->size.descent - yRel,
+ 0);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "pos = max (%d + %d + %d - %d, 0)",
+ vloat->yReal, vloat->size.ascent, vloat->size.descent,
+ yRel);
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", pos);
+
+ 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->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)
+{
+ notImplemented ("OOFFloatsMgr::getAvailWidthOfChild");
+ return 0;
+}
+
+int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ notImplemented ("OOFFloatsMgr::getAvailHeightOfChild");
+ return 0;
+}
+
+int OOFFloatsMgr::getNumWidgets ()
+{
+ return leftFloats->size() + rightFloats->size();
+}
+
+Widget *OOFFloatsMgr::getWidget (int i)
+{
+ if (i < leftFloats->size())
+ return leftFloats->get(i)->getWidget ();
+ else
+ return rightFloats->get(i - leftFloats->size())->getWidget ();
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh
new file mode 100644
index 00000000..87cdc866
--- /dev/null
+++ b/dw/ooffloatsmgr.hh
@@ -0,0 +1,287 @@
+#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 };
+
+ OOFAwareWidget *container;
+ int oofmIndex;
+
+ core::Allocation containerAllocation;
+
+ class WidgetInfo: public lout::object::Object
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ core::Widget *widget;
+
+ protected:
+ OOFFloatsMgr *getOOFFloatsMgr () { return oofm; }
+
+ public:
+ WidgetInfo (OOFFloatsMgr *oofm, core::Widget *widget);
+
+ inline core::Widget *getWidget () { return widget; }
+ };
+
+ class Float: public WidgetInfo
+ {
+ public:
+ class ComparePosition: public lout::object::Comparator
+ {
+ public:
+ 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;
+
+ public:
+ CompareGBAndExtIndex (OOFFloatsMgr *oofm)
+ { this->oofm = oofm; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ OOFAwareWidget *generator;
+ int externalIndex;
+ int index; // TODO Needed after SRDOP?
+ int yReq, yReal; // relative to container
+ int sideSpanningIndex;
+ core::Requisition size;
+ bool dirty;
+
+ Float (OOFFloatsMgr *oofm, core::Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex);
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ bool covers (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>
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ Side side;
+
+ public:
+ inline SortedFloatsVector (OOFFloatsMgr *oofm, Side side) :
+ lout::container::typed::Vector<Float> (1, false)
+ { this->oofm = oofm; this->side = side; }
+
+ int findFloatIndex (OOFAwareWidget *lastGB, int lastExtIndex);
+ int find (int y, int start, int end);
+ int findFirst (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:
+ class ComparePosition: public lout::object::Comparator
+ {
+ private:
+ int oofmIndex;
+
+ public:
+ inline ComparePosition (int oofmIndex) { this->oofmIndex = oofmIndex; }
+ int compare (Object *o1, Object *o2);
+ };
+
+ int index; // position within "tbInfos"
+ int y; // used for sorting
+
+ TBInfo *parent;
+ int parentExtIndex;
+
+ // These two lists store all floats of a generator, in the order
+ // in which they are defined. Used for optimization
+ lout::container::typed::Vector<Float> *leftFloats, *rightFloats;
+
+ TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex);
+ ~TBInfo ();
+
+ inline OOFAwareWidget *getOOFAwareWidget ()
+ { return (OOFAwareWidget*)getWidget (); }
+ };
+
+ SortedFloatsVector *leftFloats, *rightFloats;
+
+ 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;
+
+ void moveExternalIndices (lout::container::typed::Vector<Float> *list,
+ int oldStartIndex, int diff);
+ Float *findFloatByWidget (core::Widget *widget);
+ int findTBInfo (int y);
+
+ void sizeAllocateFloats (Side side);
+ int getGBWidthForAllocation (Float *vloat);
+ int calcFloatX (Float *vloat);
+
+ 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, int *yReal);
+ bool collidesH (Float *vloat, Float *other);
+
+ 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 (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex);
+ bool hasFloat (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex);
+ int getFloatHeight (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex);
+
+ int getClearPosition (OOFAwareWidget *widget, 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, int oofmIndex);
+ ~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 (int y, int h, OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightBorder (int y, int h, OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool hasFloatLeft (int y, int h, OOFAwareWidget *lastGB, int lastExtIndex);
+ bool hasFloatRight (int y, int h, OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getLeftFloatHeight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex);
+ int getRightFloatHeight (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..aa506dd8
--- /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::oof::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..e66fd29a
--- /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::oof::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..ef6142a6
--- /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::oof::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..bf04c034
--- /dev/null
+++ b/dw/oofpositionedmgr.cc
@@ -0,0 +1,395 @@
+/*
+ * 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::oof::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 (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightBorder (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::hasFloatLeft (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::hasFloatRight (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return false;
+}
+
+
+int OOFPositionedMgr::getLeftFloatHeight (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightFloatHeight (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..f8ea0a3c
--- /dev/null
+++ b/dw/oofpositionedmgr.hh
@@ -0,0 +1,139 @@
+ #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 (int y, int h, OOFAwareWidget *lastGen, int lastExtIndex);
+ int getRightBorder (int y, int h, OOFAwareWidget *lastGen, int lastExtIndex);
+
+ bool hasFloatLeft (int y, int h, OOFAwareWidget *lastGen, int lastExtIndex);
+ bool hasFloatRight (int y, int h, OOFAwareWidget *lastGen, int lastExtIndex);
+
+ int getLeftFloatHeight (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex);
+ int getRightFloatHeight (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..17d59b37
--- /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::oof::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)
+{
+ notImplemented("OOFPosRelMgr::getAvailWidthOfChild");
+ return 0;
+}
+
+int OOFPosRelMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ notImplemented ("OOFPosRelMgr::getAvailHeightOfChild");
+ 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..209ae42c 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -5,431 +5,146 @@
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 (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 (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 (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);
+ /**
+ * Return whether there is a float on the right side. *y* is
+ * relative to the *container*.
+ *
+ * See also hasFloatLeft(), getLeftBorder();
+ */
+ virtual bool hasFloatRight (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex) = 0;
- int getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- int getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
+ /**
+ * 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 (int y, int h, OOFAwareWidget *lastGen,
+ int lastExtIndex) = 0;
- int getClearPosition (Textblock *tb);
+ /**
+ * 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 (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;
- 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); }
+ /**
+ * Return value is relative to the *calling generator* (not container).
+ */
+ 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..fc0bbce6 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,11 +73,24 @@ 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);
}
+core::Widget *Ruler::getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext
+ *context)
+{
+ // Override (complex) implementation OOFAwareWidget::getWidgetAtPoint().
+
+ if (inAllocation (x, y))
+ return this;
+ else
+ return NULL;
+}
+
core::Iterator *Ruler::iterator (core::Content::Type mask, bool atEnd)
{
/** \todo TextIterator? */
diff --git a/dw/ruler.hh b/dw/ruler.hh
index cd4f63f4..a3c6c962 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -14,18 +14,20 @@ 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);
+ core::Widget *getWidgetAtPoint (int x, int y,
+ core::GettingWidgetAtPointContext *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..1466439b 100644
--- a/dw/simpletablecell.cc
+++ b/dw/simpletablecell.cc
@@ -50,14 +50,14 @@ bool SimpleTableCell::isBlockLevel ()
return tablecell::isBlockLevel ();
}
-bool SimpleTableCell::mustBeWidenedToAvailWidth ()
+bool SimpleTableCell::usesMaxGeneratorWidth ()
{
- return tablecell::mustBeWidenedToAvailWidth ();
+ return tablecell::usesMaxGeneratorWidth ();
}
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..2985a420 100644
--- a/dw/simpletablecell.hh
+++ b/dw/simpletablecell.hh
@@ -19,6 +19,8 @@ protected:
bool getAdjustMinWidth ();
+ bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
public:
static int CLASS_ID;
@@ -30,7 +32,7 @@ public:
bool isBlockLevel ();
- bool mustBeWidenedToAvailWidth ();
+ bool usesMaxGeneratorWidth ();
};
} // namespace dw
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..77bc1942
--- /dev/null
+++ b/dw/stackingcontextmgr.hh
@@ -0,0 +1,76 @@
+#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 IMPL_POS &&
+ 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..38907b71 100644
--- a/dw/tablecell.hh
+++ b/dw/tablecell.hh
@@ -7,7 +7,7 @@ namespace dw {
namespace tablecell {
-inline bool mustBeWidenedToAvailWidth () { return true; }
+inline bool usesMaxGeneratorWidth () { return true; }
bool getAdjustMinWidth ();
bool isBlockLevel ();
@@ -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..f0bdf72a 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,14 +234,16 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
- outOfFlowMgr = NULL;
wrapRefLines = wrapRefParagraphs = -1;
+ wrapRefLinesFCX = wrapRefLinesFCY = -1;
DBG_OBJ_SET_NUM ("lines.size", lines->size ());
DBG_OBJ_SET_NUM ("words.size", words->size ());
DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
+ DBG_OBJ_SET_NUM ("wrapRefLinesFCX", wrapRefLinesFCX);
+ DBG_OBJ_SET_NUM ("wrapRefLinesFCY", wrapRefLinesFCY);
hoverLink = -1;
@@ -267,9 +251,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 +259,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 +289,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,16 +302,40 @@ 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);
+ // We have to rewrap the whole textblock, if (i) the available width (which
+ // is the line break width) has changed, or (ii) if the position within the
+ // float container, and so possibly borders relative to this textblock, have
+ // changed.
+ //
+ // (The latter is a simplification: an over-correct implementation would test
+ // all OOFMs on whether affectsLeftBorder() or affectsRightBorder() returns
+ // true.)
+
int newLineBreakWidth = getAvailWidth (true);
- if (newLineBreakWidth != lineBreakWidth) {
+ int newFCX, newFCY;
+ bool fcDefined = findSizeRequestReference (OOFM_FLOATS, &newFCX, &newFCY);
+
+ if (newLineBreakWidth != lineBreakWidth ||
+ (fcDefined && (newFCX != wrapRefLinesFCX ||
+ newFCY != wrapRefLinesFCY))) {
lineBreakWidth = newLineBreakWidth;
wrapRefLines = 0;
DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
+
+ if (!fcDefined) {
+ wrapRefLinesFCX = newFCX;
+ wrapRefLinesFCY = newFCY;
+ DBG_OBJ_SET_NUM ("wrapRefLinesFCX", wrapRefLinesFCX);
+ DBG_OBJ_SET_NUM ("wrapRefLinesFCY", wrapRefLinesFCY);
+ }
}
rewrap ();
@@ -347,14 +347,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,17 +368,15 @@ 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 ()) {
+ if (usesMaxGeneratorWidth ()) {
DBG_OBJ_MSGF ("resize", 1,
"before considering lineBreakWidth (= %d): %d * (%d + %d)",
lineBreakWidth, requisition->width, requisition->ascent,
@@ -407,31 +406,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)
@@ -450,9 +441,7 @@ int Textblock::calcVerticalBorder (int widgetPadding, int widgetBorder,
} else
result = lineMarginTotal + widgetPadding + widgetBorder + widgetMargin;
- DBG_OBJ_MSGF ("resize", 0, "=> %d", result);
- DBG_OBJ_LEAVE ();
-
+ DBG_OBJ_LEAVE_VAL ("%d", result);
return result;
}
@@ -469,9 +458,9 @@ 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");
+ DBG_OBJ_ENTER0 ("resize", 0, "getExtremesSimpl");
// TODO Can extremes depend on the available width? Should not; if
// they do, the following code must be reactivated, but it causes
@@ -515,7 +504,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 +523,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 +532,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)
{
@@ -567,55 +581,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
showMissingLines ();
- // In some cases, this allocation results in child allocation which
- // exceed the top of this allocation, which will then result in an
- // endless resize idle cascade and CPU hogging (when floats come
- // into play).
- //
- // Example:
- //
- // <div id="id1" style="height: 50px">
- // <div id="id2">...</div>
- // <div>
- //
- // Assume that the inner section, div#id2, has a height of 200px =
- // 100px (ascent) + 100px (descent). For the outer section,
- // div#id1, this will be initially calculated for the size, but
- // then (because of CSS 'height') reduced to 50px = 50px (ascent) +
- // 0px (descent). Without the following correction, the inner
- // section (div#id2) would be allocated at 50px top of the
- // allocation of the outer section: childAllocation->y =
- // allocation->y - 50.
- //
- // For this reason, we calculat "childBaseAllocation", which will
- // avoid this case; in the example above, the height will be 50px =
- // 100px (ascent) - 50px (descent: negative).
-
- childBaseAllocation.x = allocation->x;
- childBaseAllocation.y = allocation->y;
- childBaseAllocation.width = allocation->width;
- childBaseAllocation.ascent =
- misc::max (allocation->ascent,
- // Reconstruct the initial size; see
- // Textblock::sizeRequestImpl.
- (lines->size () > 0 ?
- calcVerticalBorder (getStyle()->padding.top,
- getStyle()->borderWidth.top,
- getStyle()->margin.top,
- lines->getRef(0)->borderAscent,
- lines->getRef(0)->marginAscent) :
- getStyle()->boxOffsetY ()) + verticalOffset);
- childBaseAllocation.descent =
- allocation->ascent + allocation->descent - childBaseAllocation.ascent;
-
- DBG_OBJ_SET_NUM ("childBaseAllocation.x", childBaseAllocation.x);
- DBG_OBJ_SET_NUM ("childBaseAllocation.y", childBaseAllocation.y);
- DBG_OBJ_SET_NUM ("childBaseAllocation.width", childBaseAllocation.width);
- 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;
@@ -643,8 +609,10 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
// the allocation width is greater than the line break width,
// due to wide unbreakable lines (large image etc.), use the
// original line break width.
- calcTextOffset (lineIndex,
- misc::min (childBaseAllocation.width, lineBreakWidth));
+ //
+ // TODO: test case?
+
+ calcTextOffset (lineIndex, misc::min (allocation->width, lineBreakWidth));
line = lines->getRef (lineIndex);
xCursor = line->textOffset;
@@ -656,7 +624,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
word = words->getRef (wordIndex);
if (wordIndex == lastWordDrawn + 1) {
- redrawY = misc::min (redrawY, lineYOffsetWidget (line));
+ redrawY = misc::min (redrawY, lineYOffsetWidget (line, allocation));
DBG_OBJ_SET_NUM ("redrawY", redrawY);
}
@@ -665,29 +633,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 + allocation->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)
+ childAllocation.y = lineYOffsetCanvas (line, allocation)
+ (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;
@@ -700,7 +660,8 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
/* The child widget has changed its position or its width
* so we need to redraw from this line onwards.
*/
- redrawY = misc::min (redrawY, lineYOffsetWidget (line));
+ redrawY =
+ misc::min (redrawY, lineYOffsetWidget (line, allocation));
DBG_OBJ_SET_NUM ("redrawY", redrawY);
if (word->content.widget->wasAllocated ()) {
redrawY = misc::min (redrawY,
@@ -728,7 +689,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
core::Content::BREAK)) {
int childChangedY =
- misc::min(childAllocation.y - childBaseAllocation.y +
+ misc::min(childAllocation.y - allocation->y +
childAllocation.ascent + childAllocation.descent,
oldChildAllocation->y - this->allocation.y +
oldChildAllocation->ascent +
@@ -737,7 +698,8 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
redrawY = misc::min (redrawY, childChangedY);
DBG_OBJ_SET_NUM ("redrawY", redrawY);
} else {
- redrawY = misc::min (redrawY, lineYOffsetWidget (line));
+ redrawY =
+ misc::min (redrawY, lineYOffsetWidget (line, allocation));
DBG_OBJ_SET_NUM ("redrawY", redrawY);
}
}
@@ -747,7 +709,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
xCursor += (word->size.width + word->effSpace);
DBG_OBJ_MSGF ("resize", 1, "xCursor = %d (after word %d)",
xCursor, wordIndex);
- DBG_MSG_WORD("resize", 1, "<i>that is:</i> ", wordIndex, "");
+ DBG_MSG_WORD ("resize", 1, "<i>that is:</i> ", wordIndex, "");
}
DBG_OBJ_MSG_END ();
@@ -755,9 +717,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;
@@ -769,7 +730,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
y = allocation->y + allocation->ascent + allocation->descent;
} else {
Line *line = lines->getRef(findLineOfWord (anchor->wordIndex));
- y = lineYOffsetCanvas (line);
+ y = lineYOffsetCanvas (line, allocation);
}
changeAnchor (anchor->name, y);
}
@@ -777,32 +738,59 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_LEAVE ();
}
+void Textblock::calcExtraSpaceImpl (int numPos, Widget **references, int *x,
+ int *y)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "Textblock::calcExtraSpaceImpl");
+
+ sizeRequestParams.fill (numPos, references, x, y);
+
+ OOFAwareWidget::calcExtraSpaceImpl (numPos, references, x, y);
+
+ int clearPosition = 0;
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (searchOutOfFlowMgr (i) && findSizeRequestReference (i, NULL, NULL))
+ clearPosition =
+ misc::max (clearPosition,
+ searchOutOfFlowMgr(i)->getClearPosition (this));
+
+ extraSpace.top = misc::max (extraSpace.top, clearPosition);
+
+ DBG_OBJ_LEAVE ();
+}
+
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 () &&
+ !usesMaxGeneratorWidth ()) {
+ 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 +798,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 +818,8 @@ void Textblock::containerSizeChangedForChildren ()
word->content.widget->containerSizeChanged ();
}
- if (outOfFlowMgr)
- outOfFlowMgr->containerSizeChangedForChildren ();
-
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -833,10 +828,10 @@ 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 () &&
+ if (!usesMaxGeneratorWidth () &&
(extremesQueued () || extremesChanged ()))
ret = true;
else
@@ -876,13 +871,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 +882,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 +905,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 +916,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 +928,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 +1017,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;
@@ -1093,7 +1028,7 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
wordIndex = -1;
} else {
Line *lastLine = lines->getRef (lines->size () - 1);
- int yFirst = lineYOffsetCanvasI (0);
+ int yFirst = lineYOffsetCanvas (0);
int yLast = lineYOffsetCanvas (lastLine) + lastLine->borderAscent +
lastLine->borderDescent;
if (event->yCanvas < yFirst) {
@@ -1213,11 +1148,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 +1175,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 +1479,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 +1512,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 +1543,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 +1552,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 +1575,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));
}
@@ -1634,7 +1584,7 @@ int Textblock::findLineIndexWhenNotAllocated (int y)
int Textblock::findLineIndexWhenAllocated (int y)
{
assert (wasAllocated ());
- return findLineIndex (y, childBaseAllocation.ascent);
+ return findLineIndex (y, allocation.ascent);
}
int Textblock::findLineIndex (int y, int ascent)
@@ -1650,13 +1600,12 @@ int Textblock::findLineIndex (int y, int ascent)
step = (lines->size() + 1) >> 1;
while ( step > 1 ) {
index = low + step;
- if (index <= maxIndex &&
- lineYOffsetWidgetIAllocation (index, &alloc) <= y)
+ if (index <= maxIndex && lineYOffsetWidget (index, &alloc) <= y)
low = index;
step = (step + 1) >> 1;
}
- if (low < maxIndex && lineYOffsetWidgetIAllocation (low + 1, &alloc) <= y)
+ if (low < maxIndex && lineYOffsetWidget (low + 1, &alloc) <= y)
low++;
/*
@@ -1710,7 +1659,7 @@ int Textblock::findParagraphOfWord (int wordIndex)
if (wordIndex < 0 || wordIndex >= words->size () ||
// It may be that the paragraphs list is incomplete. But look
// also at fillParagraphs, where this method is called.
- (paragraphs->size () > 0 &&
+ (paragraphs->size () == 0 ||
wordIndex > paragraphs->getLastRef()->lastWord))
return -1;
@@ -1772,38 +1721,46 @@ 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.widgetReference->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 ();
}
@@ -1849,7 +1806,9 @@ void Textblock::cleanupWord (int wordNo)
if (word->content.type == core::Content::WIDGET_IN_FLOW)
delete word->content.widget;
- /** \todo Widget references? What about texts? */
+ if (word->content.type == core::Content::WIDGET_OOF_REF)
+ delete word->content.widgetReference;
+ /** \todo What about texts? */
removeWordImgRenderer (wordNo);
removeSpaceImgRenderer (wordNo);
@@ -1914,6 +1873,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 +2264,93 @@ 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, firstWordOfLine;
+
+ if (hasListitemValue)
+ // For list items, the word #0 at the beginning (bullet, number ...) has
+ // to be considered;
+ firstWordOfLine = wordIndex == 1 ||
+ (wordIndex > 0 &&
+ words->getRef(wordIndex - 1)->content.type == core::Content::BREAK);
+ else
+ firstWordOfLine = wordIndex == 0 ||
+ words->getRef(wordIndex - 1)->content.type == core::Content::BREAK;
+
+ DBG_OBJ_MSGF ("resize", 1, "firstWordOfLine = %s",
+ boolToStr (firstWordOfLine));
+
+ if (firstWordOfLine &&
+ (widget->getStyle()->display == core::style::DISPLAY_BLOCK ||
+ widget->getStyle()->display == core::style::DISPLAY_LIST_ITEM ||
+ widget->getStyle()->display == core::style::DISPLAY_TABLE)) {
+ // pass positions
+ DBG_OBJ_MSG ("resize", 1, "pass position");
+ 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 - min (lastMargin, widget->getStyle()->margin.top);
+
+ DBG_OBJ_MSGF ("resize", 1,
+ "xRel = %d + %d + (%d == 0 ? %d : 0) = %d, "
+ "yRel = %d - min (%d, %d) = %d",
+ boxOffsetX (), leftInnerPadding , lines->size (),
+ line1OffsetEff, xRel, yLine, lastMargin,
+ widget->getStyle()->margin.top, yRel);
+
+ 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)
+ DBG_OBJ_MSG ("resize", 1, "do not pass position");
+ 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 +2358,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,41 +2403,50 @@ 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;
+ word->content.widgetReference = new core::WidgetReference (widget);
+ widget->setWidgetReference (word->content.widgetReference);
// After a out-of-flow reference, breaking is allowed. (This avoids some
// 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;
}
@@ -2438,7 +2486,7 @@ bool Textblock::addAnchor (const char *name, core::style::Style *style)
if (lines->size () == 0)
y = allocation.y;
else
- y = allocation.y + lineYOffsetWidgetI (lines->size () - 1);
+ y = allocation.y + lineYOffsetWidget (lines->size () - 1);
copy = Widget::addAnchor (name, y);
} else
copy = Widget::addAnchor (name);
@@ -2632,7 +2680,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 +2691,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 +2700,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 +2799,68 @@ 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.widgetReference->widget)
+ == oofmIndex &&
+ doesWidgetOOFInterruptDrawing (word->content.widgetReference
+ ->widget))
+ widgetAtPoint =
+ word->content.widgetReference->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 +2961,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,186 +2984,20 @@ 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 ();
}
-bool Textblock::mustBeWidenedToAvailWidth ()
+void Textblock::updateReference (int ref)
{
- 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);
- DBG_OBJ_MSGF ("resize", 0,
- "=> %s (toplevel: %s, block: %s, float: %s)",
- result ? "true" : "false", toplevel ? "true" : "false",
- block ? "true" : "false", vloat ? "true" : "false");
- DBG_OBJ_LEAVE ();
- return result;
+ queueResize (ref, false);
}
-/**
- * Called by dw::OutOfFlowMgr when the border has changed due to a
- * float (or some floats).
- *
- * "y", which given in widget coordinates, denotes the minimal
- * position (when more than one float caused this), "vloat" the
- * floating widget belonging to "y".
- */
-void Textblock::borderChanged (int y, Widget *vloat)
+void Textblock::widgetRefSizeChanged (int externalIndex)
{
- DBG_OBJ_ENTER ("resize", 0, "borderChanged", "%d, %p", y, vloat);
-
- int lineIndex = findLineIndex (y);
- DBG_OBJ_MSGF ("resize", 1, "Line index: %d (of %d).",
- lineIndex, lines->size ());
-
- // Nothing to do at all, when lineIndex >= lines->size (),
- // i. e. the change is below the bottom of this widget.
- if (lineIndex < lines->size ()) {
- int wrapLineIndex;
- if (lineIndex < 0)
- // Rewrap all.
- wrapLineIndex = 0;
- else
- wrapLineIndex = lineIndex;
-
- int realWrapLineIndex = wrapLineIndex;
- // The following two variables are only used for debugging:
- int minWrapLineIndex = wrapLineIndex, maxWrapLineIndex = wrapLineIndex;
-
- if (vloat->getGenerator() == this && lines->size () > 0) {
- bool found = false;
- // Sometimes, the respective word is not yet part of a
- // line. Nothing to do, but because of the assertion below
- // (and also for performace reasons) this should be
- // considered. TODO: Integrate this below.
- for (int wordIndex =
- lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
- !found && wordIndex < words->size(); wordIndex++) {
- Word *word = words->getRef (wordIndex);
- if (word->content.type == core::Content::WIDGET_OOF_REF &&
- word->content.widget == vloat)
- found = true;
- }
-
- // We search for the line of the float reference. There are
- // two cases when this is not the line corresponsing to y:
- //
- // (1) When the float was moved down, due to collisions with
- // other floats: in this case, the line number gets
- // smaller (since the float reference is before).
- //
- // (2) In some cases, the line number may become larger, due
- // to the per-line optimization of the words: initially,
- // lines->size() - 1 is assigned, but it may happen that
- // the float reference is put into another line.
- //
- // Only in the first case, a correction is neccessary, but a
- // test for the second case is useful. (TODO: I've forgotten
- // why a correction is neccessary.)
- //
- // Searched is done in the following order:
- //
- // - wrapLineIndex,
- // - wrapLineIndex - 1,
- // - wrapLineIndex + 1,
- // - wrapLineIndex - 2,
- // - wrapLineIndex + 2,
- //
- // etc. until either the float reference has been found or
- // all lines have been searched (the latter triggers an
- // abortion).
-
- bool exceedsBeginning = false, exceedsEnd = false;
- for (int i = 0; !found; i++) {
- bool exceeds;
- int lineIndex2;
- if (i % 2 == 0) {
- // even: +0, +1, +2, ...
- lineIndex2 = realWrapLineIndex + i / 2;
- if (i > 0)
- exceeds = exceedsEnd = lineIndex2 >= lines->size ();
- else
- exceeds = exceedsEnd = false;
- } else {
- // odd: -1, -2, ...
- lineIndex2 = realWrapLineIndex - (i + 1) / 2;
- exceeds = exceedsBeginning = lineIndex2 < 0;
- }
-
- DBG_OBJ_MSGF ("resize", 2,
- "lineIndex2 = %d (of %d), exceeds = %s, "
- "exceedsBeginning = %s, exceedsEnd = %s",
- lineIndex2, lines->size (),
- exceeds ? "true" : "false",
- exceedsBeginning ? "true" : "false",
- exceedsEnd ? "true" : "false");
-
- if (exceedsBeginning && exceedsEnd)
- break;
-
- if (!exceeds) {
- Line *line = lines->getRef (lineIndex2);
- for (int wordIndex = line->firstWord;
- !found && wordIndex <= line->lastWord; wordIndex++) {
- Word *word = words->getRef (wordIndex);
- if (word->content.type == core::Content::WIDGET_OOF_REF &&
- word->content.widget == vloat) {
- found = true;
- // Correct only by smaller values (case (1) above):
- realWrapLineIndex =
- misc::min (realWrapLineIndex, lineIndex2);
- }
- }
-
- minWrapLineIndex = misc::min (minWrapLineIndex, lineIndex2);
- maxWrapLineIndex = misc::max (maxWrapLineIndex, lineIndex2);
- }
- }
-
- assert (found);
- }
-
- DBG_OBJ_MSGF ("resize", 1,
- "wrapLineIndex: corrected from %d to %d (%d lines total); "
- "searched between %d and %d; this is the GB: %s",
- wrapLineIndex, realWrapLineIndex, lines->size (),
- minWrapLineIndex, maxWrapLineIndex,
- vloat->getGenerator() == this ? "yes" : "no");
-
- queueResize (OutOfFlowMgr::createRefNormalFlow (realWrapLineIndex), true);
-
- // Notice that the line no. realWrapLineIndex may not exist yet.
- if (realWrapLineIndex == 0)
- lastWordDrawn = misc::min (lastWordDrawn, -1);
- else
- lastWordDrawn =
- misc::min (lastWordDrawn,
- lines->getRef(realWrapLineIndex - 1)->lastWord);
- DBG_OBJ_SET_NUM ("lastWordDrawn", lastWordDrawn);
-
- // TODO Is the following necessary? Or even useless?
- //redrawY =
- // misc::min (redrawY,
- // lineYOffsetWidget (lines->getRef (realWrapLineIndex)));
- //DBG_OBJ_SET_NUM ("redrawY", redrawY);
- }
-
- DBG_OBJ_LEAVE ();
+ int lineNo = findLineOfWord (externalIndex);
+ if (lineNo >= 0 && lineNo < lines->size ())
+ queueResize (makeParentRefInFlow (lineNo), true);
}
void Textblock::clearPositionChanged ()
@@ -3127,14 +3015,107 @@ 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 ())
+ if (extremesChanged && !usesMaxGeneratorWidth ())
containerSizeChanged ();
DBG_OBJ_LEAVE ();
}
+int Textblock::getGeneratorX (int oofmIndex)
+{
+ int xRef;
+ if (findSizeRequestReference (oofmIndex, &xRef, NULL))
+ return xRef;
+ else {
+ // Only called for floats, so this should not happen:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+int Textblock::getGeneratorY (int oofmIndex)
+{
+ int yRef;
+ if (findSizeRequestReference (oofmIndex, NULL, &yRef))
+ return yRef;
+ else {
+ // Only called for floats, so this should not happen:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+int Textblock::getGeneratorRest (int oofmIndex)
+{
+ int xRef;
+ OOFAwareWidget *container = oofContainer[oofmIndex];
+
+ if (container != NULL && findSizeRequestReference (container, &xRef, NULL))
+ return misc::max (container->getGeneratorWidth ()
+ - (xRef + getGeneratorWidth ()),
+ 0);
+ else {
+ // Only called for floats, so this should not happen:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+int Textblock::getGeneratorWidth ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getGeneratorWidth");
+
+ // Cf. sizeRequestImpl.
+ if (usesMaxGeneratorWidth ()) {
+ DBG_OBJ_LEAVE_VAL ("%d", lineBreakWidth);
+ return lineBreakWidth;
+ } else {
+ int w0 = lines->size () > 0 ? lines->getLastRef()->maxLineWidth : 0,
+ w = min (w0 + leftInnerPadding + boxDiffWidth (), lineBreakWidth);
+ DBG_OBJ_LEAVE_VAL ("min (%d + %d + %d, %d) = %d",
+ w0, leftInnerPadding, boxDiffWidth (), lineBreakWidth,
+ w);
+ return w;
+ }
+}
+
+int Textblock::getMaxGeneratorWidth ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getMaxGeneratorWidth");
+ DBG_OBJ_LEAVE_VAL ("%d", lineBreakWidth);
+ return lineBreakWidth;
+}
+
+bool Textblock::usesMaxGeneratorWidth ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "usesMaxGeneratorWidth");
+ bool toplevel = getParent () == NULL,
+ block = getStyle()->display == core::style::DISPLAY_BLOCK,
+ 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_LEAVE_VAL ("%s (toplevel: %s, block: %s, float: %s, abspos: %s, "
+ "fixpos: %s)",
+ boolToStr(result), boolToStr(toplevel), boolToStr(block),
+ boolToStr(vloat), boolToStr(abspos), boolToStr(fixpos));
+ return result;
+}
+
+bool Textblock::isPossibleOOFContainer (int oofmIndex)
+{
+ return true;
+}
+
+bool Textblock::isPossibleOOFContainerParent (int oofmIndex)
+{
+ return true;
+}
+
RegardingBorder *Textblock::getWidgetRegardingBorderForLine (Line *line)
{
return getWidgetRegardingBorderForLine (line->firstWord, line->lastWord);
@@ -3168,16 +3149,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 +3164,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 +3184,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..01f7d9f3 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -4,7 +4,6 @@
#include <limits.h>
#include "regardingborder.hh"
-#include "outofflowmgr.hh"
#include "../lout/misc.hh"
// These were used when improved line breaking and hyphenation were implemented.
@@ -24,10 +23,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>
*
@@ -130,6 +128,8 @@ namespace dw {
* Widget::extraSpace should fix this, but it is only fully working
* in the GROWS branch (<http://flpsed.org/hgweb/dillo_grows>).
*
+ * Update: This needs to be re-evaluated.
+ *
* - Do margins of inline blocks and tables collapse? Check CSS
* spec. (They do currently; if not, ignoring them is simple.)
*
@@ -164,11 +164,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 +195,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 +278,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 +295,8 @@ private:
static const char *hyphenDrawChar;
- Textblock *containingBlock;
- OutOfFlowMgr *outOfFlowMgr;
-
protected:
+
/**
* \brief Implementation used for words.
*/
@@ -316,8 +319,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 +329,6 @@ protected:
void getBgArea (int *x, int *y, int *width, int *height);
core::style::Style *getStyle ();
-
- void print ();
};
struct Paragraph
@@ -452,8 +451,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,45 +500,34 @@ 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;
- // See sizeAllocateImpl for details. It is also used elsewhere.
- core::Allocation childBaseAllocation;
-
/* These fields provide some ad-hoc-functionality, used by sub-classes. */
bool hasListitemValue; /* If true, the first word of the page is treated
specially (search in source). */
@@ -582,16 +575,16 @@ 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
parentRef. */
+ int wrapRefLinesFCX, wrapRefLinesFCY;
// These four values are calculated by containingBlock->outOfFlowMgr
// (when defined; otherwise, they are false, or 0, respectively), for
@@ -623,10 +616,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 +633,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 +649,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 +681,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
@@ -699,48 +703,43 @@ protected:
return getWidgetRegardingBorderForLine (lineNo) == NULL;
}
- inline int _lineYOffsetWidgetAllocation (Line *line,
- core::Allocation *allocation)
+ // The following methods return the y offset of a line,
+ // - given as pointer or by index;
+ // - either within the canvas, or within this widget;
+ // - with allocation passed explicitely, or using the widget allocation
+ // (important: this is set *after* sizeRequestImpl is returning.
+
+ inline int lineYOffsetWidget (Line *line, core::Allocation *allocation)
{
return line->top + (allocation->ascent - lines->getRef(0)->borderAscent);
}
inline int lineYOffsetWidget (Line *line)
{
- return _lineYOffsetWidgetAllocation (line, &childBaseAllocation);
+ return lineYOffsetWidget (line, &allocation);
}
- /**
- * Like lineYOffsetCanvas, but with the allocation as parameter. Rarely used
- * outside of lineYOffsetCanvas.
- */
- inline int _lineYOffsetCanvasAllocation (Line *line,
- core::Allocation *allocation)
+ inline int lineYOffsetCanvas (Line *line, core::Allocation *allocation)
{
- return allocation->y + _lineYOffsetWidgetAllocation (line, allocation);
+ return allocation->y + lineYOffsetWidget (line, allocation);
}
- /**
- * Returns the y offset (within the canvas) of a line.
- */
inline int lineYOffsetCanvas (Line *line)
{
- return _lineYOffsetCanvasAllocation (line, &childBaseAllocation);
+ return lineYOffsetCanvas (line, &allocation);
}
- inline int lineYOffsetWidgetI (int lineIndex)
+ inline int lineYOffsetWidget (int lineIndex)
{
return lineYOffsetWidget (lines->getRef (lineIndex));
}
- inline int lineYOffsetWidgetIAllocation (int lineIndex,
- core::Allocation *allocation)
+ inline int lineYOffsetWidget (int lineIndex, core::Allocation *allocation)
{
- return _lineYOffsetWidgetAllocation (lines->getRef (lineIndex),
- allocation);
+ return lineYOffsetWidget (lines->getRef (lineIndex), allocation);
}
- inline int lineYOffsetCanvasI (int lineIndex)
+ inline int lineYOffsetCanvas (int lineIndex)
{
return lineYOffsetCanvas (lines->getRef (lineIndex));
}
@@ -765,16 +764,18 @@ protected:
RegardingBorder *getWidgetRegardingBorderForLine (int lineNo);
RegardingBorder *getWidgetRegardingBorderForLine (int firstWord,
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);
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 +810,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 numPos, Widget **references, int *x, int *y);
+
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
void containerSizeChangedForChildren ();
bool affectsSizeChangeContainerChild (Widget *child);
bool usesAvailWidth ();
@@ -821,13 +844,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 +860,8 @@ protected:
core::style::Style *style,
int numBreaks, int *breakPos,
core::Requisition *wordSize);
- static bool isContainingBlock (Widget *widget);
+
+ int getGeneratorRest (int oofmIndex);
public:
static int CLASS_ID;
@@ -854,8 +873,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 +887,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 +894,25 @@ 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 ();
-
- void borderChanged (int y, core::Widget *vloat);
+
+ void updateReference (int ref);
+ void widgetRefSizeChanged (int externalIndex);
void clearPositionChanged ();
void oofSizeChanged (bool extremesChanged);
- inline int getLineBreakWidth () { return lineBreakWidth; }
+ int getGeneratorX (int oofmIndex);
+ int getGeneratorY (int oofmIndex);
+ int getGeneratorWidth ();
+ int getMaxGeneratorWidth ();
+ bool usesMaxGeneratorWidth ();
+ bool isPossibleOOFContainer (int oofmIndex);
+ bool isPossibleOOFContainerParent (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,40 +921,64 @@ public:
else \
DBG_OBJ_ARRATTRSET_NUM ("words", n, "penalty." is, \
words->getRef(n)->badnessAndPenalty \
- .getPenalty (i)); \
+ .getPenalty (i)); \
} D_STMT_END
+#ifdef DBG_RTFL
+#define DBG_OBJ_ARRATTRSET_WREF(var, ind, attr, wref) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:p (p, d)", this, var, ind, attr, wref, \
+ wref->widget, wref->parentRef)
+#else
+#define DBG_OBJ_ARRATTRSET_WREF(var, ind, attr, wref) STMT_NOP
+#endif
+
#define DBG_SET_WORD(n) \
D_STMT_START { \
switch (words->getRef(n)->content.type) { \
case ::dw::core::Content::TEXT: \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "type", "TEXT"); \
- DBG_OBJ_ARRATTRSET_STR ("words", n, "text/widget/breakSpace", \
+ DBG_OBJ_ARRATTRSET_STR ("words", n, \
+ "text/widget/widgetReference/breakSpace", \
words->getRef(n)->content.text); \
break; \
case ::dw::core::Content::WIDGET_IN_FLOW: \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "type", "WIDGET_IN_FLOW"); \
- DBG_OBJ_ARRATTRSET_PTR ("words", n, "text/widget/breakSpace", \
+ DBG_OBJ_ARRATTRSET_PTR ("words", n, \
+ "text/widget/widgetReference/breakSpace", \
words->getRef(n)->content.widget); \
break; \
case ::dw::core::Content::WIDGET_OOF_REF: \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "type", "WIDGET_OOF_REF"); \
- DBG_OBJ_ARRATTRSET_PTR ("words", n, "text/widget/breakSpace", \
- words->getRef(n)->content.widget); \
+ DBG_OBJ_ARRATTRSET_WREF ("words", n, \
+ "text/widget/widgetReference/breakSpace", \
+ words->getRef(n)->content.widgetReference); \
break; \
case ::dw::core::Content::BREAK: \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "type", "BREAK"); \
- DBG_OBJ_ARRATTRSET_NUM ("words", n, "text/widget/breakSpace", \
+ DBG_OBJ_ARRATTRSET_NUM ("words", n, \
+ "text/widget/widgetReference/breakSpace", \
words->getRef(n)->content.breakSpace); \
break; \
default: \
DBG_OBJ_ARRATTRSET_SYM ("words", n, "type", "???"); \
- DBG_OBJ_ARRATTRSET_SYM ("words", n, "text/widget/breakSpace", "???"); \
+ DBG_OBJ_ARRATTRSET_SYM ("words", n, \
+ "text/widget/widgetReference/breakSpace", \
+ "???"); \
} \
DBG_SET_WORD_PENALTY (n, 0, "0"); \
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 ()) \
@@ -945,8 +994,12 @@ public:
words->getRef(n)->content.widget); \
break; \
case ::dw::core::Content::WIDGET_OOF_REF: \
- DBG_OBJ_MSGF (aspect, prio, prefix "WIDGET_OOF_REF / %p" suffix, \
- words->getRef(n)->content.widget); \
+ DBG_OBJ_MSGF (aspect, prio, \
+ prefix "WIDGET_OOF_REF / %p (%p, %d)" suffix,\
+ words->getRef(n)->content.widgetReference, \
+ words->getRef(n)->content.widgetReference->widget, \
+ words->getRef(n)->content.widgetReference \
+ ->parentRef); \
break; \
case ::dw::core::Content::BREAK: \
DBG_OBJ_MSGF (aspect, prio, prefix "BREAK / %d" suffix, \
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..f4789619 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -30,6 +30,7 @@
#include <math.h>
using namespace lout;
+using namespace lout::misc;
namespace dw {
@@ -50,7 +51,7 @@ int Textblock::BadnessAndPenalty::badnessValue (int infLevel)
}
// compiler happiness
- lout::misc::assertNotReached ();
+ assertNotReached ();
return 0;
}
@@ -75,7 +76,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,14 +192,7 @@ 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)
+void Textblock::BadnessAndPenalty::intoStringBuffer(StringBuffer *sb)
{
switch (badnessState) {
case NOT_STRETCHABLE:
@@ -247,42 +241,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 ();
-}
-
/*
* ...
*
@@ -408,11 +366,11 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
line->breakSpace = 0;
bool regardBorder = mustBorderBeRegarded (line);
- line->leftOffset = misc::max (regardBorder ? newLineLeftBorder : 0,
- boxOffsetX () + leftInnerPadding
- + (lineIndex == 0 ? line1OffsetEff : 0));
- line->rightOffset = misc::max (regardBorder ? newLineRightBorder : 0,
- boxRestWidth ());
+ line->leftOffset = max (regardBorder ? newLineLeftBorder : 0,
+ boxOffsetX () + leftInnerPadding
+ + (lineIndex == 0 ? line1OffsetEff : 0));
+ line->rightOffset = max (regardBorder ? newLineRightBorder : 0,
+ boxRestWidth ());
DBG_OBJ_MSGF ("construct.line", 1,
"regardBorder = %s, newLineLeftBorder = %d, "
@@ -450,7 +408,7 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
line->lastOofRefPositionedBeforeThisLine = -1;
} else {
Line *prevLine = lines->getRef (lines->size () - 2);
- line->maxLineWidth = misc::max (lineWidth, prevLine->maxLineWidth);
+ line->maxLineWidth = max (lineWidth, prevLine->maxLineWidth);
line->lastOofRefPositionedBeforeThisLine =
prevLine->lastOofRefPositionedBeforeThisLine;
}
@@ -477,8 +435,8 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
// zero height, which may cause endless loops. For this reasons,
// the height should be positive (assuming the caller passed
// minHeight > 0).
- line->borderAscent = misc::max (line->borderAscent, minHeight);
- line->marginAscent = misc::max (line->marginAscent, minHeight);
+ line->borderAscent = max (line->borderAscent, minHeight);
+ line->marginAscent = max (line->marginAscent, minHeight);
DBG_OBJ_ARRATTRSET_NUM ("lines", lineIndex, "borderAscent",
line->borderAscent);
@@ -495,25 +453,38 @@ 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.widgetReference->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;
}
line->lastOofRefPositionedBeforeThisLine =
- misc::max (line->lastOofRefPositionedBeforeThisLine, newLastOofPos);
+ max (line->lastOofRefPositionedBeforeThisLine, newLastOofPos);
DBG_OBJ_SET_NUM ("lastLine.lastOofRefPositionedBeforeThisLine",
line->lastOofRefPositionedBeforeThisLine);
@@ -601,7 +572,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);
@@ -756,7 +727,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
"breakPos = %d, height = %d, lastFloatPos = %d",
breakPos, height, lastFloatPos);
- int startSearch = misc::max (firstIndex, lastFloatPos + 1);
+ int startSearch = max (firstIndex, lastFloatPos + 1);
int newFloatPos = -1;
// Step 1: search for the next float.
@@ -764,14 +735,14 @@ 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++) {
+ Widget *widget = content->widgetReference->widget;
+ if ((searchOutOfFlowMgr(j)->affectsLeftBorder(widget) ||
+ searchOutOfFlowMgr(j)->affectsRightBorder (widget)))
+ newFloatPos = i;
+ }
+ }
}
DBG_OBJ_MSGF ("construct.word", 2, "newFloatPos = %d", newFloatPos);
@@ -782,10 +753,23 @@ 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.widgetReference->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,
@@ -799,29 +783,39 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
} while (floatHandled);
int minHeight;
- if (firstIndex <= breakPos)
+ if (firstIndex <= breakPos) {
// Not an empty line: calculate line height from contents.
minHeight = 1;
- else {
+ DBG_OBJ_MSGF ("construct.word", 1, "%d <= %d => minHeight = %d",
+ firstIndex, breakPos, minHeight);
+ } else {
// Empty line. Too avoid too many lines one pixel high, we
// use the float heights.
if (newLineHasFloatLeft && newLineHasFloatRight)
- minHeight = misc::max (misc::min (newLineLeftFloatHeight,
- newLineRightFloatHeight),
- 1);
+ minHeight = max (min (newLineLeftFloatHeight,
+ newLineRightFloatHeight),
+ 1);
else if (newLineHasFloatLeft && !newLineHasFloatRight)
- minHeight = misc::max (newLineLeftFloatHeight, 1);
+ minHeight = max (newLineLeftFloatHeight, 1);
else if (!newLineHasFloatLeft && newLineHasFloatRight)
- minHeight = misc::max (newLineRightFloatHeight, 1);
+ minHeight = max (newLineRightFloatHeight, 1);
else
// May this happen?
minHeight = 1;
+
+ DBG_OBJ_MSGF ("construct.word", 1,
+ "%d < %d => minHeight = %d (l: %s (%d), r: %s (%d))",
+ firstIndex, breakPos, minHeight,
+ boolToStr (newLineHasFloatLeft),
+ newLineHasFloatLeft ? newLineLeftFloatHeight : 0,
+ boolToStr (newLineHasFloatRight),
+ newLineHasFloatRight ? newLineRightFloatHeight : 0);
}
addLine (firstIndex, breakPos, lastFloatPos, tempNewLine, minHeight);
DBG_OBJ_MSGF ("construct.word", 1,
- "accumulating again from %d to %d\n",
+ "accumulating again from %d to %d",
breakPos + 1, wordIndexEnd);
for(int i = breakPos + 1; i <= wordIndexEnd; i++)
accumulateWordData (i);
@@ -851,8 +845,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 +856,51 @@ 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.widgetReference->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);
+ }
+
+ if(word->content.type == core::Content::WIDGET_OOF_REF) {
+ // Set parentRef for the referred widget. Cf. wrapWordInFlow.
+ int firstWordWithoutLine;
+ if (lines->size() == 0)
+ firstWordWithoutLine = 0;
+ else
+ firstWordWithoutLine = lines->getLastRef()->lastWord + 1;
+
+ if (wordIndex >= firstWordWithoutLine) {
+ word->content.widgetReference->parentRef =
+ makeParentRefInFlow (lines->size ());
+ DBG_SET_WORD (wordIndex);
+ }
+ }
+
+ 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,
@@ -957,7 +995,8 @@ void Textblock::balanceBreakPosAndHeight (int wordIndex, int firstIndex,
runNo++;
}
- DBG_OBJ_LEAVE ();
+ DBG_OBJ_LEAVE_VAL ("%d, %d, %d, %d",
+ *searchUntil, *lastFloatPos, *height, *breakPos);
}
// *wordIndexEnd must be initialized (initially to wordIndex)
@@ -973,7 +1012,8 @@ int Textblock::searchBreakPos (int wordIndex, int firstIndex, int *searchUntil,
tempNewLine ? "true" : "false", penaltyIndex,
thereWillBeMoreSpace ? "true" : "false",
wrapAll ? "true" : "false");
- DBG_MSG_WORD ("construct.word", 0, "<i>first word:</i> ", firstIndex, "");
+
+ DBG_MSG_WORD ("construct.word", 1, "<i>first word:</i> ", firstIndex, "");
int result;
bool lineAdded;
@@ -991,8 +1031,14 @@ int Textblock::searchBreakPos (int wordIndex, int firstIndex, int *searchUntil,
} else if (thereWillBeMoreSpace &&
words->getRef(firstIndex)->badnessAndPenalty.lineTooTight ()) {
int hyphenatedWord = considerHyphenation (firstIndex, firstIndex);
- DBG_OBJ_MSGF ("construct.word", 1, "too tight ... hyphenatedWord = %d",
- hyphenatedWord);
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ words->getRef(firstIndex)->badnessAndPenalty.intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("construct.word", 1,
+ "too tight: %s ... hyphenatedWord = %d",
+ sb.getChars (), hyphenatedWord);
+ }
if (hyphenatedWord == -1) {
DBG_OBJ_MSG ("construct.word", 1, "... => empty line");
@@ -1051,7 +1097,7 @@ int Textblock::searchBreakPos (int wordIndex, int firstIndex, int *searchUntil,
*diffWords += n;
DBG_OBJ_MSGF ("construct.word", 1,
- "accumulating again from %d to %d\n",
+ "accumulating again from %d to %d",
breakPos + 1, *wordIndexEnd);
for(int i = breakPos + 1; i <= *wordIndexEnd; i++)
accumulateWordData (i);
@@ -1061,8 +1107,7 @@ int Textblock::searchBreakPos (int wordIndex, int firstIndex, int *searchUntil,
DBG_OBJ_MSG_END ();
} while(!lineAdded);
- DBG_OBJ_MSGF ("construct.word", 1, "=> %d", result);
- DBG_OBJ_LEAVE ();
+ DBG_OBJ_LEAVE_VAL ("%d", result);
return result;
}
@@ -1082,7 +1127,7 @@ int Textblock::searchMinBap (int firstWord, int lastWord, int penaltyIndex,
Word *w = words->getRef(i);
DBG_IF_RTFL {
- misc::StringBuffer sb;
+ StringBuffer sb;
w->badnessAndPenalty.intoStringBuffer (&sb);
DBG_OBJ_MSGF ("construct.word", 2, "%d (of %d): b+p: %s",
i, words->size (), sb.getChars ());
@@ -1101,7 +1146,7 @@ int Textblock::searchMinBap (int firstWord, int lastWord, int penaltyIndex,
}
DBG_OBJ_MSG_END ();
- DBG_OBJ_MSGF ("construct.word", 1, "found at %d\n", pos);
+ DBG_OBJ_MSGF ("construct.word", 1, "found at %d", pos);
if (correctAtEnd && lastWord == words->size () - 1) {
// Since no break and no space is added, the last word will have
@@ -1117,7 +1162,7 @@ int Textblock::searchMinBap (int firstWord, int lastWord, int penaltyIndex,
correctedBap.setPenalty (0);
DBG_IF_RTFL {
- misc::StringBuffer sb;
+ StringBuffer sb;
correctedBap.intoStringBuffer (&sb);
DBG_OBJ_MSGF ("construct.word", 1, "corrected b+p: %s",
sb.getChars ());
@@ -1126,7 +1171,7 @@ int Textblock::searchMinBap (int firstWord, int lastWord, int penaltyIndex,
if (correctedBap.compareTo(penaltyIndex,
&words->getRef(pos)->badnessAndPenalty) <= 0) {
pos = lastWord;
- DBG_OBJ_MSGF ("construct.word", 1, "corrected: %d\n", pos);
+ DBG_OBJ_MSGF ("construct.word", 1, "corrected: %d", pos);
}
}
@@ -1190,11 +1235,11 @@ int Textblock::calcLinePartHeight (int firstWord, int lastWord)
for (int i = firstWord; i <= lastWord; i++) {
Word *word = words->getRef (i);
- ascent = misc::max (ascent, word->size.ascent);
- descent = misc::max (descent, word->size.descent);
+ ascent = max (ascent, word->size.ascent);
+ descent = max (descent, word->size.descent);
}
- return misc::max (ascent + descent, 1);
+ return max (ascent + descent, 1);
}
/**
@@ -1283,11 +1328,11 @@ void Textblock::handleWordExtremes (int wordIndex)
wordExtremes.minWidthIntrinsic + word->hyphenWidth + corrDiffMin;
lastPar->parAdjustmentWidth +=
wordExtremes.adjustmentWidth + word->hyphenWidth + corrDiffMin;
- lastPar->maxParMin = misc::max (lastPar->maxParMin, lastPar->parMin);
+ lastPar->maxParMin = max (lastPar->maxParMin, lastPar->parMin);
lastPar->maxParMinIntrinsic =
- misc::max (lastPar->maxParMinIntrinsic, lastPar->parMinIntrinsic);
+ max (lastPar->maxParMinIntrinsic, lastPar->parMinIntrinsic);
lastPar->maxParAdjustmentWidth =
- misc::max (lastPar->maxParAdjustmentWidth, lastPar->parAdjustmentWidth);
+ max (lastPar->maxParAdjustmentWidth, lastPar->parAdjustmentWidth);
DBG_OBJ_ARRATTRSET_NUM ("paragraphs", paragraphs->size() - 1, "parMin",
lastPar->parMin);
@@ -1321,9 +1366,9 @@ void Textblock::handleWordExtremes (int wordIndex)
lastPar->parMax += wordExtremes.maxWidth + word->hyphenWidth + corrDiffMax;
lastPar->parMaxIntrinsic +=
wordExtremes.maxWidthIntrinsic + word->hyphenWidth + corrDiffMax;
- lastPar->maxParMax = misc::max (lastPar->maxParMax, lastPar->parMax);
+ lastPar->maxParMax = max (lastPar->maxParMax, lastPar->parMax);
lastPar->maxParMaxIntrinsic =
- misc::max (lastPar->maxParMaxIntrinsic, lastPar->parMaxIntrinsic);
+ max (lastPar->maxParMaxIntrinsic, lastPar->parMaxIntrinsic);
DBG_OBJ_ARRATTRSET_NUM ("paragraphs", paragraphs->size() - 1, "parMax",
lastPar->parMax);
@@ -1469,8 +1514,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);
@@ -1521,12 +1567,12 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
int len = word->style->font->ascent;
if (word->style->valign == core::style::VALIGN_SUPER)
len += len / 2;
- line->contentAscent = misc::max (line->contentAscent, len);
+ line->contentAscent = max (line->contentAscent, len);
len = word->style->font->descent;
if (word->style->valign == core::style::VALIGN_SUB)
len += word->style->font->ascent / 3;
- line->contentDescent = misc::max (line->contentDescent, len);
+ line->contentDescent = max (line->contentDescent, len);
int borderAscent, borderDescent, marginAscent, marginDescent;
@@ -1542,8 +1588,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 {
@@ -1551,8 +1596,12 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
borderDescent = marginDescent = word->size.descent;
if (word->content.type == core::Content::BREAK)
- line->breakSpace =
- misc::max (word->content.breakSpace, line->breakSpace);
+ line->breakSpace = max (word->content.breakSpace, line->breakSpace);
+ else if (word->content.type == core::Content::WIDGET_OOF_REF) {
+ word->content.widgetReference->parentRef =
+ makeParentRefInFlow (lineIndex);
+ DBG_SET_WORD (wordIndex);
+ }
}
DBG_OBJ_MSGF ("construct.line", 2,
@@ -1560,10 +1609,10 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
"marginDescent = %d",
borderAscent, borderDescent, marginAscent, marginDescent);
- line->borderAscent = misc::max (line->borderAscent, borderAscent);
- line->borderDescent = misc::max (line->borderDescent, borderDescent);
- line->marginAscent = misc::max (line->marginAscent, marginAscent);
- line->marginDescent = misc::max (line->marginDescent, marginDescent);
+ line->borderAscent = max (line->borderAscent, borderAscent);
+ line->borderDescent = max (line->borderDescent, borderDescent);
+ line->marginAscent = max (line->marginAscent, marginAscent);
+ line->marginDescent = max (line->marginDescent, marginDescent);
DBG_OBJ_LEAVE ();
}
@@ -1617,8 +1666,8 @@ void Textblock::accumulateWordData (int wordIndex)
word->totalWidth = prevWord->totalWidth
+ prevWord->origSpace - prevWord->hyphenWidth
+ word->size.width + word->hyphenWidth;
- word->maxAscent = misc::max (prevWord->maxAscent, word->size.ascent);
- word->maxDescent = misc::max (prevWord->maxDescent, word->size.descent);
+ word->maxAscent = max (prevWord->maxAscent, word->size.ascent);
+ word->maxDescent = max (prevWord->maxDescent, word->size.descent);
word->totalSpaceStretchability =
prevWord->totalSpaceStretchability + getSpaceStretchability(prevWord);
word->totalSpaceShrinkability =
@@ -1652,9 +1701,10 @@ void Textblock::accumulateWordData (int wordIndex)
totalShrinkability);
DBG_IF_RTFL {
- misc::StringBuffer sb;
+ StringBuffer sb;
word->badnessAndPenalty.intoStringBuffer (&sb);
- DBG_OBJ_MSGF ("construct.word.accum", 1, "b+p: %s", sb.getChars ());
+ DBG_OBJ_ARRATTRSET_SYM ("words", wordIndex, "badnessAndPenalty",
+ sb.getChars ());
}
DBG_OBJ_LEAVE ();
@@ -1669,8 +1719,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,16 +1731,14 @@ int Textblock::calcLineBreakWidth (int lineIndex)
} else
leftBorder = rightBorder = 0;
- leftBorder = misc::max (leftBorder, getStyle()->boxOffsetX());
- rightBorder = misc::max (rightBorder, getStyle()->boxRestWidth());
+ leftBorder = max (leftBorder, boxOffsetX());
+ rightBorder = max (rightBorder, boxRestWidth());
lineBreakWidth -= (leftBorder + rightBorder);
- DBG_OBJ_MSGF ("construct.word.width", 2, "=> %d - %d - (%d + %d) = %d\n",
- this->lineBreakWidth, leftInnerPadding, leftBorder,
- rightBorder, lineBreakWidth);
-
- DBG_OBJ_LEAVE ();
+ DBG_OBJ_LEAVE_VAL ("%d - %d - (%d + %d) = %d",
+ this->lineBreakWidth, leftInnerPadding, leftBorder,
+ rightBorder, lineBreakWidth);
return lineBreakWidth;
}
@@ -1837,7 +1884,7 @@ void Textblock::calcTextOffset (int lineIndex, int totalWidth)
break;
default:
- misc::assertNotReached ();
+ assertNotReached ();
break;
}
@@ -1866,7 +1913,7 @@ void Textblock::rewrap ()
// the line list up from this position is rebuild.
lines->setSize (wrapRefLines);
DBG_OBJ_SET_NUM ("lines.size", lines->size ());
- nonTemporaryLines = misc::min (nonTemporaryLines, wrapRefLines);
+ nonTemporaryLines = min (nonTemporaryLines, wrapRefLines);
initNewLine ();
@@ -1879,14 +1926,32 @@ void Textblock::rewrap ()
DBG_OBJ_MSGF ("construct.line", 0, "starting with word %d", firstWord);
- lastWordDrawn = misc::min (lastWordDrawn, firstWord - 1);
+ lastWordDrawn = min (lastWordDrawn, firstWord - 1);
DBG_OBJ_SET_NUM ("lastWordDrawn", lastWordDrawn);
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.widgetReference->widget);
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
+ oofm->calcWidgetRefSize (word->content.widgetReference->widget,
+ &(word->size));
+ DBG_SET_WORD_SIZE (i);
+ }
+ break;
+
+ default:
+ break;
+ }
wordWrap (i, false);
@@ -1924,7 +1989,7 @@ void Textblock::fillParagraphs ()
if (lines->size () > 0 && wrapRefParagraphs > 0) {
// Sometimes, wrapRefParagraphs is larger than lines->size(), due to
// floats? (Has to be clarified.)
- int lineNo = misc::min (wrapRefParagraphs, lines->size ()) - 1;
+ int lineNo = min (wrapRefParagraphs, lines->size ()) - 1;
firstWordOfLine = lines->getRef(lineNo)->lastWord + 1;
} else
firstWordOfLine = 0;
@@ -1942,7 +2007,7 @@ void Textblock::fillParagraphs ()
else
// If there are no paragraphs yet, findParagraphOfWord will return
// -1: use 0 then instead.
- parNo = misc::max (0, findParagraphOfWord (firstWordOfLine));
+ parNo = max (0, findParagraphOfWord (firstWordOfLine));
paragraphs->setSize (parNo);
DBG_OBJ_SET_NUM ("paragraphs.size", paragraphs->size ());
@@ -1972,17 +2037,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 +2054,96 @@ 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.
-
-
- 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>");
+ 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;
+
+ if (oofmDefined) {
+ int firstWordOfLine =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
+ int effOofRef = max (lastOofRef, firstWordOfLine - 1);
+ 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 (y, height, this, effOofRef);
+ newLineHasFloatLeft = newLineHasFloatLeft || thisHasLeft;
+ thisHasRight = oofm->hasFloatRight (y, height, this, effOofRef);
+ newLineHasFloatRight = newLineHasFloatRight || thisHasRight;
+
+ newLineLeftBorder =
+ max (newLineLeftBorder,
+ oofm->getLeftBorder (y, height, this, effOofRef)
+ - getGeneratorX (i));
+ newLineRightBorder =
+ max (newLineRightBorder,
+ oofm->getRightBorder (y, height, this, effOofRef)
+ - getGeneratorRest (i));
+
+ // TODO "max" is not really correct for the heights. (Does
+ // not matter, since only one, the float manager, returns
+ // meaningful values.)
+ if (thisHasLeft)
+ newLineLeftFloatHeight =
+ max (newLineLeftFloatHeight,
+ oofm->getLeftFloatHeight (y, height, this, effOofRef));
+ if (thisHasRight)
+ newLineRightFloatHeight =
+ max (newLineRightFloatHeight,
+ oofm->getRightFloatHeight (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..547c2585
--- /dev/null
+++ b/dw/tools.cc
@@ -0,0 +1,192 @@
+#include "core.hh"
+
+namespace dw {
+namespace core {
+
+using namespace lout::misc;
+
+SizeParams::SizeParams ()
+{
+ DBG_OBJ_CREATE ("dw::core::SizeParams");
+ init ();
+ debugPrint ();
+}
+
+SizeParams::SizeParams (int numPos, Widget **references, int *x, int *y)
+{
+ DBG_OBJ_CREATE ("dw::core::SizeParams");
+ init ();
+ fill (numPos, references, x, y);
+ debugPrint ();
+}
+
+SizeParams::SizeParams (const SizeParams &other)
+{
+ DBG_OBJ_CREATE ("dw::core::SizeParams");
+ init ();
+ fill (other.numPos, other.references, other.x, other.y);
+ debugPrint ();
+}
+
+SizeParams::~SizeParams ()
+{
+ cleanup ();
+ DBG_OBJ_DELETE ();
+}
+
+SizeParams &SizeParams::operator=(const SizeParams &other)
+{
+ cleanup ();
+ init ();
+ fill (other.numPos, other.references, other.x, other.y);
+ debugPrint ();
+ return *this;
+}
+
+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_ENTER ("resize", 0, "fill", "%d, ...", numPos);
+
+ 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[childParams->numPos] = childReference;
+ childParams->x[childParams->numPos] = xRel;
+ childParams->y[childParams->numPos] = yRel;
+ childParams->numPos++;
+ } else {
+ bool found = false;
+ for (int j = 0; !found && j < numPos; j++) {
+ if (childReference == references[j]) {
+ found = true;
+ childParams->references[childParams->numPos] = childReference;
+ childParams->x[childParams->numPos] = x[j] + xRel;
+ childParams->y[childParams->numPos] = y[j] + yRel;
+ childParams->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;
+}
+
+/**
+ * Compares two instances, but considers a change in the order of the reference
+ * widgets as equivalent.
+ */
+bool SizeParams::isEquivalent (SizeParams *other)
+{
+ DBG_OBJ_ENTER ("resize", 0, "isEquivalent", "%p", other);
+ bool result;
+
+ if (numPos != other->numPos)
+ result = false;
+ else {
+ result = true;
+
+ for (int i = 0; result && i < numPos; i++) {
+ bool otherFound = false;
+ for (int j = 0; !otherFound && j < numPos; j++) {
+ if (references[i] == other->references[j]) {
+ otherFound = true;
+ if (!(x[i] == other->x[j] && y[i] == other->y[j]))
+ result = false;
+ }
+ }
+
+ if (!otherFound)
+ result = false;
+ }
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%s", boolToStr (result));
+ return result;
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/tools.hh b/dw/tools.hh
new file mode 100644
index 00000000..2f8ff0b5
--- /dev/null
+++ b/dw/tools.hh
@@ -0,0 +1,66 @@
+#ifndef __DW_TOOLS_HH__
+#define __DW_TOOLS_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#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 (int numPos, Widget **references, int *x, int *y);
+ SizeParams (const SizeParams &other);
+ ~SizeParams ();
+
+ SizeParams &operator=(const SizeParams &other);
+
+ 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);
+
+ bool isEquivalent (SizeParams *other);
+
+ 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.cc b/dw/types.cc
index 56af66d1..bd7ff748 100644
--- a/dw/types.cc
+++ b/dw/types.cc
@@ -299,9 +299,11 @@ void Content::intoStringBuffer(Content *content, misc::StringBuffer *sb)
break;
case WIDGET_OOF_REF:
sb->append ("<widget oof ref: ");
- sb->appendPointer (content->widget);
+ sb->appendPointer (content->widgetReference->widget);
sb->append (" (");
- sb->append (content->widget->getClassName());
+ sb->append (content->widgetReference->widget->getClassName());
+ sb->append (", ");
+ sb->appendInt (content->widgetReference->parentRef);
sb->append (")>");
break;
case WIDGET_OOF_CONT:
diff --git a/dw/types.hh b/dw/types.hh
index b6b4ca0b..877593fe 100644
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -185,6 +185,15 @@ struct Extremes
int adjustmentWidth;
};
+class WidgetReference: public lout::object::Object
+{
+public:
+ Widget *widget;
+ int parentRef;
+
+ WidgetReference (Widget *widget) { parentRef = -1; this->widget = widget; }
+};
+
struct Content
{
enum Type {
@@ -208,6 +217,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
@@ -222,6 +235,7 @@ struct Content
union {
const char *text;
Widget *widget;
+ WidgetReference *widgetReference;
int breakSpace;
};
@@ -231,6 +245,72 @@ struct Content
static void maskIntoStringBuffer(Type mask, lout::misc::StringBuffer *sb);
static void print (Content *content);
static void printMask (Type mask);
+
+ inline Widget *getWidget () {
+ assert (type & ANY_WIDGET);
+ return type == WIDGET_OOF_REF ? widgetReference->widget : widget;
+ }
+};
+
+/**
+ * \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
diff --git a/dw/ui.cc b/dw/ui.cc
index 1ea10ebc..62b91d5f 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)
@@ -230,14 +230,14 @@ void Resource::sizeAllocate (Allocation *allocation)
int Resource::getAvailWidthOfChild (Widget *child, bool forceValue)
{
// Only used when the resource contains other dillo widgets.
- misc::assertNotReached ();
+ misc::notImplemented ("Resource::getAvailWidthOfChild");
return 0;
}
int Resource::getAvailHeightOfChild (Widget *child, bool forceValue)
{
// Only used when the resource contains other dillo widgets.
- misc::assertNotReached ();
+ misc::notImplemented ("Resource::getAvailHeightOfChild");
return 0;
}
@@ -247,14 +247,14 @@ void Resource::correctRequisitionOfChild (Widget *child,
int*))
{
// Only used when the resource contains other dillo widgets.
- misc::assertNotReached ();
+ misc::notImplemented ("Resource::correctRequisitionOfChild");
}
void Resource::correctExtremesOfChild (Widget *child, Extremes *extremes,
bool useAdjustmentWidth)
{
// Only used when the resource contains other dillo widgets.
- misc::assertNotReached ();
+ misc::notImplemented ("Resource::correctExtremesOfChild");
}
void Resource::containerSizeChangedForChildren ()
@@ -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..7538b58b 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -68,8 +68,12 @@ Widget::Widget ()
DBG_OBJ_CREATE ("dw::core::Widget");
registerName ("dw::core::Widget", &CLASS_ID);
+ DBG_OBJ_ASSOC_CHILD (&requisitionParams);
+ DBG_OBJ_ASSOC_CHILD (&extremesParams);
+
flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED);
parent = quasiParent = generator = container = NULL;
+ setWidgetReference (NULL);
DBG_OBJ_SET_PTR ("container", container);
layout = NULL;
@@ -91,6 +95,8 @@ Widget::Widget ()
deleteCallbackFunc = NULL;
widgetImgRenderer = NULL;
+
+ stackingContextMgr = NULL;
}
Widget::~Widget ()
@@ -104,6 +110,9 @@ Widget::~Widget ()
delete widgetImgRenderer;
}
+ if (stackingContextMgr)
+ delete stackingContextMgr;
+
if (style)
style->unref ();
@@ -117,35 +126,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;
+
+ 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;
+ }
+ }
- parentArea = *area;
- parentArea.x += parent->allocation.x;
- parentArea.y += parent->allocation.y;
+ if (r) {
+ intersection->x -= allocation.x;
+ intersection->y -= allocation.y;
- childArea.x = allocation.x;
- childArea.y = allocation.y;
- childArea.width = allocation.width;
- childArea.height = getHeight ();
+ 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 (parentArea.intersectsWith (&childArea, intersection)) {
- intersection->x -= allocation.x;
- intersection->y -= allocation.y;
- return true;
- } else
- return false;
+ 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 +255,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)
@@ -317,6 +416,11 @@ void Widget::actualQueueResize (int ref, bool extremesChanged, bool fast)
} else {
for (widget2 = parent, child = this; widget2;
child = widget2, widget2 = widget2->parent) {
+ // TODO Could the following code be used for optimization?
+ //if (widget2->resizeQueued () &&
+ // (widget2->extremesQueued () || !extremesChanged))
+ // break;
+
if (layout && !widget2->resizeQueued ())
layout->queueResizeList->put (widget2);
@@ -472,11 +576,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 ();
@@ -489,9 +594,27 @@ void Widget::sizeRequest (Requisition *requisition)
// Layout::resizeIdle.
}
- if (needsResize ()) {
+ bool callImpl;
+ if (needsResize ())
+ callImpl = true;
+ else {
+ // Even if RESIZE_QUEUED / NEEDS_RESIZE is not set, calling
+ // sizeRequestImpl is necessary when the relavive positions passed here
+ // have changed.
+ SizeParams newParams (numPos, references, x, y);
+ DBG_OBJ_ASSOC_CHILD (&newParams);
+ if (newParams.isEquivalent (&requisitionParams))
+ callImpl = false;
+ else {
+ callImpl = true;
+ requisitionParams = newParams;
+ }
+ }
+
+ if (callImpl) {
+ calcExtraSpace (numPos, references, x, y);
/** \todo Check requisition == &(this->requisition) and do what? */
- sizeRequestImpl (requisition);
+ sizeRequestImpl (requisition, numPos, references, x, y);
this->requisition = *requisition;
unsetFlags (NEEDS_RESIZE);
@@ -519,7 +642,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 +750,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,11 +1014,12 @@ 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 ());
- DBG_OBJ_ENTER0 ("resize", 0, "getExtremes");
+ DBG_OBJ_ENTER ("resize", 0, "getExtremes", "%d, ...", numPos);
enterGetExtremes ();
@@ -908,11 +1032,28 @@ void Widget::getExtremes (Extremes *extremes)
// Layout::resizeIdle.
}
- if (extremesChanged ()) {
+ bool callImpl;
+ if (extremesChanged ())
+ callImpl = true;
+ else {
+ // Even if EXTREMES_QUEUED / EXTREMES_CHANGED is not set, calling
+ // getExtremesImpl is necessary when the relavive positions passed here
+ // have changed.
+ SizeParams newParams (numPos, references, x, y);
+ DBG_OBJ_ASSOC_CHILD (&newParams);
+ if (newParams.isEquivalent (&extremesParams))
+ callImpl = false;
+ else {
+ callImpl = true;
+ extremesParams = newParams;
+ }
+ }
+
+ if (callImpl) {
// 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 +1080,49 @@ 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 (int numPos, Widget **references, int *x, int *y)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "calcExtraSpace");
+
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+ calcExtraSpaceImpl (numPos, references, x, y);
+
+ 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);
+
+ DBG_OBJ_LEAVE ();
+}
+
+int Widget::numSizeRequestReferences ()
+{
+ return 0;
+}
+
+Widget *Widget::sizeRequestReference (int index)
+{
+ misc::notImplemented ("Widget::sizeRequestReference");
+ return NULL;
+}
+
+int Widget::numGetExtremesReferences ()
+{
+ return 0;
+}
+
+Widget *Widget::getExtremesReference (int index)
+{
+ misc::notImplemented ("Widget::getExtremesReference");
+ return NULL;
+}
+
+/**
* \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when
* needed.
*/
@@ -1082,6 +1266,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 +1390,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 +1420,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 +1559,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 +1566,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 +1593,62 @@ 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.
+ DBG_OBJ_ENTER0 ("resize", 0, "Widget::sizeRequestImpl");
+ sizeRequestSimpl (requisition);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::sizeRequestSimpl (Requisition *requisition)
+{
+ // Either variant should be implemented.
+ misc::notImplemented ("Widget::sizeRequestSimpl");
+}
+
+void Widget::getExtremesImpl (Extremes *extremes, int numPos,
+ Widget **references, int *x, int *y)
+{
+ // Use the simple variant.
+ DBG_OBJ_ENTER0 ("resize", 0, "Widget::getExtremesImpl");
+ getExtremesSimpl (extremes);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::getExtremesSimpl (Extremes *extremes)
+{
+ // Either variant should be implemented.
+ misc::notImplemented ("Widget::getExtremesSimpl");
}
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 (int numPos, Widget **references, int *x,
+ int *y)
+{
+}
+
void Widget::markSizeChange (int ref)
{
}
@@ -1753,10 +1964,11 @@ void Widget::leaveNotifyImpl (EventCrossing *)
tooltip->onLeave();
}
+
void Widget::removeChild (Widget *child)
{
// Should be implemented.
- misc::assertNotReached ();
+ misc::notImplemented ("Widget::removeChild");
}
// ----------------------------------------------------------------------
diff --git a/dw/widget.hh b/dw/widget.hh
index f9d1293c..2e9bcfd1 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -125,6 +125,8 @@ private:
*/
Widget *container;
+ WidgetReference *widgetReference;
+
style::Style *style;
Flags flags;
@@ -136,11 +138,13 @@ private:
* Do not read this directly, but call size_request().
*/
Requisition requisition;
+ SizeParams requisitionParams;
/**
* \brief Analogue to dw::core::Widget::requisition.
*/
Extremes extremes;
+ SizeParams extremesParams;
/**
* \brief See dw::core::Widget::setBgColor().
@@ -180,19 +184,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 +275,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 +284,29 @@ 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 (int numPos, Widget **references, int *x,
+ int *y);
/**
* \brief See \ref dw-widget-sizes.
@@ -292,8 +329,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 +445,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 +461,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 ();
+
+ /**
+ * \brief See \ref dw-widget-sizes (or \ref dw-size-request-pos).
+ */
+ virtual Widget *getExtremesReference (int index);
- void sizeRequest (Requisition *requisition);
- void getExtremes (Extremes *extremes);
+ 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 numPos, Widget **references, int *x, int *y);
+
int getAvailWidth (bool forceValue);
int getAvailHeight (bool forceValue);
virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; }
@@ -442,15 +506,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);
@@ -477,15 +550,21 @@ public:
int getGeneratorLevel ();
Widget *getNearestCommonAncestor (Widget *otherWidget);
+ inline WidgetReference *getWidgetReference () { return widgetReference; }
+ inline void setWidgetReference (WidgetReference *widgetReference) {
+ this->widgetReference = widgetReference;
+ DBG_OBJ_SET_PTR ("widgetReference", widgetReference);
+ }
+
inline Widget *getGenerator () { return generator ? generator : parent; }
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 +581,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..80f227f8 100644
--- a/lout/misc.hh
+++ b/lout/misc.hh
@@ -38,6 +38,26 @@ inline void assertNotReached ()
abort ();
}
+inline void assertNotReached (const char *fmt, ...)
+{
+ va_list argp;
+ va_start(argp, fmt);
+
+ fprintf (stderr, "*** [%s] This should not happen: ", prgName);
+ vfprintf(stderr, fmt, argp);
+ fprintf (stderr, "! ***\n");
+
+ va_end(argp);
+
+ abort ();
+}
+
+inline void notImplemented (const char *name)
+{
+ fprintf (stderr, "*** [%s] Not implemented: %s ***\n", prgName, name);
+ abort ();
+}
+
inline int roundInt(double d)
{
return (int) ((d > 0) ? (d + 0.5) : (d - 0.5));
@@ -64,6 +84,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 +140,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 +402,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..9c2d9493 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -364,12 +364,21 @@ static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace,
bool addBreakOpt)
{
Textblock *textblock = new Textblock (prefs.limit_text_width);
+ Style *style;
+
+ if (addBreaks) {
+ StyleAttrs attrs = *(html->style ());
+ attrs.display = DISPLAY_BLOCK;
+ style = Style::create (&attrs);
+ } else {
+ style = html->style ();
+ style->ref ();
+ }
if (addBreaks)
HT2TB(html)->addParbreak (breakSpace, html->wordStyle ());
- HT2TB(html)->addWidget (textblock, html->style ()); /* Works also for floats
- etc. */
+ HT2TB(html)->addWidget (textblock, style); /* Works also for floats etc. */
if (addBreakOpt)
HT2TB(html)->addBreakOption (html->style (), false);
@@ -378,11 +387,13 @@ static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace,
S_TOP(html)->textblock = html->dw = textblock;
if (addBreaks)
S_TOP(html)->hand_over_break = true;
+
+ style->unref ();
}
-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 +3924,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;
+}