aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rw-r--r--ChangeLog9
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/dw-out-of-flow.doc27
-rw-r--r--doc/dw-stacking-context.doc114
-rw-r--r--dw/Makefile.am13
-rw-r--r--dw/alignedtablecell.cc7
-rw-r--r--dw/alignedtablecell.hh2
-rw-r--r--dw/core.hh2
-rw-r--r--dw/image.cc31
-rw-r--r--dw/iterator.cc8
-rw-r--r--dw/iterator.hh2
-rw-r--r--dw/layout.cc20
-rw-r--r--dw/oofawarewidget.cc391
-rw-r--r--dw/oofawarewidget.hh206
-rw-r--r--dw/oofawarewidget_iterator.cc261
-rw-r--r--dw/ooffloatsmgr.cc2314
-rw-r--r--dw/ooffloatsmgr.hh397
-rw-r--r--dw/oofposabsmgr.cc69
-rw-r--r--dw/oofposabsmgr.hh27
-rw-r--r--dw/oofposfixedmgr.cc60
-rw-r--r--dw/oofposfixedmgr.hh27
-rw-r--r--dw/oofpositionedmgr.cc577
-rw-r--r--dw/oofpositionedmgr.hh120
-rw-r--r--dw/outofflowmgr.cc2377
-rw-r--r--dw/outofflowmgr.hh519
-rw-r--r--dw/ruler.cc9
-rw-r--r--dw/selection.cc102
-rw-r--r--dw/simpletablecell.cc5
-rw-r--r--dw/simpletablecell.hh2
-rw-r--r--dw/stackingcontextmgr.cc154
-rw-r--r--dw/stackingcontextmgr.hh60
-rw-r--r--dw/style.cc4
-rw-r--r--dw/style.hh14
-rw-r--r--dw/table.cc56
-rw-r--r--dw/table.hh15
-rw-r--r--dw/table_iterator.cc115
-rw-r--r--dw/tablecell.hh2
-rw-r--r--dw/textblock.cc456
-rw-r--r--dw/textblock.hh72
-rw-r--r--dw/textblock_iterator.cc252
-rw-r--r--dw/textblock_linebreaking.cc247
-rw-r--r--dw/types.hh4
-rw-r--r--dw/widget.cc182
-rw-r--r--dw/widget.hh30
-rw-r--r--lout/debug.hh8
-rw-r--r--src/cssparser.cc21
-rw-r--r--src/styleengine.cc6
-rw-r--r--test/Makefile.am4
-rw-r--r--test/identity.cc55
50 files changed, 5829 insertions, 3628 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/ChangeLog b/ChangeLog
index ae45dcbc..332def1f 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 positioned elements.
+ - Fixedly positioned elements (incomplete: referring to the canvas instead to
+ the viewport).
+ - "Z-index", stacking contexts.
+ Patches: Sebastian Geerken
+
+-----------------------------------------------------------------------------
dillo-3.1 [not released yet]
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 8ade3d15..7f627d09 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -13,6 +13,7 @@ EXTRA_DIST = \
dw-images-and-backgrounds.doc \
dw-dw-out-of-flow.doc \
dw-dw-out-of-flow-2.doc \
+ dw-stacking-context.doc \
fltk-problems.doc \
rounding-errors.doc \
uml-legend.doc \
diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc
index d02c3b28..8bfcde4c 100644
--- a/doc/dw-out-of-flow.doc
+++ b/doc/dw-out-of-flow.doc
@@ -1,10 +1,35 @@
/** \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>
+<div style="border: 2px solid #ff4040; margin-bottom: 0.5em;
+padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+Not up to date; incorporate these two changes: (i) there are different
+containing blocks for floats and absolutely (furthermore also fixedly)
+positioned elements; (ii) dw::OutOfFlowMgr is now only the base class:
+floats and absolutely positioned elements are seperated:
+\dot
+digraph G {
+ node [shape=record, fontname=Helvetica, fontsize=10];
+ edge [arrowhead="none", arrowtail="empty", dir="both"];
+ fontname=Helvetica; fontsize=8;
+
+ OutOfFlowMgr [URL="\ref dw::OutOfFlowMgr"];
+ OOFFloatsMgr [URL="\ref dw::OOFFloatsMgr"];
+ OOFPositionedMgr [URL="\ref dw::OOFPositionedMgr"];
+ OOFPosAbsMgr [URL="\ref dw::OOFPosAbsMgr"];
+ OOFPosFixedMgr [URL="\ref dw::OOFPosFixedMgr"];
+
+ OutOfFlowMgr -> OOFFloatsMgr;
+ OutOfFlowMgr -> OOFPositionedMgr;
+ OOFPositionedMgr -> OOFPosAbsMgr;
+ OOFPositionedMgr -> OOFPosFixedMgr;
+}
+\enddot
+</div>
+
Introduction
============
diff --git a/doc/dw-stacking-context.doc b/doc/dw-stacking-context.doc
new file mode 100644
index 00000000..6138ca5d
--- /dev/null
+++ b/doc/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/dw/Makefile.am b/dw/Makefile.am
index 0b4b7bb4..15055ad8 100644
--- a/dw/Makefile.am
+++ b/dw/Makefile.am
@@ -23,6 +23,8 @@ libDw_core_a_SOURCES = \
platform.hh \
selection.hh \
selection.cc \
+ stackingcontextmgr.hh \
+ stackingcontextmgr.cc \
style.cc \
style.hh \
types.cc \
@@ -69,6 +71,17 @@ libDw_widgets_a_SOURCES = \
image.hh \
listitem.cc \
listitem.hh \
+ oofawarewidget.cc \
+ oofawarewidget_iterator.cc \
+ oofawarewidget.hh \
+ ooffloatsmgr.cc \
+ ooffloatsmgr.hh \
+ oofposabsmgr.cc \
+ oofposabsmgr.hh \
+ oofposfixedmgr.cc \
+ oofposfixedmgr.hh \
+ oofpositionedmgr.cc \
+ oofpositionedmgr.hh \
outofflowmgr.cc \
outofflowmgr.hh \
ruler.cc \
diff --git a/dw/alignedtablecell.cc b/dw/alignedtablecell.cc
index 633c4e68..e7ab2741 100644
--- a/dw/alignedtablecell.cc
+++ b/dw/alignedtablecell.cc
@@ -129,6 +129,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;
@@ -191,7 +196,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 5ea606d7..5325ba63 100644
--- a/dw/alignedtablecell.hh
+++ b/dw/alignedtablecell.hh
@@ -22,6 +22,8 @@ protected:
bool getAdjustMinWidth ();
+ bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
int wordWrap (int wordIndex, bool wrapAll);
int getValue ();
diff --git a/dw/core.hh b/dw/core.hh
index 022574b1..9463df2b 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -25,6 +25,7 @@ class Layout;
class View;
class Widget;
class Iterator;
+class StackingContextMgr;
// Nothing yet to free.
inline void freeall () { }
@@ -53,6 +54,7 @@ class ResourceFactory;
#include "selection.hh"
#include "layout.hh"
#include "widget.hh"
+#include "stackingcontextmgr.hh"
#include "ui.hh"
#undef __INCLUDED_FROM_DW_CORE_HH__
diff --git a/dw/image.cc b/dw/image.cc
index 20460f33..8a4be32f 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -334,7 +334,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;
@@ -342,7 +342,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;
@@ -412,8 +412,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 ();
@@ -440,31 +440,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);
}
}
@@ -515,9 +513,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/iterator.cc b/dw/iterator.cc
index 0edb580b..dbb779f6 100644
--- a/dw/iterator.cc
+++ b/dw/iterator.cc
@@ -204,14 +204,6 @@ void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end,
}
}
-
-void Iterator::print ()
-{
- misc::StringBuffer sb;
- intoStringBuffer (&sb);
- printf ("%s", sb.getChars ());
-}
-
// -------------------
// EmptyIterator
// -------------------
diff --git a/dw/iterator.hh b/dw/iterator.hh
index abf31d0b..9460adc4 100644
--- a/dw/iterator.hh
+++ b/dw/iterator.hh
@@ -86,8 +86,6 @@ public:
static void scrollTo (Iterator *it1, Iterator *it2, int start, int end,
HPosition hpos, VPosition vpos);
-
- virtual void print ();
};
diff --git a/dw/layout.cc b/dw/layout.cc
index 2845a8e9..600f2088 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -374,6 +374,13 @@ void Layout::addWidget (Widget *widget)
return;
}
+ // The toplevel widget always establishes a stacking context. It could
+ // already be set in Widget::setStyle().
+ if (widget->stackingContextMgr == NULL) {
+ widget->stackingContextMgr = new StackingContextMgr (widget);
+ DBG_OBJ_ASSOC (widget, widget->stackingContextMgr);
+ }
+
topLevel = widget;
widget->layout = this;
widget->container = NULL;
@@ -1093,12 +1100,17 @@ void Layout::leaveNotify (View *view, ButtonState state)
*/
Widget *Layout::getWidgetAtPoint (int x, int y)
{
- _MSG ("------------------------------------------------------------\n");
- _MSG ("widget at (%d, %d)\n", x, y);
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *widget;
+
if (topLevel && topLevel->wasAllocated ())
- return topLevel->getWidgetAtPoint (x, y, 0);
+ widget = topLevel->getWidgetAtPoint (x, y);
else
- return NULL;
+ widget = NULL;
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
}
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
new file mode 100644
index 00000000..9994c0cc
--- /dev/null
+++ b/dw/oofawarewidget.cc
@@ -0,0 +1,391 @@
+/*
+ * 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;
+
+namespace dw {
+
+namespace oof {
+
+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;
+ 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 ();
+}
+
+void OOFAwareWidget::notifySetAsTopLevel()
+{
+ oofContainer[OOFM_FLOATS] = oofContainer[OOFM_ABSOLUTE]
+ = oofContainer[OOFM_FIXED] = this;
+}
+
+bool OOFAwareWidget::isOOFContainer (Widget *widget, int oofmIndex)
+{
+ // TODO The methods isPossibleContainer() and isPossibleContainerParent()
+ // are only used in few cases. Does not matter currently, however.
+
+ switch (oofmIndex) {
+ case OOFM_FLOATS:
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (// For floats, only some OOF aware widgets are considered as
+ // containers.
+ ((OOFAwareWidget*)widget)->isPossibleContainer (OOFM_FLOATS) &&
+ // The second condition: that this block is "out of flow", in a
+ // wider sense.
+ (// The toplevel widget is "out of flow", since there is no
+ // parent, and so no context.
+ widget->getParent() == NULL ||
+ // A similar reasoning applies to a widget with an
+ // unsuitable parent (typical example: a table cell (this
+ // is also a text block, so possible float container)
+ // within a table widget, which is not a suitable float
+ // container parent).
+ !(widget->getParent()->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ ((OOFAwareWidget*)widget->getParent())
+ ->isPossibleContainerParent (OOFM_FLOATS)) ||
+ // Inline blocks are containing blocks, too.
+ widget->getStyle()->display == 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;
+ // absolutely and fixedly positioned elements; furthermore,
+ // relatively positioned elements must already be
+ // considered here, since they may constitute a stacking
+ // context.
+ testWidgetOutOfFlow (widget) || testWidgetPositioned (widget)));
+
+ case OOFM_ABSOLUTE:
+ // Only the toplevel widget (as for all) as well as absolutely,
+ // relatively, and fixedly positioned elements constitute the
+ // containing block for absolutely positioned elements, but
+ // neither floats nor other elements like table cells, or
+ // elements with 'overview' set to another value than 'visible'.
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (widget->getParent() == NULL || testWidgetPositioned (widget));
+
+ case OOFM_FIXED:
+ // The single container for fixedly positioned elements is the
+ // toplevel (canvas; actually the viewport). (The toplevel
+ // widget should always be a textblock; at least this is the
+ // case in dillo.)
+ return widget->getParent() == NULL;
+
+ default:
+ // compiler happiness
+ lout::misc::assertNotReached ();
+ return false;
+ }
+}
+
+void OOFAwareWidget::notifySetParent ()
+{
+ // Search for containing blocks.
+ for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
+ oofContainer[oofmIndex] = NULL;
+
+ for (Widget *widget = this;
+ widget != NULL && oofContainer[oofmIndex] == NULL;
+ widget = widget->getParent ())
+ if (isOOFContainer (widget, oofmIndex)) {
+ assert (widget->instanceOf (OOFAwareWidget::CLASS_ID));
+ oofContainer[oofmIndex] = (OOFAwareWidget*)widget;
+ }
+
+ DBG_OBJ_ARRSET_PTR ("oofContainer", oofmIndex, oofContainer[oofmIndex]);
+
+ assert (oofContainer[oofmIndex] != NULL);
+ }
+}
+
+void OOFAwareWidget::initOutOfFlowMgrs ()
+{
+ if (oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] == NULL) {
+ oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] =
+ new OOFFloatsMgr (oofContainer[OOFM_FLOATS]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_FLOATS],
+ oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS]);
+ }
+
+ if (oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] == NULL) {
+ oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] =
+ new OOFPosAbsMgr (oofContainer[OOFM_ABSOLUTE]);
+ DBG_OBJ_ASSOC (oofContainer[OOFM_ABSOLUTE],
+ oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE]);
+ }
+
+ if (oofContainer[OOFM_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*))
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ int oofWidth, oofHeight;
+ DBG_OBJ_MSGF ("resize", 1,
+ "before considering widgets by OOFM #%d: %d * (%d + %d)",
+ i, requisition->width, requisition->ascent,
+ requisition->descent);
+
+ outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight);
+
+ if (oofWidth > requisition->width) {
+ if (adjustExtraSpaceWhenCorrectingRequisitionByOOF ())
+ extraSpace.right = max (extraSpace.right,
+ oofWidth - requisition->width);
+ requisition->width = oofWidth;
+ }
+
+ if (oofHeight > requisition->ascent + requisition->descent) {
+ if (adjustExtraSpaceWhenCorrectingRequisitionByOOF ())
+ extraSpace.bottom = max (extraSpace.bottom,
+ oofHeight - (requisition->ascent +
+ requisition->descent));
+ splitHeightFun (oofHeight,
+ &requisition->ascent, &requisition->descent);
+ }
+ }
+ }
+}
+
+void OOFAwareWidget::correctExtremesByOOF (Extremes *extremes)
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "OOFM (#%d) correction: %d / %d",
+ i, 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);
+ }
+ }
+}
+
+void OOFAwareWidget::sizeAllocateStart (core::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 ();
+}
+
+void OOFAwareWidget::drawOOF (View *view, Rectangle *area)
+{
+ for (int i = 0; i < NUM_OOFM; i++)
+ if(outOfFlowMgr[i])
+ outOfFlowMgr[i]->draw(view, area);
+}
+
+Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y)
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ Widget *oofWidget =
+ outOfFlowMgr[i] ?
+ outOfFlowMgr[i]->getWidgetAtPoint (x, y) : NULL;
+ if (oofWidget)
+ return oofWidget;
+ }
+
+ return NULL;
+}
+
+
+int OOFAwareWidget::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ if (isWidgetOOF(child)) {
+ assert (getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child));
+ return getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,
+ forceValue);
+ } else
+ return Widget::getAvailWidthOfChild (child, forceValue);
+}
+
+int OOFAwareWidget::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ if (isWidgetOOF(child)) {
+ assert (getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child));
+ return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child,
+ forceValue);
+ } else
+ return Widget::getAvailWidthOfChild (child, forceValue);
+}
+
+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));
+}
+
+core::Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y)
+{
+ if (x >= allocation.x &&
+ y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ()) {
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getTopWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ Widget *oofWidget = getWidgetOOFAtPoint (x, y);
+ if (oofWidget)
+ return oofWidget;
+
+ Widget *childAtPoint = NULL;
+ Iterator *it =
+ iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
+
+ while (childAtPoint == NULL && it->next ()) {
+ Widget *child = it->getContent()->widget;
+ if (!StackingContextMgr::handledByStackingContextMgr (child) &&
+ child->wasAllocated ())
+ childAtPoint = child->getWidgetAtPoint (x, y);
+ }
+
+ it->unref ();
+
+ if (childAtPoint)
+ return childAtPoint;
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ return this;
+ } else
+ return NULL;
+}
+
+void OOFAwareWidget::borderChanged (int y, Widget *vloat)
+{
+ assertNotReached ();
+}
+
+void OOFAwareWidget::clearPositionChanged ()
+{
+ assertNotReached ();
+}
+
+void OOFAwareWidget::oofSizeChanged (bool extremesChanged)
+{
+ DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s",
+ extremesChanged ? "true" : "false");
+ queueResize (-1, extremesChanged);
+
+ // Extremes changes may become also relevant for the children.
+ if (extremesChanged)
+ containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+int OOFAwareWidget::getLineBreakWidth ()
+{
+ assertNotReached ();
+ return 0;
+}
+
+bool OOFAwareWidget::isPossibleContainer (int oofmIndex)
+{
+ return oofmIndex != OOFM_FLOATS;
+}
+
+bool OOFAwareWidget::isPossibleContainerParent (int oofmIndex)
+{
+ return oofmIndex != OOFM_FLOATS;
+}
+
+bool OOFAwareWidget::adjustExtraSpaceWhenCorrectingRequisitionByOOF ()
+{
+ return true;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh
new file mode 100644
index 00000000..d2d5ef85
--- /dev/null
+++ b/dw/oofawarewidget.hh
@@ -0,0 +1,206 @@
+#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.)
+ *
+ * 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; see implementations of
+ * dw::oof::OOFAwareWidget. (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_FIXED, NUM_OOFM };
+ enum { PARENT_REF_OOFM_BITS = 2,
+ 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 ();
+ void print ();
+ };
+
+ 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];
+
+ inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex)
+ { return oofContainer[oofmIndex] ?
+ oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; }
+
+ static inline bool testWidgetFloat (Widget *widget)
+ { return widget->getStyle()->vloat != core::style::FLOAT_NONE; }
+ static inline bool testWidgetAbsolutelyPositioned (Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; }
+ static inline bool testWidgetFixedlyPositioned (Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_FIXED; }
+ static inline bool testWidgetPositioned (Widget *widget)
+ { return testWidgetAbsolutelyPositioned (widget) ||
+ testWidgetRelativelyPositioned (widget) ||
+ testWidgetFixedlyPositioned (widget); }
+ static inline bool testWidgetOutOfFlow (Widget *widget)
+ { return testWidgetFloat (widget) || testWidgetAbsolutelyPositioned (widget)
+ || testWidgetFixedlyPositioned (widget); }
+
+ static inline bool testWidgetRelativelyPositioned (Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_RELATIVE; }
+
+ 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 ();
+ void drawOOF (core::View *view, core::Rectangle *area);
+ core::Widget *getWidgetOOFAtPoint (int x, int y);
+
+ static bool isOOFContainer (Widget *widget, int oofmIndex);
+
+ void notifySetAsTopLevel();
+ void notifySetParent();
+
+ int getAvailWidthOfChild (Widget *child, bool forceValue);
+ int getAvailHeightOfChild (Widget *child, bool forceValue);
+
+ void removeChild (Widget *child);
+
+ core::Widget *getWidgetAtPoint (int x, int y);
+
+public:
+ static int CLASS_ID;
+
+ OOFAwareWidget ();
+ ~OOFAwareWidget ();
+
+ virtual void borderChanged (int y, core::Widget *vloat);
+ virtual void clearPositionChanged ();
+ virtual void oofSizeChanged (bool extremesChanged);
+ virtual int getLineBreakWidth (); // Should perhaps be renamed.
+ virtual bool isPossibleContainer (int oofmIndex);
+ virtual bool isPossibleContainerParent (int oofmIndex);
+ virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFAWAREWIDGET_HH__
diff --git a/dw/oofawarewidget_iterator.cc b/dw/oofawarewidget_iterator.cc
new file mode 100644
index 00000000..afafb5d5
--- /dev/null
+++ b/dw/oofawarewidget_iterator.cc
@@ -0,0 +1,261 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofawarewidget.hh"
+#include "ooffloatsmgr.hh"
+#include "oofposabsmgr.hh"
+#include "oofposfixedmgr.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace lout::misc;
+using namespace lout::object;
+
+namespace dw {
+
+namespace oof {
+
+// "numContentsInFlow" is passed here to avoid indirectly callin the (virtual)
+// method numContentsInFlow() from the constructor.
+OOFAwareWidget::OOFAwareWidgetIterator::OOFAwareWidgetIterator
+ (OOFAwareWidget *widget, Content::Type mask, bool atEnd,
+ int numContentsInFlow) :
+ Iterator (widget, mask, atEnd)
+{
+ if (atEnd) {
+ sectionIndex = NUM_SECTIONS - 1;
+ while (sectionIndex >= 0 &&
+ numParts (sectionIndex, numContentsInFlow) == 0)
+ sectionIndex--;
+ index = numParts (sectionIndex, numContentsInFlow);
+ } else {
+ sectionIndex = 0;
+ index = -1;
+ }
+
+ content.type = atEnd ? core::Content::END : core::Content::START;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::setValues (int sectionIndex,
+ int index)
+{
+ this->sectionIndex = sectionIndex;
+ this->index = index;
+
+ if (sectionIndex == 0 && index < 0)
+ content.type = core::Content::START;
+ else if (sectionIndex == NUM_SECTIONS - 1 &&
+ index >= numParts (sectionIndex))
+ content.type = core::Content::END;
+ else
+ getPart (sectionIndex, index, &content);
+}
+
+int OOFAwareWidget::OOFAwareWidgetIterator::numParts (int sectionIndex,
+ int numContentsInFlow)
+{
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget(), "numParts", "%d, %d",
+ sectionIndex, numContentsInFlow);
+
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+ int result;
+
+ if (sectionIndex == 0)
+ result = numContentsInFlow == -1 ?
+ this->numContentsInFlow () : numContentsInFlow;
+ else
+ result = widget->outOfFlowMgr[sectionIndex - 1] ?
+ widget->outOfFlowMgr[sectionIndex - 1]->getNumWidgets () : 0;
+
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget(), "=> %d", result);
+ DBG_OBJ_LEAVE_O (getWidget());
+ return result;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::getPart (int sectionIndex,
+ int index,
+ Content *content)
+{
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+
+ if (sectionIndex == 0)
+ getContentInFlow (index, content);
+ else {
+ content->type = Content::WIDGET_OOF_CONT;
+ content->widget =
+ widget->outOfFlowMgr[sectionIndex - 1]->getWidget (index);
+ }
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::intoStringBuffer (StringBuffer *sb)
+{
+ Iterator::intoStringBuffer (sb);
+ sb->append (", sectionIndex = ");
+ sb->appendInt (sectionIndex);
+ sb->append (", index = ");
+ sb->appendInt (index);
+}
+
+int OOFAwareWidget::OOFAwareWidgetIterator::compareTo (Comparable *other)
+{
+ OOFAwareWidgetIterator *otherTI = (OOFAwareWidgetIterator*)other;
+
+ if (sectionIndex != otherTI->sectionIndex)
+ return sectionIndex - otherTI->sectionIndex;
+ else
+ return index - otherTI->index;
+}
+
+bool OOFAwareWidget::OOFAwareWidgetIterator::next ()
+{
+ DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (),
+ "OOFAwareWidgetIterator/next");
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s",
+ sb.getChars ());
+ }
+
+ bool r;
+
+ if (content.type == Content::END)
+ r = false;
+ else {
+ r = true;
+ bool cancel = false;
+
+ do {
+ index++;
+
+ if (index < numParts(sectionIndex))
+ getPart (sectionIndex, index, &content);
+ else {
+ sectionIndex++;
+ while (sectionIndex < NUM_SECTIONS && numParts (sectionIndex) == 0)
+ sectionIndex++;
+
+ if (sectionIndex == NUM_SECTIONS) {
+ content.type = Content::END;
+ r = false;
+ cancel = true;
+ } else {
+ index = 0;
+ getPart (sectionIndex, index, &content);
+ }
+ }
+ } while (!cancel && (content.type & getMask()) == 0);
+ }
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s",
+ sb.getChars ());
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s",
+ r ? "true" : "false");
+ }
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+ return r;
+}
+
+bool OOFAwareWidget::OOFAwareWidgetIterator::prev ()
+{
+ DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (),
+ "OOFAwareWidgetIterator/prev");
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s",
+ sb.getChars ());
+ }
+
+ bool r;
+
+ if (content.type == Content::START)
+ r = false;
+ else {
+ r = true;
+ bool cancel = false;
+
+ do {
+ index--;
+
+ if (index >= 0)
+ getPart (sectionIndex, index, &content);
+ else {
+ sectionIndex--;
+ while (sectionIndex >= 0 && numParts (sectionIndex) == 0)
+ sectionIndex--;
+
+ if (sectionIndex < 0) {
+ content.type = Content::START;
+ r = false;
+ cancel = true;
+ } else {
+ index = numParts (sectionIndex) - 1;
+ getPart (sectionIndex, index, &content);
+ }
+ }
+ } while (!cancel && (content.type & getMask()) == 0);
+ }
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s",
+ sb.getChars ());
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s",
+ r ? "true" : "false");
+ }
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+ return r;
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::highlightOOF (int start, int end,
+ HighlightLayer layer)
+{
+ // TODO What about OOF widgets?
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::unhighlightOOF (int direction,
+ HighlightLayer
+ layer)
+{
+ // TODO What about OOF widgets?
+}
+
+void OOFAwareWidget::OOFAwareWidgetIterator::getAllocationOOF (int start,
+ int end,
+ Allocation
+ *allocation)
+{
+ // TODO Consider start and end?
+ OOFAwareWidget *widget = (OOFAwareWidget*)getWidget();
+ *allocation = *(widget->outOfFlowMgr[sectionIndex - 1]
+ ->getWidget(index)->getAllocation());
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc
new file mode 100644
index 00000000..fdfd986b
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,2314 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ooffloatsmgr.hh"
+#include "oofawarewidget.hh"
+#include "../lout/debug.hh"
+
+#include <limits.h>
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace dw {
+
+namespace oof {
+
+OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget)
+{
+ this->oofm = oofm;
+ this->widget = widget;
+ wasAllocated = false;
+ xCB = yCB = width = height = -1;
+}
+
+void OOFFloatsMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
+ int width, int height)
+{
+ DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
+ wasAllocated ? "true" : "false", xCB, yCB, width, height);
+
+ this->wasAllocated = wasAllocated;
+ this->xCB = xCB;
+ this->yCB = yCB;
+ this->width = width;
+ this->height = height;
+
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
+
+ DBG_OBJ_LEAVE_O (widget);
+}
+
+// ----------------------------------------------------------------------
+
+OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex)
+ : WidgetInfo (oofm, widget)
+{
+ this->generatingBlock = generatingBlock;
+ this->externalIndex = externalIndex;
+
+ yReq = yReal = size.width = size.ascent = size.descent = 0;
+ dirty = sizeChangedSinceLastAllocation = true;
+ indexGBList = indexCBList = -1;
+
+ // Sometimes a float with widget = NULL is created as a key; this
+ // is not interesting for RTFL.
+ if (widget) {
+ DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
+ sizeChangedSinceLastAllocation);
+ }
+}
+
+void OOFFloatsMgr::Float::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ sb->appendPointer (getWidget ());
+
+ if (getWidget ()) {
+ sb->append (" (");
+ sb->append (getWidget()->getClassName ());
+ sb->append (")");
+ }
+
+ sb->append (", indexGBList = ");
+ sb->appendInt (indexGBList);
+ sb->append (", indexCBList = ");
+ sb->appendInt (indexCBList);
+ sb->append (", sideSpanningIndex = ");
+ sb->appendInt (sideSpanningIndex);
+ sb->append (", generatingBlock = ");
+ sb->appendPointer (generatingBlock);
+ sb->append (", yReq = ");
+ sb->appendInt (yReq);
+ sb->append (", yReal = ");
+ sb->appendInt (yReal);
+ sb->append (", size = { ");
+ sb->appendInt (size.width);
+ sb->append (" * ");
+ sb->appendInt (size.ascent);
+ sb->append (" + ");
+ sb->appendInt (size.descent);
+ sb->append (" }, dirty = ");
+ sb->appendBool (dirty);
+ sb->append (", sizeChangedSinceLastAllocation = ");
+ sb->appendBool (sizeChangedSinceLastAllocation);
+ sb->append (" }");
+}
+
+bool OOFFloatsMgr::Float::covers (OOFAwareWidget *textblock, int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%p, %d, %d [vloat: %p]",
+ textblock, y, h, getWidget ());
+
+ bool b;
+
+ if (textblock == generatingBlock) {
+ int reqyGB = y;
+ int flyGB = yReal;
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ int flh = size.ascent + size.descent;
+ b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "for generator: reqyGB = %d, flyGB = %d, "
+ "flh = %d + %d = %d => %s",
+ reqyGB, flyGB, size.ascent, size.descent, flh,
+ b ? "true" : "false");
+ } else {
+ assert (getOOFFloatsMgr()->wasAllocated (generatingBlock));
+ assert (getOOFFloatsMgr()->wasAllocated (textblock));
+
+ if (!getWidget()->wasAllocated ()) {
+ DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (not allocated) => false");
+ b = false;
+ } else {
+ Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock),
+ //*gba = getOOFFloatsMgr()->getAllocation(generatingBlock),
+ *fla = getWidget()->getAllocation ();
+ int reqyCanv = tba->y + y;
+ int flyCanv = fla->y;
+ int flh = fla->ascent + fla->descent;
+ b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (allocated): reqyCanv = %d + %d = %d, "
+ "flyCanv = %d, flh = %d + %d = %d => %s",
+ tba->y, y, reqyCanv, flyCanv,
+ fla->ascent, fla->descent, flh, b ? "true" : "false");
+ }
+ }
+
+ DBG_OBJ_LEAVE_O (getOOFFloatsMgr ());
+
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
+ int r;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm,
+ "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
+ fl1->getIndex (type), fl2->getIndex (type), refTB);
+
+ if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
+ r = fl1->yReal - fl2->yReal;
+ } else {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ assert (oofm->wasAllocated (fl1->generatingBlock));
+ assert (oofm->wasAllocated (fl2->generatingBlock));
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
+ fl1->generatingBlock, fl2->generatingBlock);
+
+ // (i) Floats may not yet been allocated (although the
+ // generators are). Non-allocated floats do not have an effect
+ // yet, they are considered "at the end" of the list.
+
+ // (ii) Float::widget for the key used for binary search. In
+ // this case, Float::yReal is used instead (which is set in
+ // SortedFloatsVector::find).
+
+ 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 {
+ 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 {
+ fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
+ oofm->getAllocation(fl2->generatingBlock)->y,
+ fl2->yReal, fly2);
+ }
+
+ r = fly1 - fly2;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
+ } else if (a1 && !a2)
+ r = -1;
+ else if (!a1 && a2)
+ r = +1;
+ else // if (!a1 && !a2)
+ return 0;
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
+ Object *o2)
+{
+ return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
+}
+
+int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
+{
+ Float *f1 = (Float*)o1, *f2 = (Float*)o2;
+ int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
+ "#%d -> %p/%d, #%d -> %p/#%d",
+ f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
+ f2->getIndex (type), f2->generatingBlock,
+ f2->externalIndex);
+
+ if (f1->generatingBlock == f2->generatingBlock) {
+ r = f1->externalIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(a) generating blocks equal => %d - %d = %d",
+ f1->externalIndex, f2->externalIndex, r);
+ } else {
+ TBInfo *t1 = oofm->getOOFAwareWidget (f1->generatingBlock),
+ *t2 = oofm->getOOFAwareWidget (f2->generatingBlock);
+ bool rdef = false;
+
+ for (TBInfo *t = t1; t != NULL; t = t->parent)
+ if (t->parent == t2) {
+ rdef = true;
+ r = t->parentExtIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(b) %p is an achestor of %p; direct child is "
+ "%p (%d) => %d - %d = %d\n",
+ t2->getOOFAwareWidget (), t1->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ t->parentExtIndex, f2->externalIndex, r);
+ }
+
+ for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
+ if (t->parent == t1) {
+ r = f1->externalIndex - t->parentExtIndex;
+ rdef = true;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(c) %p is an achestor of %p; direct child is %p "
+ "(%d) => %d - %d = %d\n",
+ t1->getOOFAwareWidget (), t2->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ f1->externalIndex, t->parentExtIndex, r);
+ }
+
+ if (!rdef) {
+ r = t1->index - t2->index;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
+ t1->index, t2->index, r);
+ }
+ }
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
+ lastGB, lastExtIndex);
+
+ Float key (oofm, NULL, lastGB, lastExtIndex);
+ key.setIndex (type, -1); // for debugging
+ Float::CompareGBAndExtIndex comparator (oofm, type);
+ int i = bsearch (&key, false, &comparator);
+
+ // At position i is the next larger element, so element i should
+ // not included, but i - 1 returned; except if the exact element is
+ // found: then include it and so return i.
+ int r;
+ if (i == size())
+ r = i - 1;
+ else {
+ Float *f = get (i);
+ if (comparator.compare (f, &key) == 0)
+ r = i;
+ else
+ r = i - 1;
+ }
+
+ //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
+ // "in %s list %p on the %s side\n",
+ // oofm->container, lastGB, lastExtIndex, i, r, size (),
+ // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
+
+ //for (int i = 0; i < size (); i++) {
+ // Float *f = get(i);
+ // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock);
+ // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
+ // t->index, t->parent ? t->parent->textblock : NULL,
+ // get(i)->externalIndex);
+ //}
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::find (OOFAwareWidget *textblock, int y,
+ int start, int end)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d",
+ textblock, y, start, end);
+
+ Float key (oofm, NULL, NULL, 0);
+ key.generatingBlock = textblock;
+ key.yReal = y;
+ key.setIndex (type, -1); // for debugging
+ Float::ComparePosition comparator (oofm, textblock, type);
+ int result = bsearch (&key, false, start, end, &comparator);
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFirst (OOFAwareWidget *textblock,
+ int y, int h,
+ OOFAwareWidget *lastGB,
+ int lastExtIndex,
+ int *lastReturn)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d",
+ textblock, y, h, lastGB, lastExtIndex);
+
+ DBG_IF_RTFL {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ for (int i = 0; i < size(); i++) {
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), "
+ "%s, %s, ext = %d, GB = %p); widget at (%d, %d)",
+ i, get(i)->getWidget (), get(i)->getIndex (type),
+ get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal,
+ get(i)->size.width, get(i)->size.ascent,
+ get(i)->size.descent,
+ get(i)->dirty ? "dirty" : "clean",
+ get(i)->sizeChangedSinceLastAllocation ? "scsla"
+ : "sNcsla",
+ get(i)->externalIndex, get(i)->generatingBlock,
+ get(i)->getWidget()->getAllocation()->x,
+ get(i)->getWidget()->getAllocation()->y);
+ }
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ int last = findFloatIndex (lastGB, lastExtIndex);
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last);
+ assert (last < size());
+
+ // If the caller wants to reuse this value:
+ if (lastReturn)
+ *lastReturn = last;
+
+ int i = find (textblock, y, 0, last), result;
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i);
+
+ // Note: The smallest value of "i" is 0, which means that "y" is before or
+ // equal to the first float. The largest value is "last + 1", which means
+ // that "y" is after the last float. In both cases, the first or last,
+ // respectively, float is a candidate. Generally, both floats, before and
+ // at the search position, are candidates.
+
+ if (i > 0 && get(i - 1)->covers (textblock, y, h))
+ result = i - 1;
+ else if (i <= last && get(i)->covers (textblock, y, h))
+ result = i;
+ else
+ result = -1;
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex
+ (int sideSpanningIndex)
+{
+ OOFFloatsMgr::Float::CompareSideSpanningIndex comparator;
+ Float key (NULL, NULL, NULL, 0);
+ key.sideSpanningIndex = sideSpanningIndex;
+ return bsearch (&key, false, &comparator) - 1;
+}
+
+void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat)
+{
+ lout::container::typed::Vector<Float>::put (vloat);
+ vloat->setIndex (type, size() - 1);
+}
+
+OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex) :
+ WidgetInfo (oofm, textblock)
+{
+ this->parent = parent;
+ this->parentExtIndex = parentExtIndex;
+
+ leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB);
+ rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB);
+
+ wasAllocated = getWidget()->wasAllocated ();
+ allocation = *(getWidget()->getAllocation ());
+ clearPosition = 0;
+}
+
+OOFFloatsMgr::TBInfo::~TBInfo ()
+{
+ delete leftFloatsGB;
+ delete rightFloatsGB;
+}
+
+void OOFFloatsMgr::TBInfo::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container)
+{
+ DBG_OBJ_CREATE ("dw::OOFFloatsMgr");
+
+ this->container = (OOFAwareWidget*)container;
+
+ leftFloatsCB = new SortedFloatsVector (this, LEFT, CB);
+ rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB);
+
+ DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
+ DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
+
+ leftFloatsAll = new Vector<Float> (1, true);
+ rightFloatsAll = new Vector<Float> (1, true);
+
+ DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+
+ floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
+
+ tbInfos = new Vector<TBInfo> (1, false);
+ tbInfosByOOFAwareWidget =
+ new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true);
+
+ leftFloatsMark = rightFloatsMark = 0;
+ lastLeftTBIndex = lastRightTBIndex = 0;
+
+ containerWasAllocated = container->wasAllocated ();
+ containerAllocation = *(container->getAllocation());
+
+ addWidgetInFlow (this->container, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ //printf ("OOFFloatsMgr::~OOFFloatsMgr\n");
+
+ delete leftFloatsCB;
+ delete rightFloatsCB;
+
+ // Order is important: tbInfosByOOFAwareWidget is owner of the instances
+ // of TBInfo.tbInfosByOOFAwareWidget
+ delete tbInfos;
+ delete tbInfosByOOFAwareWidget;
+
+ delete floatsByWidget;
+
+ // Order is important, since the instances of Float are owned by
+ // leftFloatsAll and rightFloatsAll, so these should be deleted
+ // last.
+ delete leftFloatsAll;
+ delete rightFloatsAll;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ // Some callers are not registered, especially tables. (Where the
+ // floats manager is actually empty?)
+ TBInfo *oofAWInfo = getOOFAwareWidgetWhenRegistered (caller);
+ if (oofAWInfo) {
+ oofAWInfo->allocation = *allocation;
+ oofAWInfo->wasAllocated = true;
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *first* OOFM method
+ // called is sizeAllocateStart, with the containing block as an
+ // argument. So this is the correct point to initialize size
+ // allocation.
+
+ containerAllocation = *allocation;
+ containerWasAllocated = 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 OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (isOOFAwareWidgetRegistered (caller)) {
+ if (caller != container) {
+ // Allocate all floats "before" this textblock.
+ sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
+ sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
+ }
+
+ // The checks below do not cover "clear position" in all cases,
+ // so this is done here separately. This position is stored in
+ // TBInfo and calculated at this points; changes will be noticed
+ // to the textblock.
+ TBInfo *tbInfo = getOOFAwareWidget (caller);
+ int newClearPosition = calcClearPosition (caller);
+ if (newClearPosition != tbInfo->clearPosition) {
+ tbInfo->clearPosition = newClearPosition;
+ caller->clearPositionChanged ();
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *last* OOFM method called
+ // is sizeAllocateEnd, with the containing block as an
+ // argument. So this is the correct point to finish size
+ // allocation.
+
+ // Allocate all remaining floats.
+ sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1);
+ sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1);
+
+ // Check changes of both textblocks and floats allocation. (All
+ // is checked by hasRelationChanged (...).)
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ int minFloatPos;
+ Widget *minFloat;
+ if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
+ tb->borderChanged (minFloatPos, minFloat);
+ }
+
+ checkAllocatedFloatCollisions (LEFT);
+ checkAllocatedFloatCollisions (RIGHT);
+
+ // Store some information for later use.
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ tbInfo->updateAllocation ();
+ tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
+ }
+
+ // There are cases where some allocated floats (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)
+ container->oofSizeChanged (extremesChanged);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < leftFloatsAll->size (); i++)
+ leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloatsAll->size (); i++)
+ rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
+ Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, ...", tbInfo->getWidget ());
+
+ int leftMinPos, rightMinPos;
+ Widget *leftMinFloat, *rightMinFloat;
+ bool c1 =
+ hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
+ bool c2 =
+ hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
+ if (c1 || c2) {
+ if (!c1) {
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ } else if (!c2) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else {
+ if (leftMinPos < rightMinPos) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else{
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ }
+ }
+ }
+
+ if (c1 || c2)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "has changed: minFloatPos = %d, minFloat = %p",
+ *minFloatPos, *minFloat);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+ return c1 || c2;
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
+ int *minFloatPos, Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, %s, ...",
+ tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size(); i++) {
+ // TODO binary search?
+ Float *vloat = list->get(i);
+ int floatPos;
+
+ if (tbInfo->getOOFAwareWidget () == vloat->generatingBlock)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "not checking (generating!) textblock %p against float "
+ "%p", tbInfo->getWidget (), vloat->getWidget ());
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+
+ int newFlx =
+ calcFloatX (vloat, side,
+ gba->x - containerAllocation.x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+ int newFly = vloat->generatingBlock->getAllocation()->y
+ - containerAllocation.y + vloat->yReal;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "checking textblock %p against float %p",
+ tbInfo->getWidget (), vloat->getWidget ());
+ DBG_OBJ_MSG_START ();
+
+ if (hasRelationChanged (tbInfo->wasThenAllocated (),
+ tbInfo->getOldXCB (), tbInfo->getOldYCB (),
+ tbInfo->getNewWidth (),
+ tbInfo->getNewHeight (),
+ tbInfo->getNewXCB (), tbInfo->getNewYCB (),
+ tbInfo->getNewWidth (),
+ tbInfo->getNewHeight (),
+ vloat->wasThenAllocated (),
+ // When not allocated before, these values
+ // are undefined, but this does not matter,
+ // since they are neither used.
+ vloat->getOldXCB (), vloat->getOldYCB (),
+ vloat->getOldWidth (), vloat->getOldHeight (),
+ newFlx, newFly, vloat->size.width,
+ vloat->size.ascent + vloat->size.descent,
+ side, &floatPos)) {
+ if (!changed || floatPos < *minFloatPos) {
+ *minFloatPos = floatPos;
+ *minFloat = vloat->getWidget ();
+ }
+ changed = true;
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 0, "No.");
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ // All floarts are searched, to find the minimum. TODO: Are
+ // floats sorted, so this can be shortened? (The first is the
+ // minimum?)
+ }
+
+ if (changed)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "has changed: minFloatPos = %d, minFloat = %p",
+ *minFloatPos, *minFloat);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+ return changed;
+}
+
+/**
+ * \brief ...
+ *
+ * All coordinates are given relative to the CB. *floatPos is relative
+ * to the TB, and may be negative.
+ */
+bool OOFFloatsMgr::hasRelationChanged (bool oldTBAlloc,
+ int oldTBx, int oldTBy, int oldTBw,
+ int oldTBh, int newTBx, int newTBy,
+ int newTBw, int newTBh,
+ bool oldFlAlloc,
+ int oldFlx, int oldFly, int oldFlw,
+ int oldFlh, int newFlx, int newFly,
+ int newFlw, int newFlh,
+ Side side, int *floatPos)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT");
+
+ if (oldTBAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d",
+ oldTBx, oldTBy, oldTBw, oldTBh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d",
+ newTBx, newTBy, newTBw, newTBh);
+
+ if (oldFlAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d",
+ oldFlx, oldFly, oldFlw, oldFlh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d",
+ newFlx, newFly, newFlw, newFlh);
+
+ bool result;
+ if (oldTBAlloc && oldFlAlloc) {
+ bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh;
+ bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.",
+ oldCov ? "yes" : "no", newCov ? "yes" : "no");
+ DBG_OBJ_MSG_START ();
+
+ if (oldCov && newCov) {
+ int yOld = oldFly - oldTBy, yNew = newFly - newTBy;
+ if (yOld == yNew) {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d) and new (%d - %d) position equal: %d",
+ oldFly, oldTBy, newFly, newTBy, yOld);
+
+ // Float position has not changed, but perhaps the amout
+ // how far the float reaches into the TB. (TODO:
+ // Generally, not only here, it could be tested whether
+ // the float reaches into the TB at all.)
+ int wOld, wNew;
+ if (side == LEFT) {
+ wOld = oldFlx + oldFlw - oldTBx;
+ wNew = newFlx + newFlw - newTBx;
+ } else {
+ wOld = oldTBx + oldTBw - oldFlx;
+ wNew = newTBx + newTBw - newFlx;
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n",
+ wOld, wNew);
+
+ if (wOld == wNew) {
+ if (oldFlh == newFlh)
+ result = false;
+ else {
+ // Only heights of floats changed. Relevant only
+ // from bottoms of float.
+ *floatPos = min (yOld + oldFlh, yNew + newFlh);
+ result = true;
+ }
+ } else {
+ *floatPos = yOld;
+ result = true;
+ }
+ } else {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d = %d) and new (%d - %d = %d) position "
+ "different",
+ oldFly, oldTBy, yOld, newFly, newTBy, yNew);
+ *floatPos = min (yOld, yNew);
+ result = true;
+ }
+ } else if (oldCov) {
+ *floatPos = oldFly - oldTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning old position: %d - %d = %d", oldFly, oldTBy,
+ *floatPos);
+ } else if (newCov) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning new position: %d - %d = %d", newFly, newTBy,
+ *floatPos);
+ } else
+ result = false;
+
+ DBG_OBJ_MSG_END ();
+ } else {
+ // Not allocated before: ignore all old values, only check whether
+ // TB is covered by Float.
+ if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ } else
+ result = false;
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d",
+ *floatPos);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+
+ return result;
+}
+
+void OOFFloatsMgr::checkAllocatedFloatCollisions (Side side)
+{
+ // In some cases, the collision detection in tellPosition() is
+ // based on the wrong allocations. Here (just after all Floats have
+ // been allocated), we correct this.
+
+ // TODO In some cases this approach is rather slow, causing a too
+ // long queueResize() cascade.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB;
+
+ // While iterating through the list of floats to be checked, we
+ // iterate equally through the list of the opposite floats, using
+ // this index:
+ int oppIndex = 0;
+
+ for (int index = 0; index < list->size (); index++) {
+ Float *vloat = list->get(index);
+ bool needsChange = false;
+ int yRealNew = INT_MAX;
+
+ // Same side.
+ if (index >= 1) {
+ Float *other = list->get(index - 1);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same side: checking %p (#%d, GB: %p) against "
+ "%p (#%d, GB: %p)",
+ vloat->getWidget (), index, vloat->generatingBlock,
+ other->getWidget (), index - 1, other->generatingBlock);
+
+ if (vloat->generatingBlock != other->generatingBlock) {
+ int yRealNewSame;
+ if (collidesV (vloat, other, CB, &yRealNewSame)) {
+ 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);
+ oppIndexTmp--) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "opposite side (after collision (v) test): "
+ "checking %p (#%d/%d, GB: %p) against "
+ "%p (#%d/%d, GB: %p)",
+ vloat->getWidget (), index,
+ vloat->sideSpanningIndex,
+ vloat->generatingBlock,
+ oppList->get(oppIndexTmp)->getWidget (),
+ oppList->get(oppIndexTmp)->getIndex (CB),
+ oppList->get(oppIndexTmp)->sideSpanningIndex,
+ oppList->get(oppIndexTmp)->generatingBlock);
+
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides (h), new yReal = %d (old: %d)",
+ yRealNewOpp, vloat->yReal);
+ foundColl = true;
+ if (vloat->yReal != yRealNewOpp) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewOpp);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
+ }
+ }
+ }
+
+ if (needsChange)
+ vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
+ vloat->getWidget ());
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::doFloatsExceedCB (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This method is called to determine whether the *requisition* of
+ // the CB must be recalculated. So, we check the float allocations
+ // against the *requisition* of the CB, which may (e. g. within
+ // tables) differ from the new allocation. (Generally, a widget may
+ // allocated at a different size.)
+ core::Requisition cbReq;
+ container->sizeRequest (&cbReq);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool exceeds = false;
+
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < list->size () && !exceeds; i++) {
+ Float *vloat = list->get (i);
+ if (vloat->getWidget()->wasAllocated ()) {
+ Allocation *fla = vloat->getWidget()->getAllocation ();
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "Does FlA = (%d, %d, %d * %d) exceed CB req+alloc = "
+ "(%d, %d, %d * %d)?",
+ fla->x, fla->y, fla->width, fla->ascent + fla->descent,
+ containerAllocation.x, containerAllocation.y,
+ cbReq.width, cbReq.ascent + cbReq.descent);
+ if (fla->x + fla->width > containerAllocation.x + cbReq.width ||
+ fla->y + fla->ascent + fla->descent
+ > containerAllocation.y + cbReq.ascent + cbReq.descent) {
+ exceeds = true;
+ DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 2, "No.");
+ }
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return exceeds;
+}
+
+bool OOFFloatsMgr::haveExtremesChanged (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This is quite different from doFloatsExceedCB, since there is no
+ // counterpart to getExtremes, as sizeAllocate is a counterpart to
+ // sizeRequest. So we have to determine whether the allocation has
+ // changed the extremes, which is done by examining the part of the
+ // allocation which is part of the extremes calculation (see
+ // getFloatsExtremes). Changes of the extremes are handled by the
+ // normal queueResize mechanism.
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size () && !changed; i++) {
+ Float *vloat = list->get (i);
+ // When the GB is the CB, an allocation change does not play a
+ // role here.
+ if (vloat->generatingBlock != container) {
+ if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
+ changed = true;
+ else {
+ // This method is called within sizeAllocateEnd, where
+ // containinBlock->getAllocation() (old value) and
+ // containinBlockAllocation (new value) are different.
+
+ Allocation *oldCBA = container->getAllocation ();
+ Allocation *newCBA = &containerAllocation;
+
+ // Compare also to getFloatsExtremes. The box difference
+ // of the GB (from style) has not changed in this context,
+ // so it is ignored.
+
+ int oldDiffLeft = vloat->getOldXCB ();
+ int newDiffLeft = vloat->getNewXCB ();
+ int oldDiffRight =
+ oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
+ int newDiffRight =
+ newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
+
+ if (// regarding minimum
+ (side == LEFT && oldDiffLeft != newDiffLeft) ||
+ (side == RIGHT && oldDiffRight != newDiffRight) ||
+ // regarding maximum
+ oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
+ changed = true;
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return changed;
+}
+
+void OOFFloatsMgr::moveFromGBToCB (Side side)
+{
+ DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
+
+ for (int mark = 0; mark <= *floatsMark; mark++)
+ for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
+ it.hasNext (); ) {
+ TBInfo *tbInfo = it.getNext ();
+ SortedFloatsVector *src =
+ side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ for (int i = 0; i < src->size (); i++) {
+ Float *vloat = src->get (i);
+ // "vloat->indexCBList == -1": prevent copying the vloat twice.
+ if (vloat->indexCBList == -1 && vloat->mark == mark) {
+ dest->put (vloat);
+ DBG_OBJ_MSGF ("oofm.resize", 1,
+ "moving float %p (mark %d) to CB list\n",
+ vloat->getWidget (), vloat->mark);
+ DBG_OBJ_SET_NUM (side == LEFT ?
+ "leftFloatsCB.size" : "rightFloatsCB.size",
+ dest->size());
+ DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
+ "leftFloatsCB" : "rightFloatsCB",
+ dest->size() - 1, "widget",
+ vloat->getWidget ());
+
+ }
+ }
+ }
+
+ *floatsMark = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
+{
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *lastAllocatedFloat =
+ side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
+ "%s, [%d ->] %d [size = %d]",
+ side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
+ newLastAllocatedFloat, list->size ());
+
+ Allocation *cba = &containerAllocation;
+
+ for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
+ Float *vloat = list->get(i);
+ ensureFloatSize (vloat);
+
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth();
+
+ Allocation childAllocation;
+ childAllocation.x = cba->x +
+ calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth);
+ 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 ();
+}
+
+
+/**
+ * \brief ...
+ *
+ * gbX is given relative to the CB, as is the return value.
+ */
+int OOFFloatsMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
+ int gbLineBreakWidth)
+{
+ DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d, %d",
+ vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
+ gbWidth, gbLineBreakWidth);
+ 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->boxOffsetX();
+ DBG_OBJ_MSGF ("resize.oofm", 1, "left: x = %d + %d = %d",
+ gbX, vloat->generatingBlock->boxOffsetX(), x);
+ // ... but when the float exceeds the line break width of the
+ // container, it is corrected (but not left of the container).
+ // This way, we save space and, especially within tables, avoid
+ // some problems.
+ if (wasAllocated (container) &&
+ x + vloat->size.width > container->getLineBreakWidth ()) {
+ x = max (0, container->getLineBreakWidth () - vloat->size.width);
+ DBG_OBJ_MSGF ("resize.common", 1,
+ "corrected to: max (0, %d - %d) = %d",
+ container->getLineBreakWidth (), vloat->size.width,
+ x);
+ }
+ break;
+
+ case RIGHT:
+ // Similar for right floats, but in this case, floats are
+ // shifted to the right when they are too big (instead of
+ // shifting the generator to the right).
+
+ // Notice that not the actual width, but the line break width is
+ // used. (This changed for GROWS, where the width of a textblock
+ // is often smaller that the line break.)
+
+ x = max (gbX + gbLineBreakWidth - vloat->size.width
+ - vloat->generatingBlock->boxRestWidth(),
+ // Do not exceed CB allocation:
+ 0);
+ DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d",
+ gbX, gbLineBreakWidth, vloat->size.width,
+ vloat->generatingBlock->boxRestWidth(), x);
+ break;
+
+ default:
+ assertNotReached ();
+ x = 0;
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return x;
+}
+
+
+void OOFFloatsMgr::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawFloats (leftFloatsCB, view, area);
+ drawFloats (rightFloatsCB, view, area);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::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++) {
+ Widget *childWidget = list->get(i)->getWidget ();
+ Rectangle childArea;
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->intersects (area, &childArea))
+ childWidget->draw (view, &childArea);
+ }
+}
+
+void OOFFloatsMgr::addWidgetInFlow (OOFAwareWidget *textblock,
+ OOFAwareWidget *parentBlock,
+ int externalIndex)
+{
+ //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
+ // container, textblock, parentBlock, externalIndex);
+
+ TBInfo *tbInfo =
+ new TBInfo (this, textblock,
+ parentBlock ? getOOFAwareWidget (parentBlock) : NULL,
+ externalIndex);
+ tbInfo->index = tbInfos->size();
+
+ tbInfos->put (tbInfo);
+ tbInfosByOOFAwareWidget->put (new TypedPointer<OOFAwareWidget> (textblock),
+ tbInfo);
+}
+
+int OOFFloatsMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generatingBlock,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generatingBlock, externalIndex);
+
+ int subRef;
+
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
+
+ // Note: Putting the float first in the GB list, and then, possibly
+ // into the CB list (in that order) will trigger setting
+ // Float::inCBList to the right value.
+
+ switch (widget->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ leftFloatsAll->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
+ subRef = createSubRefLeftFloat (leftFloatsAll->size() - 1);
+ tbInfo->leftFloatsGB->put (vloat);
+
+ if (wasAllocated (generatingBlock)) {
+ leftFloatsCB->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1,
+ "widget", vloat->getWidget ());
+ } else {
+ if (tbInfo->index < lastLeftTBIndex)
+ leftFloatsMark++;
+
+ vloat->mark = leftFloatsMark;
+ lastLeftTBIndex = tbInfo->index;
+ }
+ break;
+
+ case FLOAT_RIGHT:
+ rightFloatsAll->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
+ subRef = createSubRefRightFloat (rightFloatsAll->size() - 1);
+ tbInfo->rightFloatsGB->put (vloat);
+
+ if (wasAllocated (generatingBlock)) {
+ rightFloatsCB->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1,
+ "widget", vloat->getWidget ());
+ } else {
+ if (tbInfo->index < lastRightTBIndex)
+ rightFloatsMark++;
+
+ vloat->mark = rightFloatsMark;
+ lastRightTBIndex = tbInfo->index;
+ }
+
+ break;
+
+ default:
+ assertNotReached();
+ }
+
+ // "sideSpanningIndex" is only compared, so this simple assignment
+ // is sufficient; differenciation between GB and CB lists is not
+ // neccessary. TODO: Can this also be applied to "index", to
+ // simplify the current code? Check: where is "index" used.
+ vloat->sideSpanningIndex =
+ leftFloatsAll->size() + rightFloatsAll->size() - 1;
+
+ floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
+
+ DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef);
+ DBG_OBJ_LEAVE ();
+ return subRef;
+}
+
+void OOFFloatsMgr::moveExternalIndices (OOFAwareWidget *generatingBlock,
+ int oldStartIndex, int diff)
+{
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff);
+ moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff);
+}
+
+void OOFFloatsMgr::moveExternalIndices (SortedFloatsVector *list,
+ int oldStartIndex, int diff)
+{
+ // Could be faster with binary search, but the GB (not CB!) lists
+ // should be rather small.
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ if (vloat->externalIndex >= oldStartIndex) {
+ vloat->externalIndex += diff;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
+ vloat->externalIndex);
+ }
+ }
+}
+
+OOFFloatsMgr::Float *OOFFloatsMgr::findFloatByWidget (Widget *widget)
+{
+ TypedPointer <Widget> key (widget);
+ Float *vloat = floatsByWidget->get (&key);
+ assert (vloat != NULL);
+ return vloat;
+}
+
+void OOFFloatsMgr::markSizeChange (int ref)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
+
+ Float *vloat;
+
+ if (isSubRefLeftFloat (ref))
+ vloat = leftFloatsAll->get (getFloatIndexFromSubRef (ref));
+ else if (isSubRefRightFloat (ref))
+ vloat = rightFloatsAll->get (getFloatIndexFromSubRef (ref));
+ else {
+ assertNotReached();
+ vloat = NULL; // compiler happiness
+ }
+
+ vloat->dirty = vloat->sizeChangedSinceLastAllocation = true;
+
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (),
+ "<Float>.sizeChangedSinceLastAllocation",
+ vloat->sizeChangedSinceLastAllocation);
+
+ // The generating block is told directly about this. (Others later, in
+ // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which
+ // differentiates many special cases), but the size is not known yet,
+ vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ());
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFFloatsMgr::markExtremesChange (int ref)
+{
+ // Nothing to do here.
+}
+
+Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y)
+{
+ Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y);
+ if (childAtPoint == NULL)
+ childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y);
+ return childAtPoint;
+}
+
+Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x,
+ int y)
+{
+ for (int i = 0; i < list->size(); i++) {
+ // Could use binary search to be faster.
+ Widget *childWidget = list->get(i)->getWidget ();
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->wasAllocated ()) {
+ Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y);
+ if (childAtPoint)
+ return childAtPoint;
+ }
+ }
+
+ return NULL;
+}
+
+void OOFFloatsMgr::tellPosition (Widget *widget, int x, int y)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d, %d",
+ widget, x, y);
+
+ assert (y >= 0);
+
+ Float *vloat = findFloatByWidget(widget);
+
+ SortedFloatsVector *listSame, *listOpp;
+ Side side;
+ getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
+ ensureFloatSize (vloat);
+
+ // "yReal" may change due to collisions (see below).
+ vloat->yReq = vloat->yReal = y;
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+
+ // Test collisions (on this side). Although there are (rare) cases
+ // where it could make sense, the horizontal dimensions are not
+ // tested; especially since searching and border calculation would
+ // be confused. For this reaspn, only the previous float is
+ // relevant. (Cf. below, collisions on the other side.)
+ int index = vloat->getIndex (listSame->type), yRealNew;
+ if (index >= 1 &&
+ collidesV (vloat, listSame->get (index - 1), listSame->type,
+ &yRealNew)) {
+ 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);
+ 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 OOFFloatsMgr::collidesV (Float *vloat, Float *other, SFVType type,
+ int *yReal)
+{
+ // 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 {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (wasAllocated (other->generatingBlock));
+
+ // 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 {
+ Allocation *gba = getAllocation (vloat->generatingBlock),
+ *flaOther = other->getWidget()->getAllocation ();
+ int otherBottomGB =
+ flaOther->y + flaOther->ascent + flaOther->descent - gba->y;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "different generators: "
+ "otherBottomGB = %d + (%d + %d) - %d = %d",
+ flaOther->y, flaOther->ascent, flaOther->descent, gba->y,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ }
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
+
+ DBG_OBJ_LEAVE ();
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other, SFVType type)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generatingBlock == other->generatingBlock)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generatingBlock->boxDiffWidth()
+ > vloat->generatingBlock->getLineBreakWidth();
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (wasAllocated (other->generatingBlock));
+
+ // 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 {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ int vloatX =
+ calcFloatX (vloat,
+ vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
+ LEFT : RIGHT,
+ gba->x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+
+ // Generally: right border of the left float > left border of
+ // the right float (all in canvas coordinates).
+ if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
+ // "vloat" is left, "other" is right
+ collidesH = vloatX + vloat->size.width
+ > other->getWidget()->getAllocation()->x;
+ else
+ // "other" is left, "vloat" is right
+ collidesH = other->getWidget()->getAllocation()->x
+ + other->getWidget()->getAllocation()->width
+ > vloatX;
+ }
+ }
+
+ return collidesH;
+}
+
+void OOFFloatsMgr::getFloatsListsAndSide (Float *vloat,
+ SortedFloatsVector **listSame,
+ SortedFloatsVector **listOpp,
+ Side *side)
+{
+ TBInfo *tbInfo = getOOFAwareWidget (vloat->generatingBlock);
+
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ if (wasAllocated (vloat->generatingBlock)) {
+ if (listSame) *listSame = leftFloatsCB;
+ if (listOpp) *listOpp = rightFloatsCB;
+ } else {
+ if (listSame) *listSame = tbInfo->leftFloatsGB;
+ if (listOpp) *listOpp = tbInfo->rightFloatsGB;
+ }
+ if (side) *side = LEFT;
+ break;
+
+ case FLOAT_RIGHT:
+ if (wasAllocated (vloat->generatingBlock)) {
+ if (listSame) *listSame = rightFloatsCB;
+ if (listOpp) *listOpp = leftFloatsCB;
+ } else {
+ if (listSame) *listSame = tbInfo->rightFloatsGB;
+ if (listOpp) *listOpp = tbInfo->leftFloatsGB;
+ }
+ if (side) *side = RIGHT;
+ break;
+
+ default:
+ assertNotReached();
+ }
+}
+
+void OOFFloatsMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight)
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
+
+ int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
+ getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
+ getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
+
+ // Floats must be within the *content* area of the containing
+ // block, not its *margin* area (which is equivalent to the
+ // requisition / allocation). For this reason, boxRestWidth() and
+ // boxRestHeight() are added here.
+
+ *oofWidth =
+ max (oofWidthtLeft, oofWidthRight) + container->boxRestWidth ();
+ *oofHeight =
+ max (oofHeightLeft, oofHeightRight) + container->boxRestHeight ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)",
+ oofWidthtLeft, oofWidthRight, *oofWidth, oofHeightLeft,
+ oofHeightRight, *oofHeight);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
+ int *height)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
+ cbReq->width, cbReq->ascent, cbReq->descent,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side);
+
+ *width = *height = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ if (vloat->generatingBlock == container ||
+ wasAllocated (vloat->generatingBlock)) {
+ ensureFloatSize (vloat);
+ int x, y;
+
+ if (vloat->generatingBlock == container) {
+ x = calcFloatX (vloat, side, 0, cbReq->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+ y = vloat->yReal;
+ } else {
+ Allocation *gba = getAllocation(vloat->generatingBlock);
+ x = calcFloatX (vloat, side,
+ gba->x - containerAllocation.x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+ y = gba->y - containerAllocation.y + vloat->yReal;
+ }
+
+ *width = max (*width, x + vloat->size.width);
+ *height = max (*height, y + vloat->size.ascent + vloat->size.descent);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: (%d + %d) * "
+ "(%d + (%d + %d)) => %d * %d",
+ vloat->getWidget (), vloat->generatingBlock,
+ x, vloat->size.width,
+ y, vloat->size.ascent, vloat->size.descent,
+ *width, *height);
+ } else
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: not allocated",
+ vloat->getWidget (), vloat->generatingBlock);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ cbExtr->minWidth, cbExtr->maxWidth);
+
+ int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
+ getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
+ getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
+
+ *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
+ *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
+ oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
+ oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
+ int *minWidth, int *maxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
+ cbExtr->minWidth, cbExtr->maxWidth,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ *minWidth = *maxWidth = 0;
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ int leftDiff, rightDiff;
+
+ if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) {
+ Extremes extr;
+ vloat->getWidget()->getExtremes (&extr);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: %d / %d",
+ vloat->getWidget (), vloat->generatingBlock,
+ extr.minWidth, extr.maxWidth);
+
+ // TODO: Or zero (instead of rightDiff) for right floats?
+ *minWidth =
+ max (*minWidth,
+ extr.minWidth + (side == LEFT ? leftDiff : rightDiff));
+ *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth);
+ } else
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: not allocated",
+ vloat->getWidget (), vloat->generatingBlock);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+// Returns "false" when borders cannot yet determined; *leftDiff and
+// *rightDiff are undefined in this case.
+bool OOFFloatsMgr::getFloatDiffToCB (Float *vloat, int *leftDiff,
+ int *rightDiff)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB",
+ "float %p [generated by %p], ...",
+ vloat->getWidget (), vloat->generatingBlock);
+
+ bool result;
+
+ if (vloat->generatingBlock == container) {
+ *leftDiff = vloat->generatingBlock->boxOffsetX();
+ *rightDiff = vloat->generatingBlock->boxRestWidth();
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "GB == CB => leftDiff = %d, rightDiff = %d",
+ *leftDiff, *rightDiff);
+ } else if (wasAllocated (vloat->generatingBlock)) {
+ Allocation *gba = getAllocation(vloat->generatingBlock);
+ *leftDiff = gba->x - containerAllocation.x
+ + vloat->generatingBlock->boxOffsetX();
+ *rightDiff =
+ (containerAllocation.x + containerAllocation.width)
+ - (gba->x + gba->width)
+ + vloat->generatingBlock->boxRestWidth();
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "GB != CB => leftDiff = %d - %d + %d = %d, "
+ "rightDiff = (%d + %d) - (%d + %d) + %d = %d",
+ gba->x, containerAllocation.x,
+ vloat->generatingBlock->boxOffsetX(), *leftDiff,
+ containerAllocation.x, containerAllocation.width,
+ gba->x, gba->width, vloat->generatingBlock->boxRestWidth(),
+ *rightDiff);
+ } else {
+ DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated");
+ result = false;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return result;
+}
+
+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;
+}
+
+/**
+ * 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 OOFFloatsMgr::getLeftBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d",
+ textblock, y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+/**
+ * Get the right border for the vertical position of *y*, for a height
+ * of *h*, based on floats.
+ *
+ * See also getLeftBorder(int, int);
+ */
+int OOFFloatsMgr::getRightBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d",
+ textblock, y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getBorder (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int last;
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+
+ if (first == -1) {
+ // No float.
+ DBG_OBJ_LEAVE ();
+ return 0;
+ } else {
+ // It is not sufficient to find the first float, since a line
+ // (with height h) may cover the region of multiple float, of
+ // which the widest has to be choosen.
+ int border = 0;
+ bool covers = true;
+
+ // We are not searching until the end of the list, but until the
+ // float defined by lastGB and lastExtIndex.
+ for (int i = first; covers && i <= last; i++) {
+ Float *vloat = list->get(i);
+ covers = vloat->covers (textblock, y, h);
+ DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
+ i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
+
+ if (covers) {
+ int thisBorder;
+ if (vloat->generatingBlock == textblock) {
+ int borderIn = side == LEFT ?
+ vloat->generatingBlock->boxOffsetX() :
+ vloat->generatingBlock->boxRestWidth();
+ thisBorder = vloat->size.width + borderIn;
+ DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d",
+ vloat->size.width, borderIn, thisBorder);
+ } else {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (vloat->getWidget()->wasAllocated ());
+
+ Allocation *tba = getAllocation(textblock),
+ *fla = vloat->getWidget()->getAllocation ();
+ if (side == LEFT) {
+ thisBorder = fla->x + fla->width - tba->x;
+ DBG_OBJ_MSGF ("border", 1,
+ "not GB: thisBorder = %d + %d - %d = %d",
+ fla->x, fla->width, tba->x, thisBorder);
+ } else {
+ // See also calcFloatX.
+ thisBorder =
+ tba->x + textblock->getLineBreakWidth () - fla->x;
+ DBG_OBJ_MSGF ("border", 1,
+ "not GB: thisBorder = %d + %d - %d "
+ "= %d",
+ tba->x, textblock->getLineBreakWidth (), fla->x,
+ thisBorder);
+ }
+ }
+
+ border = max (border, thisBorder);
+ DBG_OBJ_MSGF ("border", 1, "=> border = %d", border);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+ return border;
+ }
+}
+
+
+OOFFloatsMgr::SortedFloatsVector *OOFFloatsMgr::getFloatsListForOOFAwareWidget
+ (OOFAwareWidget *textblock, Side side)
+{
+ DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForOOFAwareWidget", "%p, %s",
+ textblock, side == LEFT ? "LEFT" : "RIGHT");
+
+ OOFFloatsMgr::SortedFloatsVector *list;
+
+ if (wasAllocated (textblock)) {
+ DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list");
+ list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ } else {
+ DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list");
+ TBInfo *tbInfo = getOOFAwareWidget (textblock);
+ list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return list;
+}
+
+
+bool OOFFloatsMgr::hasFloatLeft (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s",
+ textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloatRight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s",
+ textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloat (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+ DBG_OBJ_LEAVE ();
+ return first != -1;
+}
+
+int OOFFloatsMgr::getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getRightFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex);
+}
+
+// Calculate height from the position *y*.
+int OOFFloatsMgr::getFloatHeight (OOFAwareWidget *textblock, Side side, int y,
+ int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d",
+ textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
+ lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side);
+ int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
+ assert (first != -1); /* This method must not be called when there is no
+ float on the respective side. */
+
+ Float *vloat = list->get(first);
+ int yRelToFloat;
+
+ if (vloat->generatingBlock == textblock) {
+ yRelToFloat = y - vloat->yReal;
+ DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
+ y, vloat->yReal, yRelToFloat);
+ } else {
+ // The respective widgets are allocated; otherwise, hasFloat() would have
+ // returned false.
+ assert (wasAllocated (textblock));
+ assert (vloat->getWidget()->wasAllocated ());
+
+ Allocation *tba = getAllocation(textblock),
+ *fla = vloat->getWidget()->getAllocation ();
+ yRelToFloat = tba->y + y - fla->y;
+
+ DBG_OBJ_MSGF ("border", 1,
+ "caller is not CB: yRelToFloat = %d + %d - %d = %d",
+ tba->y, y, fla->y, yRelToFloat);
+ }
+
+ ensureFloatSize (vloat);
+ int height = vloat->size.ascent + vloat->size.descent - yRelToFloat;
+
+ DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d",
+ vloat->size.ascent, vloat->size.descent, yRelToFloat, height);
+ DBG_OBJ_LEAVE ();
+ return height;
+}
+
+/**
+ * Returns position relative to the textblock "tb".
+ */
+int OOFFloatsMgr::getClearPosition (OOFAwareWidget *textblock)
+{
+ return getOOFAwareWidget(textblock)->clearPosition;
+}
+
+int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", textblock);
+
+ int pos;
+
+ if (textblock->getStyle()) {
+ bool left = false, right = false;
+ switch (textblock->getStyle()->clear) {
+ case CLEAR_NONE: break;
+ case CLEAR_LEFT: left = true; break;
+ case CLEAR_RIGHT: right = true; break;
+ case CLEAR_BOTH: left = right = true; break;
+ default: assertNotReached ();
+ }
+
+ pos = max (left ? calcClearPosition (textblock, LEFT) : 0,
+ right ? calcClearPosition (textblock, RIGHT) : 0);
+ } else
+ pos = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
+ DBG_OBJ_LEAVE ();
+
+ return pos;
+}
+
+bool OOFFloatsMgr::affectsLeftBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_LEFT;
+}
+
+bool OOFFloatsMgr::affectsRightBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_RIGHT;
+};
+
+bool OOFFloatsMgr::mayAffectBordersAtAll ()
+{
+ return true;
+}
+
+int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock, Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s",
+ textblock, side == LEFT ? "LEFT" : "RIGHT");
+
+ int pos;
+
+ if (!wasAllocated (textblock))
+ // There is no relation yet to floats generated by other
+ // textblocks, and this textblocks floats are unimportant for
+ // the "clear" property.
+ pos = 0;
+ else {
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+
+ // Search the last float before (therfore -1) this textblock.
+ int i = list->findFloatIndex (textblock, -1);
+ if (i < 0) {
+ pos = 0;
+ DBG_OBJ_MSG ("resize.oofm", 1, "no float");
+ } else {
+ Float *vloat = list->get(i);
+ assert (vloat->generatingBlock != textblock);
+ if (!wasAllocated (vloat->generatingBlock))
+ pos = 0; // See above.
+ else {
+ ensureFloatSize (vloat);
+ pos = max (getAllocation(vloat->generatingBlock)->y + vloat->yReal
+ + vloat->size.ascent + vloat->size.descent
+ - getAllocation(textblock)->y,
+ 0);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p => max (%d + %d + (%d + %d) - %d, 0)",
+ vloat->getWidget (),
+ getAllocation(vloat->generatingBlock)->y,
+ vloat->yReal, vloat->size.ascent, vloat->size.descent,
+ getAllocation(textblock)->y);
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
+ DBG_OBJ_LEAVE ();
+
+ return pos;
+}
+
+void OOFFloatsMgr::ensureFloatSize (Float *vloat)
+{
+ // Historical note: relative sizes (e. g. percentages) are already
+ // handled by (at this time) Layout::containerSizeChanged, so
+ // Float::dirty will be set.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p",
+ vloat->getWidget ());
+
+ if (vloat->dirty) {
+ DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation");
+
+ vloat->getWidget()->sizeRequest (&vloat->size);
+ vloat->cbLineBreakWidth = container->getLineBreakWidth ();
+ vloat->dirty = false;
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)",
+ vloat->size.width, vloat->size.ascent, vloat->size.descent);
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width",
+ vloat->size.width);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent",
+ vloat->size.ascent);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent",
+ vloat->size.descent);
+
+ // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd()
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::dealingWithSizeOfChild (core::Widget *child)
+{
+ return false;
+}
+
+int OOFFloatsMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ assertNotReached ();
+ return 0;
+}
+
+int OOFFloatsMgr::getNumWidgets ()
+{
+ return leftFloatsAll->size() + rightFloatsAll->size();
+}
+
+Widget *OOFFloatsMgr::getWidget (int i)
+{
+ if (i < leftFloatsAll->size())
+ return leftFloatsAll->get(i)->getWidget ();
+ else
+ return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh
new file mode 100644
index 00000000..b23ba072
--- /dev/null
+++ b/dw/ooffloatsmgr.hh
@@ -0,0 +1,397 @@
+#ifndef __DW_OOFFLOATSMGR_HH__
+#define __DW_OOFFLOATSMGR_HH__
+
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+/**
+ * \brief OutOfFlowMgr implementation dealing with floats.
+ *
+ * Note: The identifiers and comments of this class still refer to
+ * "Textblock" instead of "OOFAwareWidget"; should be cleaned up some
+ * day. (OTOH, these widgets are always textblocks.)
+ */
+class OOFFloatsMgr: public OutOfFlowMgr
+{
+ friend class WidgetInfo;
+
+private:
+ enum Side { LEFT, RIGHT };
+ enum SFVType { GB, CB };
+
+ OOFAwareWidget *container;
+
+ // These two values are redundant to TBInfo::wasAllocated and
+ // TBInfo::allocation, for some special cases.
+ bool containerWasAllocated;
+ core::Allocation containerAllocation;
+
+ class WidgetInfo: public lout::object::Object
+ {
+ private:
+ bool wasAllocated;
+ int xCB, yCB; // relative to the containing block
+ int width, height;
+
+ OOFFloatsMgr *oofm;
+ core::Widget *widget;
+
+ protected:
+ OOFFloatsMgr *getOOFFloatsMgr () { return oofm; }
+
+ public:
+ WidgetInfo (OOFFloatsMgr *oofm, core::Widget *widget);
+
+ inline bool wasThenAllocated () { return wasAllocated; }
+ inline int getOldXCB () { return xCB; }
+ inline int getOldYCB () { return yCB; }
+ inline int getOldWidth () { return width; }
+ inline int getOldHeight () { return height; }
+
+
+ void update (bool wasAllocated, int xCB, int yCB, int width, int height);
+
+ inline core::Widget *getWidget () { return widget; }
+ };
+
+ class Float: public WidgetInfo
+ {
+ public:
+ class ComparePosition: public lout::object::Comparator
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ OOFAwareWidget *refTB;
+ SFVType type; // actually only used for debugging
+
+ public:
+ ComparePosition (OOFFloatsMgr *oofm, OOFAwareWidget *refTB,
+ SFVType type)
+ { this->oofm = oofm; this->refTB = refTB; this->type = type; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ class CompareSideSpanningIndex: public lout::object::Comparator
+ {
+ public:
+ int compare(Object *o1, Object *o2);
+ };
+
+ class CompareGBAndExtIndex: public lout::object::Comparator
+ {
+ private:
+ OOFFloatsMgr *oofm;
+ SFVType type; // actually only used for debugging
+
+ public:
+ CompareGBAndExtIndex (OOFFloatsMgr *oofm, SFVType type)
+ { this->oofm = oofm; this->type = type; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ OOFAwareWidget *generatingBlock;
+ int externalIndex;
+ int yReq, yReal; // relative to generator, not container
+ int indexGBList; /* Refers to TBInfo::leftFloatsGB or
+ TBInfo::rightFloatsGB, respectively. -1
+ initially. */
+ int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB,
+ respectively. -1 initially. */
+ int sideSpanningIndex, mark;
+ core::Requisition size;
+ int cbLineBreakWidth; /* On which the calculation of relative sizes
+ is based. Height not yet used, and probably
+ not added before size redesign. */
+ bool dirty, sizeChangedSinceLastAllocation;
+
+ Float (OOFFloatsMgr *oofm, core::Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex);
+
+ inline bool isNowAllocated () { return getWidget()->wasAllocated (); }
+ inline int getNewXCB () { return getWidget()->getAllocation()->x -
+ getOOFFloatsMgr()->containerAllocation.x; }
+ inline int getNewYCB () { return getWidget()->getAllocation()->y -
+ getOOFFloatsMgr()->containerAllocation.y; }
+ inline int getNewWidth () { return getWidget()->getAllocation()->width; }
+ inline int getNewHeight () { return getWidget()->getAllocation()->ascent +
+ getWidget()->getAllocation()->descent; }
+ void updateAllocation ();
+
+ inline int *getIndexRef (SFVType type) {
+ return type == GB ? &indexGBList : &indexCBList; }
+ inline int getIndex (SFVType type) { return *(getIndexRef (type)); }
+ inline void setIndex (SFVType type, int value) {
+ *(getIndexRef (type)) = value; }
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ bool covers (OOFAwareWidget *textblock, int y, int h);
+ };
+
+ /**
+ * This list is kept sorted.
+ *
+ * To prevent accessing methods of the base class in an
+ * uncontrolled way, the inheritance is private, not public; this
+ * means that all methods must be delegated (see iterator(), size()
+ * etc. below.)
+ *
+ * TODO Update comment: still sorted, but ...
+ *
+ * More: add() and change() may check order again.
+ */
+ class SortedFloatsVector: private lout::container::typed::Vector<Float>
+ {
+ public:
+ SFVType type;
+
+ private:
+ OOFFloatsMgr *oofm;
+ Side side;
+
+ public:
+ inline SortedFloatsVector (OOFFloatsMgr *oofm, Side side, SFVType type) :
+ lout::container::typed::Vector<Float> (1, false)
+ { this->oofm = oofm; this->side = side; this->type = type; }
+
+ int findFloatIndex (OOFAwareWidget *lastGB, int lastExtIndex);
+ int find (OOFAwareWidget *textblock, int y, int start, int end);
+ int findFirst (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex, int *lastReturn);
+ int findLastBeforeSideSpanningIndex (int sideSpanningIndex);
+ void put (Float *vloat);
+
+ inline lout::container::typed::Iterator<Float> iterator()
+ { return lout::container::typed::Vector<Float>::iterator (); }
+ inline int size ()
+ { return lout::container::typed::Vector<Float>::size (); }
+ inline Float *get (int pos)
+ { return lout::container::typed::Vector<Float>::get (pos); }
+ inline void clear ()
+ { lout::container::typed::Vector<Float>::clear (); }
+ };
+
+ class TBInfo: public WidgetInfo
+ {
+ public:
+ int lineBreakWidth;
+ int index; // position within "tbInfos"
+
+ TBInfo *parent;
+ int parentExtIndex;
+
+ // These two values are set by sizeAllocateStart(), and they are
+ // accessable also within sizeAllocateEnd() for the same
+ // textblock, for which allocation and WAS_ALLOCATED is set
+ // *after* sizeAllocateEnd(). See the two functions
+ // wasAllocated(Widget*) and getAllocation(Widget*) (further
+ // down) for usage.
+ bool wasAllocated;
+ core::Allocation allocation;
+ int clearPosition;
+
+ // These two lists store all floats generated by this textblock,
+ // as long as this textblock is not allocates.
+ SortedFloatsVector *leftFloatsGB, *rightFloatsGB;
+
+ TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex);
+ ~TBInfo ();
+
+ inline bool isNowAllocated () {
+ return getOOFFloatsMgr()->wasAllocated (getOOFAwareWidget ()); }
+ inline int getNewXCB () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->x -
+ getOOFFloatsMgr()->containerAllocation.x; }
+ inline int getNewYCB () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->y -
+ getOOFFloatsMgr()->containerAllocation.y; }
+ inline int getNewWidth () {
+ return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->width; }
+ inline int getNewHeight () {
+ core::Allocation *allocation =
+ getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ());
+ return allocation->ascent + allocation->descent; }
+ void updateAllocation ();
+
+ inline OOFAwareWidget *getOOFAwareWidget ()
+ { return (OOFAwareWidget*)getWidget (); }
+ };
+
+ // These two lists store all floats, in the order in which they are
+ // defined. Only used for iterators.
+ lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll;
+
+ // These two lists store all floats whose generators are already
+ // allocated.
+ SortedFloatsVector *leftFloatsCB, *rightFloatsCB;
+
+ // These two attributes are used in the size allocation process;
+ // see sizeAllocateStart and sizeAllocateEnd.
+ int lastAllocatedLeftFloat, lastAllocatedRightFloat;
+
+ lout::container::typed::HashTable<lout::object::TypedPointer
+ <dw::core::Widget>, Float> *floatsByWidget;
+
+ lout::container::typed::Vector<TBInfo> *tbInfos;
+ lout::container::typed::HashTable<lout::object::TypedPointer<OOFAwareWidget>,
+ TBInfo> *tbInfosByOOFAwareWidget;
+
+ int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
+
+ /**
+ * Variant of Widget::wasAllocated(), which can also be used within
+ * OOFM::sizeAllocateEnd().
+ */
+ inline bool wasAllocated (OOFAwareWidget *textblock) {
+ return getOOFAwareWidget(textblock)->wasAllocated;
+ }
+
+ /**
+ * Variant of Widget::getAllocation(), which can also be used
+ * within OOFM::sizeAllocateEnd().
+ */
+ inline core::Allocation *getAllocation (OOFAwareWidget *textblock) {
+ return &(getOOFAwareWidget(textblock)->allocation);
+ }
+
+ void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
+ int diff);
+ Float *findFloatByWidget (core::Widget *widget);
+
+ void moveFromGBToCB (Side side);
+ void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
+ int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
+ int gbLineBreakWidth);
+
+ 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);
+
+ bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal);
+ 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);
+ bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff);
+
+ TBInfo *getOOFAwareWidget (OOFAwareWidget *widget);
+ TBInfo *getOOFAwareWidgetWhenRegistered (OOFAwareWidget *widget);
+ inline bool isOOFAwareWidgetRegistered (OOFAwareWidget *widget)
+ { return getOOFAwareWidgetWhenRegistered (widget) != NULL; }
+ int getBorder (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ SortedFloatsVector *getFloatsListForOOFAwareWidget (OOFAwareWidget
+ *textblock,
+ Side side);
+ bool hasFloat (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getFloatHeight (OOFAwareWidget *textblock, Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int calcClearPosition (OOFAwareWidget *textblock);
+ int calcClearPosition (OOFAwareWidget *textblock, Side side);
+
+ void ensureFloatSize (Float *vloat);
+
+ inline static int createSubRefLeftFloat (int index) { return index << 1; }
+ inline static int createSubRefRightFloat (int index)
+ { return (index << 1) | 1; }
+
+ inline static bool isSubRefLeftFloat (int ref)
+ { return ref != -1 && (ref & 1) == 0; }
+ inline static bool isSubRefRightFloat (int ref)
+ { return ref != -1 && (ref & 1) == 1; }
+
+ inline static int getFloatIndexFromSubRef (int ref)
+ { return ref == -1 ? ref : (ref >> 1); }
+
+public:
+ OOFFloatsMgr (OOFAwareWidget *container);
+ ~OOFFloatsMgr ();
+
+ void sizeAllocateStart (OOFAwareWidget *caller,
+ core::Allocation *allocation);
+ void sizeAllocateEnd (OOFAwareWidget *caller);
+ void containerSizeChangedForChildren ();
+ void draw (core::View *view, core::Rectangle *area);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y);
+
+ static bool _isWidgetOutOfFlow (core::Widget *widget);
+ static bool _isWidgetHandledByOOFM (core::Widget *widget);
+ void addWidgetInFlow (OOFAwareWidget *textblock, OOFAwareWidget *parentBlock,
+ int externalIndex);
+ int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generatingBlock,
+ int externalIndex);
+ void moveExternalIndices (OOFAwareWidget *generatingBlock, int oldStartIndex,
+ int diff);
+
+ void tellPosition (core::Widget *widget, int x, int y);
+
+ void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
+ void getExtremes (core::Extremes *cbExtr,
+ int *oofMinWidth, int *oofMaxWidth);
+
+ int getLeftBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool hasFloatLeft (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ bool hasFloatRight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+ bool mayAffectBordersAtAll ();
+
+ int getClearPosition (OOFAwareWidget *textblock);
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
+ int getNumWidgets ();
+ core::Widget *getWidget (int i);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFFLOATSMGR_HH__
diff --git a/dw/oofposabsmgr.cc b/dw/oofposabsmgr.cc
new file mode 100644
index 00000000..07daca86
--- /dev/null
+++ b/dw/oofposabsmgr.cc
@@ -0,0 +1,69 @@
+/*
+ * 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"
+#include "oofawarewidget.hh"
+
+namespace dw {
+
+namespace oof {
+
+OOFPosAbsMgr::OOFPosAbsMgr (OOFAwareWidget *container) :
+ OOFPositionedMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosAbsMgr");
+}
+
+OOFPosAbsMgr::~OOFPosAbsMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+// Comment for all containerBox* implementations: for the toplevel
+// widget, assume margin = border = 0 (should perhaps set so when
+// widgets are constructed), so that the padding area is actually the
+// allocation.
+
+int OOFPosAbsMgr::containerBoxOffsetX ()
+{
+ return container->getParent () ?
+ container->boxOffsetX () - container->getStyle()->padding.left : 0;
+}
+
+int OOFPosAbsMgr::containerBoxOffsetY ()
+{
+ return container->getParent () ?
+ container->boxOffsetY () - container->getStyle()->padding.top : 0;
+}
+
+int OOFPosAbsMgr::containerBoxRestWidth ()
+{
+ return container->getParent () ?
+ container->boxRestWidth () - container->getStyle()->padding.right : 0;
+}
+
+int OOFPosAbsMgr::containerBoxRestHeight ()
+{
+ return container->getParent () ?
+ container->boxRestHeight () - container->getStyle()->padding.bottom : 0;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposabsmgr.hh b/dw/oofposabsmgr.hh
new file mode 100644
index 00000000..20c09535
--- /dev/null
+++ b/dw/oofposabsmgr.hh
@@ -0,0 +1,27 @@
+#ifndef __DW_OOFPOSABSMGR_HH__
+#define __DW_OOFPOSABSMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosAbsMgr: public OOFPositionedMgr
+{
+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..22cca983
--- /dev/null
+++ b/dw/oofposfixedmgr.cc
@@ -0,0 +1,60 @@
+/*
+ * 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) :
+ OOFPositionedMgr (container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPosFixedMgr");
+}
+
+OOFPosFixedMgr::~OOFPosFixedMgr ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+
+int OOFPosFixedMgr::containerBoxOffsetX ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxOffsetY ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxRestWidth ()
+{
+ return 0;
+}
+
+int OOFPosFixedMgr::containerBoxRestHeight ()
+{
+ return 0;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofposfixedmgr.hh b/dw/oofposfixedmgr.hh
new file mode 100644
index 00000000..38937878
--- /dev/null
+++ b/dw/oofposfixedmgr.hh
@@ -0,0 +1,27 @@
+#ifndef __DW_OOFPOSFIXEDMGR_HH__
+#define __DW_OOFPOSFIXEDMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPosFixedMgr: public OOFPositionedMgr
+{
+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..e5c31a98
--- /dev/null
+++ b/dw/oofpositionedmgr.cc
@@ -0,0 +1,577 @@
+/*
+ * 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 "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 {
+
+namespace oof {
+
+OOFPositionedMgr::OOFPositionedMgr (OOFAwareWidget *container)
+{
+ DBG_OBJ_CREATE ("dw::OOFPositionedMgr");
+
+ this->container = (OOFAwareWidget*)container;
+ children = new Vector<Child> (1, false);
+ childrenByWidget = new HashTable<TypedPointer<Widget>, Child> (true, true);
+
+ 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)
+ containerAllocation = *allocation;
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == container) {
+ sizeAllocateChildren ();
+
+ bool sizeChanged = doChildrenExceedContainer ();
+ bool extremesChanged = haveExtremesChanged ();
+ if (sizeChanged || extremesChanged)
+ container->oofSizeChanged (extremesChanged);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFPositionedMgr::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 OOFPositionedMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < children->size(); i++)
+ children->get(i)->widget->containerSizeChanged ();
+
+ 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;
+}
+
+bool OOFPositionedMgr::haveExtremesChanged ()
+{
+ // TODO Something to do?
+ return false;
+}
+
+
+void OOFPositionedMgr::draw (View *view, Rectangle *area)
+{
+ 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++) {
+ Widget *childWidget = children->get(i)->widget;
+ Rectangle childArea;
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->intersects (area, &childArea))
+ childWidget->draw (view, &childArea);
+ }
+
+ 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);
+ 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_MSGF ("construct.oofm", 1, "=> %d", subRef);
+ DBG_OBJ_LEAVE ();
+ return subRef;
+}
+
+void OOFPositionedMgr::moveExternalIndices (OOFAwareWidget *generator,
+ int oldStartIndex, int diff)
+{
+}
+
+void OOFPositionedMgr::markSizeChange (int ref)
+{
+}
+
+
+void OOFPositionedMgr::markExtremesChange (int ref)
+{
+}
+
+Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *childAtPoint = NULL;
+
+ for (int i = 0; i < children->size() && childAtPoint == NULL; i++) {
+ Widget *childWidget = children->get(i)->widget;
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->wasAllocated ()) {
+ childAtPoint = childWidget->getWidgetAtPoint (x, y);
+ }
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", childAtPoint);
+ DBG_OBJ_LEAVE ();
+ return childAtPoint;
+}
+
+void OOFPositionedMgr::tellPosition (Widget *widget, int x, int y)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%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::getSize (Requisition *containerReq, int *oofWidth,
+ int *oofHeight)
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
+
+ *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);
+ 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 ();
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ containerExtr->minWidth, containerExtr->maxWidth);
+
+ // TODO Something to do?
+ *oofMinWidth = *oofMaxWidth = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+int OOFPositionedMgr::getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+{
+ return false;
+}
+
+
+int OOFPositionedMgr::getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen,
+ int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getClearPosition (OOFAwareWidget *widget)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::affectsLeftBorder (Widget *widget)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::affectsRightBorder (Widget *widget)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::mayAffectBordersAtAll ()
+{
+ return false;
+}
+
+bool OOFPositionedMgr::dealingWithSizeOfChild (Widget *child)
+{
+ return true;
+}
+
+int OOFPositionedMgr::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);
+ width = max (availWidth - containerBoxDiffWidth ()
+ // Regard an undefined value as 0:
+ - max (getPosLeft (child, availWidth), 0),
+ - max (getPosRight (child, availWidth), 0),
+ 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 OOFPositionedMgr::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);
+ height = max (availHeight - containerBoxDiffHeight ()
+ // Regard an undefined value as 0:
+ - max (getPosTop (child, availHeight), 0),
+ - max (getPosBottom (child, availHeight), 0),
+ 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;
+}
+
+int OOFPositionedMgr::getPosBorder (style::Length cssValue, int refLength)
+{
+ if (style::isAbsLength (cssValue))
+ return style::absLengthVal (cssValue);
+ else if (style::isPerLength (cssValue))
+ return style::multiplyWithPerLength (refLength, cssValue);
+ else
+ // -1 means "undefined":
+ return -1;
+}
+
+void OOFPositionedMgr::calcPosAndSizeChildOfChild (Child *child, int refWidth,
+ int refHeight, int *x,
+ int *y, int *width,
+ int *ascent, int *descent)
+{
+ // *x and *y refer to reference area; caller must adjust them.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "calcPosAndSizeChildOfChild",
+ "%p, %d, %d, ...", child, 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);
+
+ 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 = childRequisition.width;
+ widthDefined = false;
+ }
+
+ int left = getPosLeft (child->widget, refWidth),
+ right = getPosRight (child->widget, refWidth);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "left = %d, right = %d, width = %d (defined: %s)",
+ left, right, *width, widthDefined ? "true" : "false");
+
+ if (left == -1 && right == -1)
+ *x = child->generator->getAllocation()->x + child->x;
+ else if (left == -1 && right != -1)
+ *x = refWidth - *width - right;
+ else if (left != -1 && right == -1)
+ *x = left;
+ else {
+ *x = left;
+ if (!widthDefined)
+ *width = refWidth - (left + right);
+ }
+
+ bool heightDefined;
+ *ascent = childRequisition.ascent;
+ *descent = childRequisition.descent;
+ 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 = getPosTop (child->widget, refHeight),
+ bottom = getPosBottom (child->widget, refHeight);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "top = %d, bottom = %d, height = %d + %d (defined: %s)",
+ top, bottom, *ascent, *descent,
+ heightDefined ? "true" : "false");
+
+ if (top == -1 && bottom == -1)
+ *y = child->generator->getAllocation()->y + child->y;
+ else if (top == -1 && bottom != -1)
+ *y = refHeight - (*ascent + *descent) - bottom;
+ else if (top != -1 && bottom == -1)
+ *y = top;
+ else {
+ *y = top;
+ if (!heightDefined) {
+ int height = refHeight - (top + bottom);
+ splitHeightPreserveAscent (height, ascent, descent);
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> %d, %d, %d * (%d + %d)",
+ *x, *y, *width, *ascent, *descent);
+ DBG_OBJ_LEAVE ();
+}
+
+int OOFPositionedMgr::getNumWidgets ()
+{
+ return children->size();
+}
+
+Widget *OOFPositionedMgr::getWidget (int i)
+{
+ return children->get(i)->widget;
+}
+
+} // namespace oof
+
+} // namespace dw
diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh
new file mode 100644
index 00000000..8ddecd92
--- /dev/null
+++ b/dw/oofpositionedmgr.hh
@@ -0,0 +1,120 @@
+#ifndef __DW_OOFPOSITIONEDMGR_HH__
+#define __DW_OOFPOSITIONEDMGR_HH__
+
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+class OOFPositionedMgr: public OutOfFlowMgr
+{
+protected:
+ class Child: public lout::object::Object
+ {
+ public:
+ core::Widget *widget, *generator;
+ int x, y;
+
+ inline Child (core::Widget *widget, core::Widget *generator)
+ { this->widget = widget; this->generator = generator; x = y = 0; }
+ };
+
+ 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 (); }
+
+ OOFAwareWidget *container;
+ core::Allocation containerAllocation;
+
+ lout::container::typed::Vector<Child> *children;
+ lout::container::typed::HashTable<lout::object::TypedPointer
+ <dw::core::Widget>,
+ Child> *childrenByWidget;
+
+ bool doChildrenExceedContainer ();
+ bool haveExtremesChanged ();
+ void sizeAllocateChildren ();
+
+ inline int getPosLeft (core::Widget *child, int availWidth)
+ { return getPosBorder (child->getStyle()->left, availWidth); }
+ inline int getPosRight (core::Widget *child, int availWidth)
+ { return getPosBorder (child->getStyle()->right, availWidth); }
+ inline int getPosTop (core::Widget *child, int availHeight)
+ { return getPosBorder (child->getStyle()->top, availHeight); }
+ inline int getPosBottom (core::Widget *child, int availHeight)
+ { return getPosBorder (child->getStyle()->bottom, availHeight); }
+
+ int getPosBorder (core::style::Length cssValue, int refLength);
+ void calcPosAndSizeChildOfChild (Child *child, int refWidth, int refHeight,
+ int *x, int *y, int *width, int *ascent,
+ int *descent);
+
+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);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y);
+
+ 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 tellPosition (core::Widget *widget, int x, int y);
+
+ void getSize (core::Requisition *containerReq, int *oofWidth,
+ int *oofHeight);
+ void getExtremes (core::Extremes *containerExtr,
+ int *oofMinWidth, int *oofMaxWidth);
+
+ int getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ int getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ bool hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ bool hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+ int getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex);
+
+ int getClearPosition (OOFAwareWidget *widget);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+ bool mayAffectBordersAtAll ();
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+ int 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_OOFPOSITIONEDMGR_HH__
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc
index a128a5c4..405c5e62 100644
--- a/dw/outofflowmgr.cc
+++ b/dw/outofflowmgr.cc
@@ -19,2391 +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 {
- assert (getOutOfFlowMgr()->wasAllocated (generatingBlock));
- 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),
- //*gba = getOutOfFlowMgr()->getAllocation(generatingBlock),
- *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);
-
- assert (oofm->wasAllocated (fl1->generatingBlock));
- assert (oofm->wasAllocated (fl2->generatingBlock));
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
- fl1->generatingBlock, fl2->generatingBlock);
-
- // (i) Floats may not yet been allocated (although the
- // generators are). Non-allocated floats do not have an effect
- // yet, they are considered "at the end" of the list.
-
- // (ii) Float::widget for the key used for binary search. In
- // this case, Float::yReal is used instead (which is set in
- // SortedFloatsVector::find).
-
- 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 {
- 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 {
- 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;
- }
+namespace oof {
- //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;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::find (Textblock *textblock, int y,
- int start, int end)
-{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d",
- textblock, y, start, end);
-
- Float key (oofm, NULL, NULL, 0);
- key.generatingBlock = textblock;
- key.yReal = y;
- key.setIndex (type, -1); // for debugging
- Float::ComparePosition comparator (oofm, textblock, type);
- int result = bsearch (&key, false, start, end, &comparator);
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
- DBG_OBJ_LEAVE_O (oofm);
- return result;
-}
-
-int 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::OutOfFlowMgr ()
{
- 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::AbsolutelyPositioned::AbsolutelyPositioned (OutOfFlowMgr *oofm,
- Widget *widget,
- Textblock
- *generatingBlock,
- int externalIndex)
-{
- this->widget = widget;
- dirty = true;
-}
-
-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;
-
- absolutelyPositioned = new Vector<AbsolutelyPositioned> (1, true);
-
- 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;
-
- delete absolutelyPositioned;
-
- 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 %d abspos",
- leftFloatsAll->size (), rightFloatsAll->size (),
- absolutelyPositioned->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 ();
- for (int i = 0; i < absolutelyPositioned->size(); i++)
- absolutelyPositioned->get(i)->widget->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, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
- 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)) {
- 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);
- 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);
- int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth();
-
- Allocation childAllocation;
- childAllocation.x = cba->x +
- calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth);
- 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 ();
-}
-
-
-/**
- * \brief ...
- *
- * gbX is given relative to the CB, as is the return value.
- */
-int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbLineBreakWidth)
-{
- DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d, %d",
- vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
- gbWidth, gbLineBreakWidth);
- 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.oofm", 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).
-
- // Notice that not the actual width, but the line break width is
- // used. (This changed for GROWS, where the width of a textblock
- // is often smaller that the line break.)
-
- x = max (gbX + gbLineBreakWidth - 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, gbLineBreakWidth, 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);
- drawAbsolutelyPositioned (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::drawAbsolutelyPositioned (View *view, Rectangle *area)
-{
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- AbsolutelyPositioned *abspos = absolutelyPositioned->get(i);
- Rectangle childArea;
- if (abspos->widget->intersects (area, &childArea))
- abspos->widget->draw (view, &childArea);
- }
-}
-
-/**
- * This method consideres also the attributes not yet considered by
- * dillo, so that the containing block is determined correctly, which
- * leads sometimes to a cleaner rendering.
- */
-bool OutOfFlowMgr::isWidgetOutOfFlow (Widget *widget)
-{
- // This is only half-baked, will perhaps be reactivated:
- //
- //return
- // widget->getStyle()->vloat != FLOAT_NONE ||
- // widget->getStyle()->position == POSITION_ABSOLUTE ||
- // widget->getStyle()->position == POSITION_FIXED;
-
- return isWidgetHandledByOOFM (widget);
-}
-
-bool OutOfFlowMgr::isWidgetHandledByOOFM (Widget *widget)
-{
- // May be extended for fixed (and relative?) positions.
- return isWidgetFloat (widget);
- // TODO temporary disabled: || isWidgetAbsolutelyPositioned (widget);
-}
-
-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);
- 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);
- 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 if (isWidgetAbsolutelyPositioned (widget)) {
- AbsolutelyPositioned *abspos =
- new AbsolutelyPositioned (this, widget, generatingBlock,
- externalIndex);
- absolutelyPositioned->put (abspos);
- widget->parentRef =
- createRefAbsolutelyPositioned (absolutelyPositioned->size() - 1);
- } 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 if (isRefAbsolutelyPositioned (ref)) {
- int i = getAbsolutelyPositionedIndexFromRef (ref);
- absolutelyPositioned->get(i)->dirty = true;
- } 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);
- if (childAtPoint == NULL)
- childAtPoint = getAbsolutelyPositionedWidgetAtPoint (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;
-}
-
-Widget *OutOfFlowMgr::getAbsolutelyPositionedWidgetAtPoint (int x, int y,
- int level)
-{
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- AbsolutelyPositioned *abspos = absolutelyPositioned->get(i);
- if (abspos->widget->wasAllocated ()) {
- Widget *childAtPoint =
- abspos->widget->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)) {
- 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);
- 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)
-{
- // 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 {
- assert (wasAllocated (vloat->generatingBlock));
- assert (wasAllocated (other->generatingBlock));
-
- // 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 {
- Allocation *gba = getAllocation (vloat->generatingBlock),
- *flaOther = other->getWidget()->getAllocation ();
- int otherBottomGB =
- flaOther->y + flaOther->ascent + flaOther->descent - gba->y;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "different generators: "
- "otherBottomGB = %d + (%d + %d) - %d = %d",
- flaOther->y, 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 {
- assert (wasAllocated (vloat->generatingBlock));
- assert (wasAllocated (other->generatingBlock));
-
- // 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 {
- Allocation *gba = getAllocation (vloat->generatingBlock);
- int vloatX =
- calcFloatX (vloat,
- vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
- LEFT : RIGHT,
- gba->x, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
-
- // 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 oofWidthAbsPos, oofHeightAbsPos;
- getAbsolutelyPositionedSize (cbReq, &oofWidthAbsPos, &oofHeightAbsPos);
-
- int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
- getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
- getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
-
- *oofWidth = max (oofWidthtLeft, oofWidthRight, oofWidthAbsPos);
- *oofHeight = max (oofHeightLeft, oofHeightRight, oofHeightAbsPos);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (a: %d, l: %d, r: %d => %d) * (a: %d, l: %d, r: %d => %d)",
- oofWidthAbsPos, oofWidthtLeft, oofWidthRight, *oofWidth,
- oofHeightAbsPos, 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);
-
- if (vloat->generatingBlock == containingBlock ||
- wasAllocated (vloat->generatingBlock)) {
- ensureFloatSize (vloat);
- int x, y;
-
- if (vloat->generatingBlock == containingBlock) {
- x = calcFloatX (vloat, side, 0, cbReq->width,
- vloat->generatingBlock->getLineBreakWidth ());
- y = vloat->yReal;
- } else {
- Allocation *gba = getAllocation(vloat->generatingBlock);
- x = calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
- 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 oofMinWidthAbsPos, oofMaxWidthAbsPos;
- getAbsolutelyPositionedExtremes (cbExtr, &oofMinWidthAbsPos,
- &oofMaxWidthAbsPos);
-
- int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
- getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
- getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
-
- *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight, oofMinWidthAbsPos);
- *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight, oofMaxWidthAbsPos);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (a: %d, l: %d, r: %d => %d) / (a: %d, l: %d, r: %d => %d)",
- oofMinWidthAbsPos, oofMinWidthtLeft, oofMinWidthRight,
- *oofMinWidth, oofMaxWidthAbsPos, 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);
- int leftDiff, rightDiff;
-
- if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) {
- Extremes extr;
- vloat->getWidget()->getExtremes (&extr);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: %d / %d",
- vloat->getWidget (), vloat->generatingBlock,
- extr.minWidth, extr.maxWidth);
-
- // TODO: Or zero (instead of rightDiff) for right floats?
- *minWidth =
- max (*minWidth,
- extr.minWidth + (side == LEFT ? leftDiff : rightDiff));
- *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff);
-
- DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth);
- } else
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: not allocated",
- vloat->getWidget (), vloat->generatingBlock);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-// Returns "false" when borders cannot yet determined; *leftDiff and
-// *rightDiff are undefined in this case.
-bool OutOfFlowMgr::getFloatDiffToCB (Float *vloat, int *leftDiff,
- int *rightDiff)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB",
- "float %p [generated by %p], ...",
- vloat->getWidget (), vloat->generatingBlock);
-
- bool result;
-
- if (vloat->generatingBlock == containingBlock) {
- *leftDiff = vloat->generatingBlock->getStyle()->boxOffsetX();
- *rightDiff = vloat->generatingBlock->getStyle()->boxRestWidth();
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "GB == CB => leftDiff = %d, rightDiff = %d",
- *leftDiff, *rightDiff);
- } else if (wasAllocated (vloat->generatingBlock)) {
- Allocation *gba = getAllocation(vloat->generatingBlock);
- *leftDiff = gba->x - containingBlockAllocation.x
- + vloat->generatingBlock->getStyle()->boxOffsetX();
- *rightDiff =
- (containingBlockAllocation.x + containingBlockAllocation.width)
- - (gba->x + gba->width)
- + vloat->generatingBlock->getStyle()->boxRestWidth();
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "GB != CB => leftDiff = %d - %d + %d = %d, "
- "rightDiff = (%d + %d) - (%d + %d) + %d = %d",
- gba->x, containingBlockAllocation.x,
- vloat->generatingBlock->getStyle()->boxOffsetX(),
- *leftDiff, containingBlockAllocation.x,
- containingBlockAllocation.width, gba->x, gba->width,
- vloat->generatingBlock->getStyle()->boxRestWidth(),
- *rightDiff);
- } else {
- DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated");
- result = false;
- }
-
- DBG_OBJ_LEAVE ();
- return result;
-}
-
-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 ();
-}
-
-void OutOfFlowMgr::getAbsolutelyPositionedSize (Requisition *cbReq, int *width,
- int *height)
-{
- // TODO
- *width = *height = 0;
-}
-
-void OutOfFlowMgr::getAbsolutelyPositionedExtremes (Extremes *cbExtr,
- int *minWidth,
- int *maxWidth)
-{
- // TODO
- *minWidth = *maxWidth = 0;
-}
-
-void OutOfFlowMgr::ensureAbsolutelyPositionedSizeAndPosition
- (AbsolutelyPositioned *abspos)
-{
- // TODO
- assertNotReached ();
-}
-
-int OutOfFlowMgr::calcValueForAbsolutelyPositioned
- (AbsolutelyPositioned *abspos, Length styleLen, int refLen)
-{
- assert (styleLen != LENGTH_AUTO);
- if (isAbsLength (styleLen))
- return absLengthVal (styleLen);
- else if (isPerLength (styleLen))
- return multiplyWithPerLength (refLen, styleLen);
- else {
- assertNotReached ();
- return 0; // compiler happiness
- }
-}
-
-void OutOfFlowMgr::sizeAllocateAbsolutelyPositioned ()
-{
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- Allocation *cbAllocation = getAllocation (containingBlock);
- AbsolutelyPositioned *abspos = absolutelyPositioned->get (i);
- ensureAbsolutelyPositionedSizeAndPosition (abspos);
-
- Allocation childAllocation;
- childAllocation.x = cbAllocation->x + abspos->xCB;
- childAllocation.y = cbAllocation->y + abspos->yCB;
- childAllocation.width = abspos->width;
- childAllocation.ascent = abspos->height;
- childAllocation.descent = 0; // TODO
-
- abspos->widget->sizeAllocate (&childAllocation);
-
- printf ("[%p] allocating child %p at: (%d, %d), %d x (%d + %d)\n",
- containingBlock, abspos->widget, childAllocation.x,
- childAllocation.y, childAllocation.width, childAllocation.ascent,
- childAllocation.descent);
- }
-}
+} // namespace oof
} // namespace dw
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index a42afd1d..96091ded 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -5,468 +5,81 @@
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);
- };
-
- /**
- * This list is kept sorted.
- *
- * To prevent accessing methods of the base class in an
- * uncontrolled way, the inheritance is private, not public; this
- * means that all methods must be delegated (see iterator(), size()
- * etc. below.)
- *
- * TODO Update comment: still sorted, but ...
- *
- * More: add() and change() may check order again.
- */
- class SortedFloatsVector: private lout::container::typed::Vector<Float>
- {
- public:
- SFVType type;
-
- private:
- 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;
-
- // These two values are set by sizeAllocateStart(), and they are
- // accessable also within sizeAllocateEnd() for the same
- // textblock, for which allocation and WAS_ALLOCATED is set
- // *after* sizeAllocateEnd(). See the two functions
- // wasAllocated(Widget*) and getAllocation(Widget*) (further
- // down) for usage.
- bool wasAllocated;
- core::Allocation allocation;
- int clearPosition;
-
- // These two lists store all floats generated by this textblock,
- // as long as this textblock is not allocates.
- SortedFloatsVector *leftFloatsGB, *rightFloatsGB;
-
- TBInfo (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 (); }
- };
-
- class AbsolutelyPositioned: public lout::object::Object
- {
- public:
- core::Widget *widget;
- int xCB, yCB; // relative to the containing block
- int width, height;
- bool dirty;
-
- AbsolutelyPositioned (OutOfFlowMgr *oofm, core::Widget *widget,
- Textblock *generatingBlock, int externalIndex);
- };
-
- // 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;
-
- lout::container::typed::Vector<AbsolutelyPositioned> *absolutelyPositioned;
-
- int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
-
- /**
- * Variant of Widget::wasAllocated(), which can also be used within
- * OOFM::sizeAllocateEnd().
- */
- inline bool wasAllocated (Textblock *textblock) {
- return getTextblock(textblock)->wasAllocated;
- }
-
- /**
- * Variant of Widget::getAllocation(), which can also be used
- * within OOFM::sizeAllocateEnd().
- */
- inline core::Allocation *getAllocation (Textblock *textblock) {
- return &(getTextblock(textblock)->allocation);
- }
-
- void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
- int diff);
- Float *findFloatByWidget (core::Widget *widget);
-
- void moveFromGBToCB (Side side);
- void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
- int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbLineBreakWidth);
-
- 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);
- void drawAbsolutelyPositioned (core::View *view, core::Rectangle *area);
- core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
- int level);
- core::Widget *getAbsolutelyPositionedWidgetAtPoint (int x, int y, int level);
-
- bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal);
- 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);
- bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff);
-
- 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);
-
- void getAbsolutelyPositionedSize (core::Requisition *cbReq, int *width,
- int *height);
- void getAbsolutelyPositionedExtremes (core::Extremes *cbExtr, int *minWidth,
- int *maxWidth);
- void ensureAbsolutelyPositionedSizeAndPosition (AbsolutelyPositioned
- *abspos);
- int calcValueForAbsolutelyPositioned (AbsolutelyPositioned *abspos,
- core::style::Length styleLen,
- int refLen);
- void sizeAllocateAbsolutelyPositioned ();
-
- static inline bool isWidgetFloat (core::Widget *widget)
- { return widget->getStyle()->vloat != core::style::FLOAT_NONE; }
- static inline bool isWidgetAbsolutelyPositioned (core::Widget *widget)
- { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; }
-
- /*
- * 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 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * Absolutely positioned blocks:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | index | 1 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- */
-
- 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 bool isRefAbsolutelyPositioned (int ref)
- { return ref != -1 && (ref & 3) == 3; }
-
- inline static int createRefLeftFloat (int index)
- { return (index << 3) | 1; }
- inline static int createRefRightFloat (int index)
- { return (index << 3) | 5; }
- inline static int createRefAbsolutelyPositioned (int index)
- { return (index << 2) | 3; }
-
- inline static int getFloatIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 3); }
- inline static int getAbsolutelyPositionedIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 2); }
-
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 isWidgetOutOfFlow (core::Widget *widget);
- static bool isWidgetHandledByOOFM (core::Widget *widget);
- void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
- int externalIndex);
- void addWidgetOOF (core::Widget *widget, Textblock *generatingBlock,
- int externalIndex);
- void moveExternalIndices (Textblock *generatingBlock, int oldStartIndex,
- int diff);
-
- void tellPosition (core::Widget *widget, int yReq);
-
- void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
- void getExtremes (core::Extremes *cbExtr,
- int *oofMinWidth, int *oofMaxWidth);
-
- int getLeftBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- int getRightBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- bool hasFloatLeft (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- bool hasFloatRight (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- int getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- int getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getClearPosition (Textblock *tb);
-
- 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); }
-
+ 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) = 0;
+
+ virtual void markSizeChange (int ref) = 0;
+ virtual void markExtremesChange (int ref) = 0;
+ virtual core::Widget *getWidgetAtPoint (int x, int y) = 0;
+
+ virtual void addWidgetInFlow (OOFAwareWidget *widget,
+ OOFAwareWidget *parent, int externalIndex) = 0;
+ virtual int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator,
+ int externalIndex) = 0;
+ virtual void moveExternalIndices (OOFAwareWidget *generator,
+ int oldStartIndex, int diff) = 0;
+
+ virtual void tellPosition (core::Widget *widget, int x, int y) = 0;
+
+ virtual void getSize (core::Requisition *containerReq, int *oofWidth,
+ int *oofHeight) = 0;
+ virtual void getExtremes (core::Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth) = 0;
+
+
+ virtual int getLeftBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
+ virtual int getRightBorder (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
+
+ virtual bool hasFloatLeft (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
+ virtual bool hasFloatRight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex) = 0;
+
+ virtual int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+ = 0;
+ virtual int getRightFloatHeight (OOFAwareWidget *widget, int y, int h,
+ OOFAwareWidget *lastGen, int lastExtIndex)
+ = 0;
+
+ virtual bool affectsLeftBorder (core::Widget *widget) = 0;
+ virtual bool affectsRightBorder (core::Widget *widget) = 0;
+ virtual bool mayAffectBordersAtAll () = 0;
+
+ virtual int getClearPosition (OOFAwareWidget *widget) = 0;
+
+ virtual bool dealingWithSizeOfChild (core::Widget *child) = 0;
+ virtual int getAvailWidthOfChild (core::Widget *child, bool forceValue) = 0;
+ virtual int getAvailHeightOfChild (core::Widget *child, bool forceValue) = 0;
+
// for iterators
- inline int getNumWidgets () {
- return leftFloatsAll->size() + rightFloatsAll->size() +
- absolutelyPositioned->size(); }
-
- inline core::Widget *getWidget (int i) {
- if (i < leftFloatsAll->size())
- return leftFloatsAll->get(i)->getWidget ();
- else if (i < leftFloatsAll->size() + rightFloatsAll->size())
- return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
- else
- return absolutelyPositioned->get(i - (leftFloatsAll->size() +
- rightFloatsAll->size()))->widget;
- }
-
- 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/ruler.cc b/dw/ruler.cc
index 3fdbfb6d..fc2c5bca 100644
--- a/dw/ruler.cc
+++ b/dw/ruler.cc
@@ -32,15 +32,14 @@ Ruler::Ruler ()
void Ruler::sizeRequestImpl (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)
{
- extremes->minWidth = extremes->maxWidth = getStyle()->boxDiffWidth ();
+ extremes->minWidth = extremes->maxWidth = boxDiffWidth ();
extremes->minWidthIntrinsic = extremes->minWidth;
extremes->maxWidthIntrinsic = extremes->maxWidth;
correctExtremes (extremes);
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 02f92db6..62b4a0a4 100644
--- a/dw/simpletablecell.cc
+++ b/dw/simpletablecell.cc
@@ -119,4 +119,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 4c18b454..c90fc040 100644
--- a/dw/simpletablecell.hh
+++ b/dw/simpletablecell.hh
@@ -18,6 +18,8 @@ protected:
bool getAdjustMinWidth ();
+ bool adjustExtraSpaceWhenCorrectingRequisitionByOOF ();
+
public:
static int CLASS_ID;
diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc
new file mode 100644
index 00000000..e57c73f0
--- /dev/null
+++ b/dw/stackingcontextmgr.cc
@@ -0,0 +1,154 @@
+/*
+ * 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");
+ scWidgets = new Vector<Widget> (1, false);
+ DBG_OBJ_SET_NUM ("scWidgets.size", scWidgets->size());
+
+ minZIndex = maxZIndex = 0; // Just to have some defined values.
+}
+
+StackingContextMgr::~StackingContextMgr ()
+{
+ delete scWidgets;
+ DBG_OBJ_DELETE ();
+}
+
+void StackingContextMgr::addChildSCWidget (Widget *widget)
+{
+ if (scWidgets->size () == 0)
+ minZIndex = maxZIndex = widget->getStyle()->zIndex;
+ else {
+ minZIndex = min (minZIndex, widget->getStyle()->zIndex);
+ maxZIndex = max (maxZIndex, widget->getStyle()->zIndex);
+ }
+
+ scWidgets->put (widget);
+ DBG_OBJ_SET_NUM ("scWidgets.size", scWidgets->size());
+ DBG_OBJ_ARRSET_PTR ("scWidgets", scWidgets->size() - 1, widget);
+}
+
+void StackingContextMgr::drawBottom (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "drawBottom", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ draw (view, area, INT_MIN, -1);
+ DBG_OBJ_LEAVE ();
+}
+
+void StackingContextMgr::drawTop (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "drawTop", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ draw (view, area, 0, INT_MAX);
+ DBG_OBJ_LEAVE ();
+}
+
+void StackingContextMgr::draw (View *view, Rectangle *area, int startZIndex,
+ int endZIndex)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "[%d, %d, %d * %d], %d, %d",
+ area->x, area->y, area->width, area->height, startZIndex,
+ endZIndex);
+
+ for (int zIndex = max (minZIndex, startZIndex);
+ zIndex <= min (maxZIndex, endZIndex); zIndex++) {
+ DBG_OBJ_MSGF ("draw", 1, "drawing zIndex = %d", zIndex);
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < scWidgets->size (); i++) {
+ Widget *child = scWidgets->get (i);
+ DBG_OBJ_MSGF ("draw", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ Rectangle childArea;
+ if (child->getStyle()->zIndex == zIndex &&
+ child->intersects (area, &childArea))
+ child->draw (view, &childArea);
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+Widget *StackingContextMgr::getTopWidgetAtPoint (int x, int y)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTop", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, 0, INT_MAX);
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getBottomWidgetAtPoint (int x, int y)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, INT_MIN, -1);
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getWidgetAtPoint (int x, int y, int startZIndex,
+ int endZIndex)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+
+ for (int zIndex = min (maxZIndex, endZIndex);
+ zIndex >= max (minZIndex, startZIndex) && widgetAtPoint == NULL;
+ zIndex--) {
+ DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d", zIndex);
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < scWidgets->size () && widgetAtPoint == NULL; i++) {
+ Widget *child = scWidgets->get (i);
+ DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ if (child->getStyle()->zIndex == zIndex && child->wasAllocated ())
+ widgetAtPoint = scWidgets->get(i)->getWidgetAtPoint (x, y);
+ }
+
+ 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..684fac23
--- /dev/null
+++ b/dw/stackingcontextmgr.hh
@@ -0,0 +1,60 @@
+#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 {
+
+class OOFAwareWidget;
+
+/**
+ * \brief See \ref dw-stacking-context.
+ */
+class StackingContextMgr
+{
+private:
+ lout::container::typed::Vector<Widget> *scWidgets;
+ int minZIndex, maxZIndex;
+
+ void draw (View *view, Rectangle *area, int startZIndex, int endZIndex);
+
+ Widget *getWidgetAtPoint (int x, int y, int startZIndex, int endZIndex);
+public:
+ StackingContextMgr (Widget *widget);
+ ~StackingContextMgr ();
+
+ inline static bool isEstablishingStackingContext (Widget *widget) {
+ return widget->getStyle()->position != style::POSITION_STATIC &&
+ widget->getStyle()->zIndex != style::Z_INDEX_AUTO;
+ }
+
+ inline static bool handledByStackingContextMgr (Widget *widget) {
+ // Each widget establishing a stacking context is child of another
+ // stacking context, so drawn by StackingContextMgr::drawTop or
+ // StackingContextMgr::drawBottom etc.
+ return widget->getParent () != NULL
+ && isEstablishingStackingContext (widget);
+ }
+
+ void addChildSCWidget (Widget *widget);
+
+ void drawBottom (View *view, Rectangle *area);
+ void drawTop (View *view, Rectangle *area);
+
+ Widget *getTopWidgetAtPoint (int x, int y);
+ Widget *getBottomWidgetAtPoint (int x, int y);
+};
+
+} // namespace core
+
+} // namespace dw
+
+#endif // __DW_STACKINGCONTEXTMGR_HH__
diff --git a/dw/style.cc b/dw/style.cc
index 53d2cbb7..830613fa 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 948a6457..43fff0a1 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 661b8a11..ce45b7ad 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -112,18 +112,20 @@ 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 ();
}
@@ -152,6 +154,9 @@ void Table::getExtremesImpl (core::Extremes *extremes)
correctExtremes (extremes);
+ // For the order, see similar reasoning for dw::Textblock.
+ correctExtremesByOOF (extremes);
+
DBG_OBJ_LEAVE ();
}
@@ -161,16 +166,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++) {
@@ -201,6 +206,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
x += colWidths->get (col) + getStyle()->hBorderSpacing;
}
+ sizeAllocateEnd ();
+
DBG_OBJ_LEAVE ();
}
@@ -218,16 +225,22 @@ int Table::getAvailWidthOfChild (Widget *child, bool forceValue)
child, forceValue ? "true" : "false");
int width;
+ oof::OutOfFlowMgr *oofm;
- // Unlike other containers, the table widget sometimes narrows
- // columns to a width less than specified by CSS (see
- // forceCalcCellSizes). For this reason, the column widths have to
- // be calculated in all cases.
- if (forceValue) {
- calcCellSizes (false);
- width = calcAvailWidthForDescendant (child);
- } else
- width = -1;
+ if (isWidgetOOF(child) && (oofm = getWidgetOutOfFlowMgr(child)) &&
+ oofm->dealingWithSizeOfChild (child))
+ width = oofm->getAvailWidthOfChild (child, forceValue);
+ else {
+ // Unlike other containers, the table widget sometimes narrows
+ // columns to a width less than specified by CSS (see
+ // forceCalcCellSizes). For this reason, the column widths have to
+ // be calculated in all cases.
+ if (forceValue) {
+ calcCellSizes (false);
+ width = calcAvailWidthForDescendant (child);
+ } else
+ width = -1;
+ }
DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
DBG_OBJ_LEAVE ();
@@ -306,6 +319,8 @@ void Table::containerSizeChangedForChildren ()
}
}
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -367,10 +382,13 @@ void Table::draw (core::View *view, core::Rectangle *area)
if (childDefined (i)) {
Widget *child = children->get(i)->cell.widget;
core::Rectangle childArea;
- if (child->intersects (area, &childArea))
+ if (!core::StackingContextMgr::handledByStackingContextMgr (child) &&
+ child->intersects (area, &childArea))
child->draw (view, &childArea);
}
}
+
+ drawOOF (view, area);
}
void Table::removeChild (Widget *child)
@@ -465,6 +483,8 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
curCol += colspanEff;
+ widget->parentRef = makeParentRefInFlow (0);
+
widget->setParent (this);
if (rowStyle->get (curRow))
widget->setBgColor (rowStyle->get(curRow)->backgroundColor);
diff --git a/dw/table.hh b/dw/table.hh
index 1e7c5268..560a2cb7 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"
@@ -319,7 +319,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
@@ -339,20 +339,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);
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.hh b/dw/tablecell.hh
index 2e26c8e8..f7936203 100644
--- a/dw/tablecell.hh
+++ b/dw/tablecell.hh
@@ -28,6 +28,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 4c8ce87c..d90c0781 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -227,7 +227,6 @@ Textblock::Textblock (bool limitTextWidth)
registerName ("dw::Textblock", &CLASS_ID);
setButtonSensitive(true);
- containingBlock = NULL;
hasListitemValue = false;
leftInnerPadding = 0;
line1Offset = 0;
@@ -252,7 +251,6 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
- outOfFlowMgr = NULL;
wrapRefLines = wrapRefParagraphs = -1;
@@ -267,8 +265,8 @@ Textblock::Textblock (bool limitTextWidth)
lineBreakWidth = -1;
DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
- verticalOffset = 0;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
+ clearPosition = 0;
+ DBG_OBJ_SET_NUM ("clearPosition", clearPosition);
this->limitTextWidth = limitTextWidth;
@@ -278,6 +276,11 @@ 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);
}
initNewLine ();
@@ -285,8 +288,6 @@ Textblock::Textblock (bool limitTextWidth)
Textblock::~Textblock ()
{
- _MSG("Textblock::~Textblock\n");
-
/* make sure not to call a free'd tooltip (very fast overkill) */
hoverTooltip = NULL;
@@ -304,16 +305,6 @@ Textblock::~Textblock ()
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;
@@ -370,11 +361,11 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
}
DBG_OBJ_MSGF ("resize", 1, "left inner padding = %d, boxDiffWidth = %d",
- leftInnerPadding, getStyle()->boxDiffWidth ());
+ leftInnerPadding, boxDiffWidth ());
- requisition->width += leftInnerPadding + getStyle()->boxDiffWidth ();
- requisition->ascent += verticalOffset + getStyle()->boxOffsetY ();
- requisition->descent += getStyle()->boxRestHeight ();
+ requisition->width += leftInnerPadding + boxDiffWidth ();
+ requisition->ascent += boxOffsetY ();
+ requisition->descent += boxRestHeight ();
if (mustBeWidenedToAvailWidth ()) {
DBG_OBJ_MSGF ("resize", 1,
@@ -406,25 +397,7 @@ 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);
@@ -487,7 +460,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;
@@ -505,20 +478,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);
- }
+ correctExtremesByOOF (extremes);
DBG_OBJ_MSGF ("resize", 0,
"finally, after considering OOFM: %d (%d) / %d (%d)",
@@ -568,7 +528,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
// Reconstruct the initial size; see
// Textblock::sizeRequestImpl.
(lines->size () > 0 ? lines->getRef(0)->boxAscent : 0)
- + verticalOffset + getStyle()->boxOffsetY ());
+ + boxOffsetY ());
childBaseAllocation.descent =
allocation->ascent + allocation->descent - childBaseAllocation.ascent;
@@ -578,8 +538,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_SET_NUM ("childBaseAllocation.ascent", childBaseAllocation.ascent);
DBG_OBJ_SET_NUM ("childBaseAllocation.descent", childBaseAllocation.descent);
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->sizeAllocateStart (this, allocation);
+ sizeAllocateStart (allocation);
int lineIndex, wordIndex;
Line *line;
@@ -711,9 +670,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;
@@ -733,6 +691,12 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_LEAVE ();
}
+void Textblock::calcExtraSpaceImpl ()
+{
+ OOFAwareWidget::calcExtraSpaceImpl ();
+ extraSpace.top = misc::max (extraSpace.top, clearPosition);
+}
+
int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
{
DBG_OBJ_ENTER ("resize", 0, "Textblock/getAvailWidthOfChild", "%p, %s",
@@ -740,25 +704,31 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
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)
- width = extremes.maxWidth;
+ if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ width =
+ getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
+ else {
+ if (child->getStyle()->width == core::style::LENGTH_AUTO) {
+ // No width specified: similar to standard implementation (see
+ // there), but "leftInnerPadding" has to be considered, too.
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ if (forceValue)
+ width = misc::max (getAvailWidth (true) - boxDiffWidth ()
+ - leftInnerPadding,
+ 0);
+ else
+ width = -1;
+ } else
+ width = Widget::getAvailWidthOfChild (child, forceValue);
+
+ if (forceValue && this == child->getContainer () &&
+ !mustBeWidenedToAvailWidth ()) {
+ core::Extremes extremes;
+ getExtremes (&extremes);
+ if (width > extremes.maxWidth)
+ width = extremes.maxWidth;
+ }
}
DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
@@ -766,7 +736,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 ()
{
@@ -778,9 +756,8 @@ void Textblock::containerSizeChangedForChildren ()
word->content.widget->containerSizeChanged ();
}
- if (outOfFlowMgr)
- outOfFlowMgr->containerSizeChangedForChildren ();
-
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -789,7 +766,7 @@ bool Textblock::affectsSizeChangeContainerChild (Widget *child)
DBG_OBJ_ENTER ("resize", 0,
"Textblock/affectsSizeChangeContainerChild", "%p", child);
- // See Textblock::getAvailWidthForChild() and Textblock::oofSizeChanged():
+ // See Textblock::getAvailWidthOfChild() and Textblock::oofSizeChanged():
// Extremes changes affect the size of the child, too:
bool ret;
if (!mustBeWidenedToAvailWidth () &&
@@ -832,13 +809,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
@@ -846,10 +820,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);
@@ -869,13 +843,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
@@ -883,11 +854,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);
@@ -896,61 +866,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;
@@ -1040,6 +955,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;
@@ -1168,11 +1085,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;
}
@@ -1541,8 +1464,9 @@ 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))
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child) &&
+ child->intersects (area, &childArea))
child->draw (view, &childArea);
} else {
int wordIndex2 = wordIndex;
@@ -1598,9 +1522,7 @@ int Textblock::findLineIndexWhenNotAllocated (int y)
if (lines->size() == 0)
return -1;
else
- return findLineIndex (y,
- lines->getRef(0)->boxAscent + verticalOffset +
- getStyle()->boxOffsetY());
+ return findLineIndex (y, lines->getRef(0)->boxAscent + boxOffsetY());
}
int Textblock::findLineIndexWhenAllocated (int y)
@@ -1752,15 +1674,10 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
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);
+ drawWidgetBox (view, area, false);
+
+ if (stackingContextMgr)
+ stackingContextMgr->drawBottom (view, area);
lineIndex = findLineIndexWhenAllocated (area->y);
@@ -1773,8 +1690,10 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
drawLine (line, view, area);
}
- if(outOfFlowMgr)
- outOfFlowMgr->draw(view, area);
+ drawOOF (view, area);
+
+ if (stackingContextMgr)
+ stackingContextMgr->drawTop (view, area);
DBG_OBJ_LEAVE ();
}
@@ -2335,21 +2254,31 @@ 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());
+ initOutOfFlowMgrs ();
- if (containingBlock->outOfFlowMgr == NULL) {
- containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock);
- DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr);
- }
-
- if (OutOfFlowMgr::isWidgetHandledByOOFM (widget)) {
- PRINTF (" -> out of flow.\n");
+ if (testWidgetOutOfFlow (widget)) {
+ int oofmIndex = -1;
+ if (testWidgetFloat (widget))
+ oofmIndex = OOFM_FLOATS;
+ else if (testWidgetAbsolutelyPositioned (widget))
+ oofmIndex = OOFM_ABSOLUTE;
+ else if (testWidgetFixedlyPositioned (widget))
+ oofmIndex = OOFM_FIXED;
+ else
+ lout::misc::assertNotReached ();
- widget->setParent (containingBlock);
+ widget->setParent (oofContainer[oofmIndex]);
widget->setGenerator (this);
- containingBlock->outOfFlowMgr->addWidgetOOF (widget, this,
- words->size ());
+ int oofmSubRef =
+ searchOutOfFlowMgr(oofmIndex)->addWidgetOOF (widget, this,
+ words->size ());
+ widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef);
+
+ DBG_OBJ_MSGF ("construct.word", 1,
+ "ouf of flow: oofmIndex = %d, oofmSubRef = %d => "
+ "parentRef = %d",
+ oofmIndex, oofmSubRef, widget->parentRef);
+
Word *word = addWord (0, 0, 0, 0, style);
word->content.type = core::Content::WIDGET_OOF_REF;
word->content.widget = widget;
@@ -2358,14 +2287,16 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
// problems with breaking near float definitions.)
setBreakOption (word, style, 0, 0, false);
} else {
- PRINTF (" -> within flow.\n");
+ DBG_OBJ_MSG ("construct.word", 1, "in flow");
widget->setParent (this);
// TODO Replace (perhaps) later "textblock" by "OOF aware widget".
- if (widget->instanceOf (Textblock::CLASS_ID))
- containingBlock->outOfFlowMgr->addWidgetInFlow ((Textblock*)widget,
- this, words->size ());
+ if (widget->instanceOf (Textblock::CLASS_ID)) {
+ for (int i = 0; i < NUM_OOFM; i++)
+ searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this,
+ words->size ());
+ }
core::Requisition size;
calcWidgetSize (widget, &size);
@@ -2603,7 +2534,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;
@@ -2614,7 +2545,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 =
@@ -2623,8 +2554,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;
}
}
@@ -2729,54 +2659,60 @@ void Textblock::breakAdded ()
* This is an optimized version of the general
* dw::core::Widget::getWidgetAtPoint method.
*/
-core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
+core::Widget *Textblock::getWidgetAtPoint (int x, int y)
{
- //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;
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *childAtPoint = NULL;
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;
+ DBG_OBJ_MSG ("events", 1, "outside allocation");
+ } else {
+ // First, ...
+ if (childAtPoint == NULL && stackingContextMgr)
+ childAtPoint = stackingContextMgr->getTopWidgetAtPoint (x, y);
+
+ // Then, search for widgets out of flow, notably floats, since
+ // there are cases where they overlap child textblocks.
+ if (childAtPoint == NULL)
+ childAtPoint = getWidgetOOFAtPoint (x, y);
+
+ if (childAtPoint == NULL) {
+ int lineIndex = findLineIndexWhenAllocated (y - allocation.y);
+
+ if (lineIndex < 0 || lineIndex >= lines->size ())
+ childAtPoint = this;
+ else {
+ Line *line = lines->getRef (lineIndex);
+
+ for (int wordIndex = line->firstWord;
+ wordIndex <= line->lastWord && childAtPoint == NULL;
+ wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_IN_FLOW) {
+ core::Widget * child = word->content.widget;
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child) &&
+ child->wasAllocated ()) {
+ childAtPoint = child->getWidgetAtPoint (x, y);
+ }
+ }
}
}
}
+
+ if (childAtPoint == NULL && stackingContextMgr)
+ childAtPoint = stackingContextMgr->getBottomWidgetAtPoint (x, y);
+
+ if (childAtPoint == NULL)
+ childAtPoint = this;
}
- return this;
+ DBG_OBJ_MSGF ("events", 0, "=> %p", childAtPoint);
+ DBG_OBJ_LEAVE ();
+ return childAtPoint;
}
@@ -2880,6 +2816,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);
@@ -2901,15 +2839,17 @@ void Textblock::queueDrawRange (int index1, int index2)
queueDrawArea (0, y, allocation.width, h);
}
+
+ DBG_OBJ_LEAVE ();
}
-void Textblock::setVerticalOffset (int verticalOffset)
+void Textblock::setClearPosition (int clearPosition)
{
- DBG_OBJ_ENTER ("resize", 0, "setVerticalOffset", "%d", verticalOffset);
+ DBG_OBJ_ENTER ("resize", 0, "setClearPosition", "%d", clearPosition);
- if (this->verticalOffset != verticalOffset) {
- this->verticalOffset = verticalOffset;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
+ if (this->clearPosition != clearPosition) {
+ this->clearPosition = clearPosition;
+ DBG_OBJ_SET_NUM ("clearPosition", clearPosition);
mustQueueResize = true;
queueDraw (); // Could perhaps be optimized.
}
@@ -2918,7 +2858,7 @@ void Textblock::setVerticalOffset (int verticalOffset)
}
/**
- * Called by dw::OutOfFlowMgr when the border has changed due to a
+ * Called by dw::OOFFloatsMgr when the border has changed due to a
* float (or some floats).
*
* "y", which given in widget coordinates, denotes the minimal
@@ -3047,7 +2987,7 @@ void Textblock::borderChanged (int y, Widget *vloat)
minWrapLineIndex, maxWrapLineIndex,
vloat->getGenerator() == this ? "yes" : "no");
- queueResize (OutOfFlowMgr::createRefNormalFlow (realWrapLineIndex), true);
+ queueResize (makeParentRefInFlow (realWrapLineIndex), true);
// Notice that the line no. realWrapLineIndex may not exist yet.
if (realWrapLineIndex == 0)
@@ -3083,7 +3023,7 @@ void Textblock::oofSizeChanged (bool extremesChanged)
extremesChanged ? "true" : "false");
queueResize (-1, extremesChanged);
- // See Textblock::getAvailWidthForChild(): Extremes changes may become also
+ // See Textblock::getAvailWidthOfChild(): Extremes changes may become also
// relevant for the children, under certain conditions:
if (extremesChanged && !mustBeWidenedToAvailWidth ())
containerSizeChanged ();
@@ -3091,6 +3031,21 @@ void Textblock::oofSizeChanged (bool extremesChanged)
DBG_OBJ_LEAVE ();
}
+int Textblock::getLineBreakWidth ()
+{
+ return lineBreakWidth;
+}
+
+bool Textblock::isPossibleContainer (int oofmIndex)
+{
+ return true;
+}
+
+bool Textblock::isPossibleContainerParent (int oofmIndex)
+{
+ return true;
+}
+
Textblock *Textblock::getTextblockForLine (Line *line)
{
return getTextblockForLine (line->firstWord, line->lastWord);
@@ -3144,19 +3099,16 @@ int Textblock::yOffsetOfPossiblyMissingLine (int lineNo)
int result;
if (lineNo == 0) {
- result = verticalOffset + getStyle()->boxOffsetY();
- DBG_OBJ_MSGF ("line.yoffset", 1, "first line: %d + %d = %d",
- verticalOffset, getStyle()->boxOffsetY(), result);
+ result = boxOffsetY();
+ DBG_OBJ_MSGF ("line.yoffset", 1, "first line: %d", result);
} else {
Line *prevLine = lines->getRef (lineNo - 1);
- result = verticalOffset + getStyle()->boxOffsetY() +
- prevLine->top + prevLine->boxAscent + prevLine->boxDescent +
- prevLine->breakSpace;
+ result = boxOffsetY() + prevLine->top + prevLine->boxAscent +
+ prevLine->boxDescent + prevLine->breakSpace;
DBG_OBJ_MSGF ("line.yoffset", 1,
- "other line: %d + %d + %d + (%d + %d) + %d = %d",
- verticalOffset, getStyle()->boxOffsetY(),
- prevLine->top, prevLine->boxAscent, prevLine->boxDescent,
- prevLine->breakSpace, result);
+ "other line: %d + %d + (%d + %d) + %d = %d",
+ boxOffsetY(), prevLine->top, prevLine->boxAscent,
+ prevLine->boxDescent, prevLine->breakSpace, result);
}
DBG_OBJ_LEAVE ();
diff --git a/dw/textblock.hh b/dw/textblock.hh
index c95dfff9..f041488b 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -3,8 +3,7 @@
#include <limits.h>
-#include "core.hh"
-#include "outofflowmgr.hh"
+#include "oofawarewidget.hh"
#include "../lout/misc.hh"
// These were used when improved line breaking and hyphenation were implemented.
@@ -124,7 +123,7 @@ namespace dw {
*
* 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:
@@ -152,7 +151,7 @@ namespace dw {
* necessary, or otherwise the line from which a rewrap is necessary.
*
*/
-class Textblock: public core::Widget
+class Textblock: public oof::OOFAwareWidget
{
private:
/**
@@ -246,10 +245,8 @@ private:
static const char *hyphenDrawChar;
- Textblock *containingBlock;
- OutOfFlowMgr *outOfFlowMgr;
-
protected:
+
/**
* \brief Implementation used for words.
*/
@@ -450,27 +447,24 @@ protected:
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;
@@ -528,8 +522,9 @@ protected:
/* This value is (currently) set by setAscent(). */
int lineBreakWidth;
- // Additional vertical offset, used for the "clear" attribute.
- int verticalOffset;
+ // Vertical offset at the top, used for the "clear" attribute. Goes
+ // into "extraSpace".
+ int clearPosition;
int wrapRefLines, wrapRefParagraphs; /* 0-based. Important: Both
are the line numbers, not
@@ -578,7 +573,7 @@ protected:
void calcBorders (int lastOofRef, int height);
void showMissingLines ();
void removeTemporaryLines ();
- void setVerticalOffset (int verticalOffset);
+ void setClearPosition (int clearPosition);
void decorateText (core::View *view, core::style::Style *style,
core::style::Color::Shading shading,
@@ -716,6 +711,7 @@ protected:
void processWord (int wordIndex);
virtual int wordWrap (int wordIndex, bool wrapAll);
int wrapWordInFlow (int wordIndex, bool wrapAll);
+ int wrapWordOofRef (int wordIndex, bool wrapAll);
void balanceBreakPosAndHeight (int wordIndex, int firstIndex,
int *searchUntil, bool tempNewLine,
int penaltyIndex, bool borderIsCalculated,
@@ -753,7 +749,12 @@ protected:
void sizeRequestImpl (core::Requisition *requisition);
void getExtremesImpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
- int getAvailWidthOfChild (Widget *child, bool forceValue);
+
+ void calcExtraSpaceImpl ();
+
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
void containerSizeChangedForChildren ();
bool affectsSizeChangeContainerChild (Widget *child);
bool usesAvailWidth ();
@@ -762,9 +763,6 @@ protected:
void markSizeChange (int ref);
void markExtremesChange (int ref);
- void notifySetAsTopLevel();
- void notifySetParent();
-
bool isBlockLevel ();
void draw (core::View *view, core::Rectangle *area);
@@ -783,17 +781,23 @@ protected:
core::style::Style *style,
int numBreaks, int *breakPos,
core::Requisition *wordSize);
- static bool isContainingBlock (Widget *widget);
inline bool mustBeWidenedToAvailWidth () {
DBG_OBJ_ENTER0 ("resize", 0, "mustBeWidenedToAvailWidth");
bool toplevel = getParent () == NULL,
block = getStyle()->display == core::style::DISPLAY_BLOCK,
- vloat = getStyle()->vloat != core::style::FLOAT_NONE,
- result = toplevel || (block && !vloat);
- DBG_OBJ_MSGF ("resize", 0, "=> %s (toplevel: %s, block: %s, float: %s)",
+ vloat = testWidgetFloat (this),
+ abspos = testWidgetAbsolutelyPositioned (this),
+ fixpos = testWidgetFixedlyPositioned (this),
+ // In detail, this depends on what the respective OOFM does
+ // with the child widget:
+ result = toplevel || (block && !(vloat || abspos || fixpos));
+ DBG_OBJ_MSGF ("resize", 0,
+ "=> %s (toplevel: %s, block: %s, float: %s, abspos: %s, "
+ "fixpos: %s)",
result ? "true" : "false", toplevel ? "true" : "false",
- block ? "true" : "false", vloat ? "true" : "false");
+ block ? "true" : "false", vloat ? "true" : "false",
+ abspos ? "true" : "false", fixpos ? "true" : "false");
DBG_OBJ_LEAVE ();
return result;
}
@@ -808,8 +812,8 @@ public:
static void setPenaltyEmDashRight2 (int penaltyRightEmDash2);
static void setStretchabilityFactor (int stretchabilityFactor);
- Textblock(bool limitTextWidth);
- ~Textblock();
+ Textblock (bool limitTextWidth);
+ ~Textblock ();
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
@@ -827,7 +831,7 @@ public:
void addParbreak (int space, core::style::Style *style);
void addLinebreak (core::style::Style *style);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
+ core::Widget *getWidgetAtPoint (int x, int y);
void handOverBreak (core::style::Style *style);
void changeLinkColor (int link, int newColor);
void changeWordStyle (int from, int to, core::style::Style *style,
@@ -836,7 +840,9 @@ public:
void borderChanged (int y, core::Widget *vloat);
void clearPositionChanged ();
void oofSizeChanged (bool extremesChanged);
- inline int getLineBreakWidth () { return lineBreakWidth; }
+ int getLineBreakWidth ();
+ bool isPossibleContainer (int oofmIndex);
+ bool isPossibleContainerParent (int oofmIndex);
};
#define DBG_SET_WORD_PENALTY(n, i, is) \
diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc
index c09d9a75..a0eb1bf4 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,27 +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 (oofm) {
- // TODO Consider start and end?
- *allocation =
- *(textblock->outOfFlowMgr->getWidget(index)->getAllocation());
- } else {
- int lineIndex = textblock->findLineOfWord (index);
+ if (inFlow ()) {
+ Textblock *textblock = (Textblock*)getWidget();
+ int index = getInFlowIndex (),
+ lineIndex = textblock->findLineOfWord (index);
Line *line = textblock->lines->getRef (lineIndex);
Word *word = textblock->words->getRef (index);
@@ -323,14 +228,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 5fa7bed8..8a7f1c9c 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -570,7 +570,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);
@@ -733,14 +733,15 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
startSearch, breakPos);
for (int i = startSearch; newFloatPos == -1 && i <= breakPos; i++) {
core::Content *content = &(words->getRef(i)->content);
- if (content->type == core::Content::WIDGET_OOF_REF &&
- // Later, absolutepositioned elements (which do not affect
- // borders) can be ignored at this point.
- (containingBlock->outOfFlowMgr->affectsLeftBorder
- (content->widget) ||
- containingBlock->outOfFlowMgr->affectsRightBorder
- (content->widget)))
- newFloatPos = i;
+ if (content->type == core::Content::WIDGET_OOF_REF) {
+ for (int j = 0; newFloatPos == -1 && j < NUM_OOFM; j++) {
+ if ((searchOutOfFlowMgr(j)->affectsLeftBorder(content
+ ->widget) ||
+ searchOutOfFlowMgr(j)->affectsRightBorder (content
+ ->widget)))
+ newFloatPos = i;
+ }
+ }
}
DBG_OBJ_MSGF ("construct.word", 2, "newFloatPos = %d", newFloatPos);
@@ -751,10 +752,17 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
floatHandled = true;
// Step 2: position the float and re-calculate the line.
- lastFloatPos = newFloatPos;
- containingBlock->outOfFlowMgr->tellPosition
- (words->getRef(lastFloatPos)->content.widget, yNewLine);
+ // TODO "x" is not quite correct, but this does not matter
+ // (currently?).
+
+ lastFloatPos = newFloatPos;
+
+ Widget *widget = words->getRef(lastFloatPos)->content.widget;
+ oof::OutOfFlowMgr *oofm =
+ searchOutOfFlowMgr (getWidgetOOFIndex (widget));
+ if (oofm && oofm->mayAffectBordersAtAll ())
+ oofm->tellPosition (widget, boxOffsetX (), yNewLine);
balanceBreakPosAndHeight (wordIndex, firstIndex, &searchUntil,
tempNewLine, penaltyIndex, false,
@@ -820,8 +828,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 ());
PRINTF ("The %s %p is assigned parentRef = %d.\n",
word->content.widget->getClassName(), word->content.widget,
word->content.widget->parentRef);
@@ -833,6 +840,29 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
return diffWords;
}
+int Textblock::wrapWordOofRef (int wordIndex, bool wrapAll)
+{
+ DBG_OBJ_ENTER ("construct.word", 0, "wrapWordOofRef", "%d, %s",
+ wordIndex, wrapAll ? "true" : "false");
+
+ Word *word = words->getRef (wordIndex);
+ Widget *widget = word->content.widget;
+ int yNewLine = yOffsetOfPossiblyMissingLine (lines->size ());
+
+ // Floats, which affect either border, are handled in wrapWordInFlow; this
+ // is rather for positioned elements.
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (getWidgetOOFIndex (widget));
+ 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).
+ oofm->tellPosition (widget, boxOffsetX (), yNewLine);
+
+ 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,
@@ -1414,8 +1444,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);
@@ -1503,8 +1534,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
+ word->content.widget->getStyle()->margin.top
- collapseMarginTop);
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lineIndex);
+ word->content.widget->parentRef = makeParentRefInFlow (lineIndex);
} else {
line->marginDescent =
misc::max (line->marginDescent, line->boxDescent);
@@ -1618,8 +1648,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;
@@ -1631,8 +1660,8 @@ int Textblock::calcLineBreakWidth (int lineIndex)
} else
leftBorder = rightBorder = 0;
- leftBorder = misc::max (leftBorder, getStyle()->boxOffsetX());
- rightBorder = misc::max (rightBorder, getStyle()->boxRestWidth());
+ leftBorder = misc::max (leftBorder, boxOffsetX());
+ rightBorder = misc::max (rightBorder, boxRestWidth());
lineBreakWidth -= (leftBorder + rightBorder);
@@ -1909,12 +1938,16 @@ void Textblock::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));
- }
+ if (lines->size () == 0) {
+ int clearPosition = 0;
+
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (searchOutOfFlowMgr(i))
+ clearPosition =
+ misc::max (clearPosition,
+ searchOutOfFlowMgr(i)->getClearPosition (this));
+
+ setClearPosition (misc::max (clearPosition, 0));
}
calcBorders (lines->size() > 0 ?
@@ -1934,81 +1967,97 @@ void Textblock::calcBorders (int lastOofRef, int height)
DBG_OBJ_ENTER ("construct.line", 0, "calcBorders", "%d, %d",
lastOofRef, height);
- if (containingBlock && containingBlock->outOfFlowMgr) {
- // Consider the example:
- //
- // <div>
- // Some text A ...
- // <p> Some text B ... <img style="float:right" ...> </p>
- // Some more text C ...
- // </div>
- //
- // If the image is large enough, it should float around the last
- // paragraph, "Some more text C ...":
- //
- // Some more text A ...
- //
- // Some more ,---------.
- // text B ... | |
- // | <img> |
- // Some more | | <---- Consider this line!
- // text C ... '---------'
- //
- // Since this float is generated in the <p> element, not in the-
- // <div> element, and since they are represented by different
- // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine,
- // and so lastOofRef, is -1 for the line marked with an arrow;
- // this would result in ignoring the float, because -1 is
- // equivalent to the very beginning of the <div> element ("Some
- // more text A ..."), which is not affected by the float.
- //
- // On the other hand, the only relevant values of
- // Line::lastOofRefPositionedBeforeThisLine are those greater
- // than the first word of the new line, so a solution is to use
- // the maximum of both.
+ newLineHasFloatLeft = newLineHasFloatRight = false;
+ newLineLeftBorder = newLineRightBorder = 0;
+ newLineLeftFloatHeight = newLineRightFloatHeight = 0;
+ bool oofmDefined = false;
+ for (int i = 0; i < NUM_OOFM && !oofmDefined; i++)
+ if (searchOutOfFlowMgr(i))
+ oofmDefined = true;
- int firstWordOfLine = lines->size() > 0 ?
- lines->getLastRef()->lastWord + 1 : 0;
+ if (oofmDefined) {
+ int firstWordOfLine =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
int effOofRef = misc::max (lastOofRef, firstWordOfLine - 1);
-
int y = yOffsetOfPossiblyMissingLine (lines->size ());
-
- 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>");
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr(i);
+ if (oofm) {
+ // 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.
+
+ bool thisHasLeft, thisHasRight;
+
+ thisHasLeft = oofm->hasFloatLeft (this, y, height, this, effOofRef);
+ newLineHasFloatLeft = newLineHasFloatLeft || thisHasLeft;
+ thisHasRight = oofm->hasFloatRight (this, y, height, this,
+ effOofRef);
+ newLineHasFloatRight = newLineHasFloatRight || thisHasRight;
+
+ newLineLeftBorder =
+ misc::max (newLineLeftBorder,
+ oofm->getLeftBorder (this, y, height, this,
+ effOofRef));
+ newLineRightBorder =
+ misc::max (newLineRightBorder,
+ oofm->getRightBorder (this, y, height, this,
+ effOofRef));
+
+ // TODO "max" is not really correct for the heights. (Does
+ // not matter, since only one, the float manager, returns
+ // meaningful values.)
+ if (thisHasLeft)
+ newLineLeftFloatHeight =
+ misc::max (newLineLeftFloatHeight,
+ oofm->getLeftFloatHeight (this, y, height, this,
+ effOofRef));
+ if (thisHasRight)
+ newLineRightFloatHeight =
+ misc::max (newLineRightFloatHeight,
+ oofm->getRightFloatHeight (this, y, height, this,
+ effOofRef));
+
+ DBG_OBJ_MSGF ("construct.line", 1,
+ "OOFM #%d: %d * %d (%s) / %d * %d (%s), at %d (%d), "
+ "until %d = max (%d, %d - 1)",
+ i, newLineLeftBorder, newLineLeftFloatHeight,
+ newLineHasFloatLeft ? "true" : "false",
+ newLineRightBorder, newLineRightFloatHeight,
+ newLineHasFloatRight ? "true" : "false",
+ y, height, effOofRef, lastOofRef, firstWordOfLine);
+ }
+ }
}
DBG_OBJ_SET_BOOL ("newLineHasFloatLeft", newLineHasFloatLeft);
diff --git a/dw/types.hh b/dw/types.hh
index 36d6caa1..081b8db4 100644
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -207,6 +207,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
diff --git a/dw/widget.cc b/dw/widget.cc
index ae8da192..553439ff 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -91,6 +91,8 @@ Widget::Widget ()
deleteCallbackFunc = NULL;
widgetImgRenderer = NULL;
+
+ stackingContextMgr = NULL;
}
Widget::~Widget ()
@@ -104,6 +106,9 @@ Widget::~Widget ()
delete widgetImgRenderer;
}
+ if (stackingContextMgr)
+ delete stackingContextMgr;
+
if (style)
style->unref ();
@@ -125,21 +130,24 @@ Widget::~Widget ()
*/
bool Widget::intersects (Rectangle *area, Rectangle *intersection)
{
- Rectangle parentArea, childArea;
-
- parentArea = *area;
- parentArea.x += parent->allocation.x;
- parentArea.y += parent->allocation.y;
-
- childArea.x = allocation.x;
- childArea.y = allocation.y;
- childArea.width = allocation.width;
- childArea.height = getHeight ();
-
- if (parentArea.intersectsWith (&childArea, intersection)) {
- intersection->x -= allocation.x;
- intersection->y -= allocation.y;
- return true;
+ if (wasAllocated ()) {
+ Rectangle parentArea, childArea;
+
+ parentArea = *area;
+ parentArea.x += parent->allocation.x;
+ parentArea.y += parent->allocation.y;
+
+ childArea.x = allocation.x;
+ childArea.y = allocation.y;
+ childArea.width = allocation.width;
+ childArea.height = getHeight ();
+
+ if (parentArea.intersectsWith (&childArea, intersection)) {
+ intersection->x -= allocation.x;
+ intersection->y -= allocation.y;
+ return true;
+ } else
+ return false;
} else
return false;
}
@@ -170,6 +178,17 @@ 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);
+ }
+
notifySetParent();
}
@@ -496,6 +515,7 @@ void Widget::sizeRequest (Requisition *requisition)
}
if (needsResize ()) {
+ calcExtraSpace ();
/** \todo Check requisition == &(this->requisition) and do what? */
sizeRequestImpl (requisition);
this->requisition = *requisition;
@@ -622,7 +642,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
@@ -903,6 +923,8 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ calcExtraSpace ();
+
// For backward compatibility (part 1/2):
extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
@@ -932,6 +954,24 @@ void Widget::getExtremes (Extremes *extremes)
}
/**
+ * \brief Calculates dw::core::Widget::extraSpace.
+ *
+ * Delegated to dw::core::Widget::calcExtraSpaceImpl. Called both from
+ * dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes.
+ */
+void Widget::calcExtraSpace ()
+{
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+ calcExtraSpaceImpl ();
+
+ DBG_OBJ_SET_NUM ("extraSpace.top", extraSpace.top);
+ DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom);
+ DBG_OBJ_SET_NUM ("extraSpace.left", extraSpace.left);
+ DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right);
+
+}
+
+/**
* \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when
* needed.
*/
@@ -1075,6 +1115,15 @@ 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);
+ }
+
if (sizeChanged)
queueResize (0, true);
else
@@ -1208,8 +1257,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);
@@ -1335,42 +1386,50 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
*
* Used by dw::core::Layout:getWidgetAtPoint.
*/
-Widget *Widget::getWidgetAtPoint (int x, int y, int level)
+Widget *Widget::getWidgetAtPoint (int x, int y)
{
- 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);
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getTopWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ // 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.
+
+ Widget *childAtPoint = NULL;
+ Iterator *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);
+ if (!StackingContextMgr::handledByStackingContextMgr (child) &&
+ child->wasAllocated ())
+ childAtPoint = child->getWidgetAtPoint (x, y);
}
it->unref ();
if (childAtPoint)
return childAtPoint;
- else
- return this;
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ return this;
} else
return NULL;
}
@@ -1383,6 +1442,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).
*
@@ -1392,18 +1469,31 @@ 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::sizeAllocateImpl (Allocation *allocation)
{
}
+/**
+ * \brief The actual implementation for calculating
+ * dw::core::Widget::extraSpace.
+ *
+ * The implementation gets a clean value of
+ * dw::core::Widget::extraSpace, which is only corrected. To make sure
+ * all possible influences are considered, the implementation of the
+ * base class should be called, too.
+ */
+void Widget::calcExtraSpaceImpl ()
+{
+}
+
void Widget::markSizeChange (int ref)
{
}
diff --git a/dw/widget.hh b/dw/widget.hh
index 0f3e2d37..9acb6605 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -180,19 +180,27 @@ 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;
+
/*inline void printFlags () {
DBG_IF_RTFL {
char buf[10 * 3 - 1 + 1];
@@ -271,6 +279,8 @@ protected:
*/
virtual void getExtremesImpl (Extremes *extremes) = 0;
+ virtual void calcExtraSpaceImpl ();
+
/**
* \brief See \ref dw-widget-sizes.
*/
@@ -292,8 +302,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,
@@ -425,6 +433,8 @@ public:
void getExtremes (Extremes *extremes);
void sizeAllocate (Allocation *allocation);
+ void calcExtraSpace ();
+
int getAvailWidth (bool forceValue);
int getAvailHeight (bool forceValue);
virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; }
@@ -441,6 +451,8 @@ 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 ();
@@ -480,11 +492,13 @@ public:
inline Layout *getLayout () { return layout; }
- virtual Widget *getWidgetAtPoint (int x, int y, int level);
+ virtual Widget *getWidgetAtPoint (int x, int y);
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);
/**
diff --git a/lout/debug.hh b/lout/debug.hh
index 896564cf..c4efbb9a 100644
--- a/lout/debug.hh
+++ b/lout/debug.hh
@@ -294,6 +294,13 @@
fflush (stdout); \
} D_STMT_END
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%d\n", \
+ RTFL_PREFIX_ARGS, obj, 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", \
@@ -367,6 +374,7 @@
#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_NUM_O(obj, 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
diff --git a/src/cssparser.cc b/src/cssparser.cc
index 1487a605..57661ff1 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -222,7 +222,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_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
{"letter-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_letter_spacing_enum_vals},
{"line-height",
@@ -277,7 +277,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 +793,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 +1177,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/styleengine.cc b/src/styleengine.cc
index 918e7460..a660b175 100644
--- a/src/styleengine.cc
+++ b/src/styleengine.cc
@@ -728,6 +728,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/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;
+}