summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rw-r--r--ChangeLog9
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/dw-miscellaneous.doc20
-rw-r--r--doc/dw-out-of-flow.doc31
-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/bullet.cc4
-rw-r--r--dw/bullet.hh4
-rw-r--r--dw/core.hh2
-rw-r--r--dw/image.cc35
-rw-r--r--dw/image.hh6
-rw-r--r--dw/iterator.cc71
-rw-r--r--dw/iterator.hh27
-rw-r--r--dw/layout.cc36
-rw-r--r--dw/layout.hh7
-rw-r--r--dw/oofawarewidget.cc846
-rw-r--r--dw/oofawarewidget.hh276
-rw-r--r--dw/oofawarewidget_iterator.cc261
-rw-r--r--dw/ooffloatsmgr.cc2403
-rw-r--r--dw/ooffloatsmgr.hh409
-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.cc784
-rw-r--r--dw/oofpositionedmgr.hh141
-rw-r--r--dw/outofflowmgr.cc2260
-rw-r--r--dw/outofflowmgr.hh490
-rw-r--r--dw/ruler.cc13
-rw-r--r--dw/ruler.hh4
-rw-r--r--dw/selection.cc102
-rw-r--r--dw/simpletablecell.cc5
-rw-r--r--dw/simpletablecell.hh2
-rw-r--r--dw/stackingcontextmgr.cc283
-rw-r--r--dw/stackingcontextmgr.hh77
-rw-r--r--dw/style.cc4
-rw-r--r--dw/style.hh14
-rw-r--r--dw/table.cc158
-rw-r--r--dw/table.hh24
-rw-r--r--dw/table_iterator.cc115
-rw-r--r--dw/tablecell.hh2
-rw-r--r--dw/textblock.cc642
-rw-r--r--dw/textblock.hh103
-rw-r--r--dw/textblock_iterator.cc249
-rw-r--r--dw/textblock_linebreaking.cc242
-rw-r--r--dw/types.hh4
-rw-r--r--dw/ui.cc4
-rw-r--r--dw/ui.hh3
-rw-r--r--dw/widget.cc372
-rw-r--r--dw/widget.hh64
-rw-r--r--lout/debug.hh354
-rw-r--r--lout/debug_rtfl.hh370
-rw-r--r--src/cssparser.cc27
-rw-r--r--src/dillo.cc24
-rw-r--r--src/html.cc2
-rw-r--r--src/styleengine.cc6
-rw-r--r--test/Makefile.am4
-rw-r--r--test/dw_simple_container.cc280
-rw-r--r--test/dw_simple_container.hh4
-rw-r--r--test/identity.cc55
63 files changed, 7941 insertions, 4114 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 f226bb49..d3fe8532 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-miscellaneous.doc b/doc/dw-miscellaneous.doc
new file mode 100644
index 00000000..118f5024
--- /dev/null
+++ b/doc/dw-miscellaneous.doc
@@ -0,0 +1,20 @@
+/** \page dw-miscellaneous Miscellaneous Notes on Dw
+
+This is a barely sorted list of issues which I consider noteworthy,
+but have yet to be moved to other parts of the documentation (which is
+partly to be created).
+
+General
+=======
+
+A **widget allocation outside of the allocation of the parent** is
+allowed, but the part outside is not visible.
+
+**Interrupted drawing:** ...
+
+Positioned element
+==================
+
+**Positioned elements outside of the container:** ...
+
+*/
diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc
index ea4a52bc..f5eade21 100644
--- a/doc/dw-out-of-flow.doc
+++ b/doc/dw-out-of-flow.doc
@@ -1,9 +1,30 @@
/** \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
============
@@ -209,6 +230,6 @@ Integration of line breaking and floats
Absolute and fixed positiones
=============================
-See <http://flpsed.org/hgweb/dillo_grows>.
+To be documented.
*/ \ No newline at end of file
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/bullet.cc b/dw/bullet.cc
index acaf81cc..0b4b5983 100644
--- a/dw/bullet.cc
+++ b/dw/bullet.cc
@@ -57,7 +57,9 @@ void Bullet::containerSizeChangedForChildren ()
DBG_OBJ_LEAVE ();
}
-void Bullet::draw (core::View *view, core::Rectangle *area)
+void Bullet::draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
int x, y, l;
bool filled = true;
diff --git a/dw/bullet.hh b/dw/bullet.hh
index 004187cd..7703a64b 100644
--- a/dw/bullet.hh
+++ b/dw/bullet.hh
@@ -17,7 +17,9 @@ protected:
void sizeRequestImpl (core::Requisition *requisition);
void getExtremesImpl (core::Extremes *extremes);
void containerSizeChangedForChildren ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
public:
diff --git a/dw/core.hh b/dw/core.hh
index 022574b1..9463df2b 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -25,6 +25,7 @@ class Layout;
class View;
class Widget;
class Iterator;
+class StackingContextMgr;
// Nothing yet to free.
inline void freeall () { }
@@ -53,6 +54,7 @@ class ResourceFactory;
#include "selection.hh"
#include "layout.hh"
#include "widget.hh"
+#include "stackingcontextmgr.hh"
#include "ui.hh"
#undef __INCLUDED_FROM_DW_CORE_HH__
diff --git a/dw/image.cc b/dw/image.cc
index d6c2ea9d..bd7c1ac9 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;
@@ -404,7 +404,9 @@ bool Image::buttonReleaseImpl (core::EventButton *event)
return false;
}
-void Image::draw (core::View *view, core::Rectangle *area)
+void Image::draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
int dx, dy;
core::Rectangle content, intersection;
@@ -412,8 +414,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 +442,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 +515,8 @@ void Image::drawRow (int row)
buffer->getRowArea (row, &area);
if (area.width && area.height)
- queueDrawArea (area.x + getStyle()->boxOffsetX (),
- area.y + getStyle()->boxOffsetY (),
- area.width, area.height);
+ queueDrawArea (area.x + boxOffsetX (), area.y + boxOffsetY (), area.width,
+ area.height);
}
void Image::finish ()
diff --git a/dw/image.hh b/dw/image.hh
index 9adf7806..85776db5 100644
--- a/dw/image.hh
+++ b/dw/image.hh
@@ -134,8 +134,10 @@ protected:
void getExtremesImpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
void containerSizeChangedForChildren ();
-
- void draw (core::View *view, core::Rectangle *area);
+
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
diff --git a/dw/iterator.cc b/dw/iterator.cc
index 0edb580b..fccd4c1a 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
// -------------------
@@ -906,5 +898,68 @@ void CharIterator::unhighlight (CharIterator *it1, CharIterator *it2,
}
}
+// ---------------------------
+// StackingIteratorStack
+// ---------------------------
+
+StackingIteratorStack::StackingIteratorStack ()
+{
+ vector = new lout::container::untyped::Vector (1, true);
+ topPos = -1;
+}
+
+StackingIteratorStack::~StackingIteratorStack ()
+{
+ delete vector;
+}
+
+void StackingIteratorStack::intoStringBuffer(lout::misc::StringBuffer *sb)
+{
+ sb->append ("[ ");
+
+ for (int i = 0; i < vector->size (); i++) {
+ if (i != 0)
+ sb->append (" ");
+ if (i == topPos)
+ sb->append ("<b>");
+ vector->get(i)->intoStringBuffer (sb);
+ if (i == topPos)
+ sb->append ("</b>");
+ }
+
+ sb->append (" ]");
+}
+
+void StackingIteratorStack::push (lout::object::Object *object)
+{
+ assert (atRealTop ());
+ vector->put (object);
+ topPos++;
+}
+
+void StackingIteratorStack::pop ()
+{
+ assert (atRealTop ());
+ vector->remove (vector->size () - 1);
+ topPos--;
+}
+
+void StackingIteratorStack::forward ()
+{
+ assert (!atRealTop ());
+ topPos++;
+}
+
+void StackingIteratorStack::backward ()
+{
+ topPos--;
+}
+
+void StackingIteratorStack::cleanup ()
+{
+ while (!atRealTop ())
+ vector->remove (vector->size () - 1);
+}
+
} // namespace core
} // namespace dw
diff --git a/dw/iterator.hh b/dw/iterator.hh
index abf31d0b..acef26da 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 ();
};
@@ -265,6 +263,31 @@ public:
hpos, vpos); }
};
+/**
+ * \brief Some completely different kind of iterator: ...
+ */
+class StackingIteratorStack
+{
+private:
+ lout::container::untyped::Vector *vector;
+ int topPos;
+
+public:
+ StackingIteratorStack ();
+ ~StackingIteratorStack ();
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ inline bool atRealTop () { return topPos == vector->size () - 1; }
+ inline lout::object::Object *getTop () { return vector->get (topPos); }
+
+ void push (lout::object::Object *object);
+ void pop ();
+ void forward ();
+ void backward ();
+ void cleanup ();
+};
+
} // namespace core
} // namespace dw
diff --git a/dw/layout.cc b/dw/layout.cc
index c2a53d08..c87606dd 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -374,6 +374,14 @@ void Layout::addWidget (Widget *widget)
return;
}
+ // The toplevel widget always establishes a stacking context. It could
+ // already be set in Widget::setStyle().
+ if (widget->stackingContextMgr == NULL) {
+ widget->stackingContextMgr = new StackingContextMgr (widget);
+ DBG_OBJ_ASSOC (widget, widget->stackingContextMgr);
+ widget->stackingContextWidget = widget;
+ }
+
topLevel = widget;
widget->layout = this;
widget->container = NULL;
@@ -654,6 +662,9 @@ bool Layout::calcScrollInto (int requestedValue, int requestedSize,
void Layout::draw (View *view, Rectangle *area)
{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
Rectangle widgetArea, intersection, widgetDrawArea;
// First of all, draw background image. (Unlike background *color*,
@@ -693,11 +704,13 @@ void Layout::draw (View *view, Rectangle *area)
widgetDrawArea.width = intersection.width;
widgetDrawArea.height = intersection.height;
- topLevel->draw (view, &widgetDrawArea);
+ topLevel->drawToplevel (view, &widgetDrawArea);
view->finishDrawing (&intersection);
}
}
+
+ DBG_OBJ_LEAVE ();
}
int Layout::currHScrollbarThickness()
@@ -1093,12 +1106,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->getWidgetAtPointToplevel (x, y);
else
- return NULL;
+ widget = NULL;
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
}
@@ -1108,12 +1126,16 @@ Widget *Layout::getWidgetAtPoint (int x, int y)
*/
void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
{
+ DBG_OBJ_ENTER ("events", 0, "moveToWidget", "%p, %d",
+ newWidgetAtPoint, state);
+
Widget *ancestor, *w;
Widget **track;
int trackLen, i, i_a;
EventCrossing crossingEvent;
- _MSG("moveToWidget: wap=%p nwap=%p\n",widgetAtPoint,newWidgetAtPoint);
+ DBG_OBJ_MSGF ("events", 1, "(old) widgetAtPoint = %p", widgetAtPoint);
+
if (newWidgetAtPoint != widgetAtPoint) {
// The mouse pointer has been moved into another widget.
if (newWidgetAtPoint && widgetAtPoint)
@@ -1183,6 +1205,8 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
widgetAtPoint = newWidgetAtPoint;
updateCursor ();
}
+
+ DBG_OBJ_LEAVE ();
}
/**
diff --git a/dw/layout.hh b/dw/layout.hh
index 32b9a134..16d19979 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -314,7 +314,12 @@ public:
/* View */
- inline void expose (View *view, Rectangle *area) { draw (view, area); }
+ inline void expose (View *view, Rectangle *area) {
+ DBG_OBJ_ENTER ("draw", 0, "expose", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ draw (view, area);
+ DBG_OBJ_LEAVE ();
+ }
/**
* \brief This function is called by a view, to delegate a button press
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
new file mode 100644
index 00000000..ff04a642
--- /dev/null
+++ b/dw/oofawarewidget.cc
@@ -0,0 +1,846 @@
+/*
+ * 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 dw::core::style;
+using namespace lout::object;
+using namespace lout::misc;
+using namespace lout::container::typed;
+
+namespace dw {
+
+namespace oof {
+
+const char *OOFAwareWidget::OOFM_NAME[NUM_OOFM] = {
+ "FLOATS", "ABSOLUTE", "FIXED"
+};
+
+OOFAwareWidget::OOFStackingIterator::OOFStackingIterator
+ (OOFAwareWidget *widget, bool atEnd)
+{
+ if (atEnd) {
+ majorLevel = OOFStackingIterator::END - 1;
+ minorLevel = widget->getLastMinorLevel (majorLevel);
+ index = widget->getLastLevelIndex (majorLevel, minorLevel);
+ } else {
+ majorLevel = OOFStackingIterator::START + 1;
+ minorLevel = index = 0;
+ }
+
+ widgetsDrawnAfterInterruption = NULL;
+}
+
+OOFAwareWidget::OOFStackingIterator::~OOFStackingIterator ()
+{
+ if (widgetsDrawnAfterInterruption)
+ delete widgetsDrawnAfterInterruption;
+}
+
+void OOFAwareWidget::OOFStackingIterator::registerWidgetDrawnAfterInterruption
+ (Widget *widget)
+{
+ if (widgetsDrawnAfterInterruption == NULL)
+ widgetsDrawnAfterInterruption = new HashSet<TypedPointer<Widget> > (true);
+
+ TypedPointer<Widget> *p = new TypedPointer<Widget> (widget);
+ assert (!widgetsDrawnAfterInterruption->contains (p));
+ widgetsDrawnAfterInterruption->put (p);
+}
+
+bool OOFAwareWidget::OOFStackingIterator::hasWidgetBeenDrawnAfterInterruption
+ (Widget *widget)
+{
+ if (widgetsDrawnAfterInterruption) {
+ TypedPointer<Widget> p (widget);
+ return widgetsDrawnAfterInterruption->contains (&p);
+ } else
+ return false;
+}
+
+const char *OOFAwareWidget::OOFStackingIterator::majorLevelText (int majorLevel)
+{
+ switch (majorLevel) {
+ case START: return "START";
+ case BACKGROUND: return "BACKGROUND";
+ case SC_BOTTOM: return "SC_BOTTOM";
+ case IN_FLOW: return "IN_FLOW";
+ case OOF_REF: return "OOF_REF";
+ case OOF_CONT: return "OOF_CONT";
+ case SC_TOP: return "SC_TOP";
+ case END: return "END";
+ default: return "???";
+ }
+}
+
+void OOFAwareWidget::OOFStackingIterator::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("(");
+ sb->append (majorLevelText (majorLevel));
+ sb->append (", ");
+ sb->appendInt (minorLevel);
+ sb->append (", ");
+ sb->appendInt (index);
+ sb->append (")");
+}
+
+int OOFAwareWidget::CLASS_ID = -1;
+
+OOFAwareWidget::OOFAwareWidget ()
+{
+ DBG_OBJ_CREATE ("dw::oof::OOFAwareWidget");
+ registerName ("dw::oof::OOFAwareWidget", &CLASS_ID);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oofContainer[i] = NULL;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ outOfFlowMgr[i] = NULL;
+ }
+}
+
+OOFAwareWidget::~OOFAwareWidget ()
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if(outOfFlowMgr[i]) {
+ // I feel more comfortable by letting the OOF aware widget delete
+ // these widgets, instead of doing this in ~OutOfFlowMgr.
+ for (int j = 0; j < outOfFlowMgr[i]->getNumWidgets (); j++)
+ delete outOfFlowMgr[i]->getWidget (j);
+
+ delete outOfFlowMgr[i];
+ }
+ }
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFAwareWidget::notifySetAsTopLevel ()
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oofContainer[i] = this;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ }
+}
+
+bool OOFAwareWidget::getOOFMIndex (Widget *widget)
+{
+ if (testWidgetFloat (widget))
+ return OOFM_FLOATS;
+ else if (testWidgetAbsolutelyPositioned (widget))
+ return OOFM_ABSOLUTE;
+ else if (testWidgetFixedlyPositioned (widget))
+ return OOFM_FIXED;
+ else {
+ lout::misc::assertNotReached ();
+ return -1;
+ }
+}
+
+bool OOFAwareWidget::isOOFContainer (Widget *widget, int oofmIndex)
+{
+ // TODO The methods isPossibleContainer() and isPossibleContainerParent()
+ // are only used in few cases. Does not matter currently, however.
+
+ switch (oofmIndex) {
+ case OOFM_FLOATS:
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (// For floats, only some OOF aware widgets are considered as
+ // containers.
+ ((OOFAwareWidget*)widget)->isPossibleContainer (OOFM_FLOATS) &&
+ // The second condition: that this block is "out of flow", in a
+ // wider sense.
+ (// The toplevel widget is "out of flow", since there is no
+ // parent, and so no context.
+ widget->getParent() == NULL ||
+ // A similar reasoning applies to a widget with an
+ // unsuitable parent (typical example: a table cell (this
+ // is also a text block, so possible float container)
+ // within a table widget, which is not a suitable float
+ // container parent).
+ !(widget->getParent()->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ ((OOFAwareWidget*)widget->getParent())
+ ->isPossibleContainerParent (OOFM_FLOATS)) ||
+ // Inline blocks are containing blocks, too.
+ widget->getStyle()->display == DISPLAY_INLINE_BLOCK ||
+ // Same for blocks with 'overview' set to another value than
+ // (the default value) 'visible'.
+ widget->getStyle()->overflow != OVERFLOW_VISIBLE ||
+ // Finally, "out of flow" in a narrower sense: floats;
+ // absolutely and fixedly positioned elements. (No
+ // relatively positioned elements; since the latters
+ // constitute a stacking context, drawing of floats gets
+ // somewhat more complicated; see "interrupting the drawing
+ // process" in "dw-stacking-context.doc".
+ testWidgetOutOfFlow (widget)));
+
+ case OOFM_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*))
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisitionByOOF", "%d * (%d + %d), ...",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofWidth, oofHeight;
+
+ outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * %d", oofWidth, oofHeight);
+
+ if (oofWidth > requisition->width) {
+ if (outOfFlowMgr[i]->containerMustAdjustExtraSpace () &&
+ adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) {
+ extraSpace.right = max (extraSpace.right,
+ oofWidth - requisition->width);
+ DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right);
+ }
+
+ requisition->width = oofWidth;
+ }
+
+ if (oofHeight > requisition->ascent + requisition->descent) {
+ if (outOfFlowMgr[i]->containerMustAdjustExtraSpace () &&
+ adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) {
+ extraSpace.bottom = max (extraSpace.bottom,
+ oofHeight - (requisition->ascent +
+ requisition->descent));
+ DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom);
+ }
+
+ splitHeightFun (oofHeight,
+ &requisition->ascent, &requisition->descent);
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::correctExtremesByOOF (Extremes *extremes)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremesByOOF", "%d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d / %d",
+ oofMinWidth, oofMaxWidth);
+
+ extremes->minWidth = max (extremes->minWidth, oofMinWidth);
+ extremes->minWidthIntrinsic = max (extremes->minWidthIntrinsic,
+ oofMinWidth);
+ extremes->maxWidth = max (extremes->maxWidth, oofMaxWidth);
+ extremes->maxWidthIntrinsic = max (extremes->maxWidthIntrinsic,
+ oofMinWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::sizeAllocateStart (Allocation *allocation)
+{
+
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (oofContainer[i]->outOfFlowMgr[i])
+ oofContainer[i]->outOfFlowMgr[i]->sizeAllocateStart (this, allocation);
+}
+
+void OOFAwareWidget::sizeAllocateEnd ()
+{
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (oofContainer[i]->outOfFlowMgr[i])
+ oofContainer[i]->outOfFlowMgr[i]->sizeAllocateEnd (this);
+}
+
+void OOFAwareWidget::containerSizeChangedForChildrenOOF ()
+{
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (outOfFlowMgr[i])
+ outOfFlowMgr[i]->containerSizeChangedForChildren ();
+}
+
+bool OOFAwareWidget::doesWidgetOOFInterruptDrawing (Widget *widget)
+{
+ DBG_OBJ_ENTER ("draw", 0, "doesWidgetOOFInterruptDrawing", "%p", widget);
+
+ // This is the generator of the widget.
+ int oofmIndex = getOOFMIndex (widget);
+ DBG_OBJ_MSGF ("draw", 1, "oofmIndex = %d", oofmIndex);
+
+ int cl = oofContainer[oofmIndex]->stackingContextWidget->getLevel (),
+ gl = stackingContextWidget->getLevel ();
+
+ DBG_OBJ_MSGF_O ("draw", 1, (void*)NULL, "%d < %d => %s",
+ cl, gl, cl < gl ? "true" : "false");
+
+ DBG_OBJ_LEAVE ();
+ return cl < gl;
+}
+
+void OOFAwareWidget::draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ while (*interruptedWidget == NULL &&
+ ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel
+ < OOFStackingIterator::END) {
+ drawLevel (view, area, iteratorStack, interruptedWidget,
+ ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel);
+
+ if (*interruptedWidget) {
+ if ((*interruptedWidget)->getParent () == this) {
+ DBG_OBJ_MSGF ("draw", 1, "interrupted at %p, drawing seperately",
+ *interruptedWidget);
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "iteratorStack: %s", sb.getChars ());
+ }
+
+ core::Rectangle interruptedWidgetArea;
+ if ((*interruptedWidget)->intersects (area,
+ &interruptedWidgetArea)) {
+ // Similar to Widget::drawToplevel. Nested interruptions are not
+ // allowed.
+ StackingIteratorStack iteratorStack2;
+ Widget *interruptedWidget2 = NULL;
+ (*interruptedWidget)->drawTotal (view, &interruptedWidgetArea,
+ &iteratorStack2,
+ &interruptedWidget2);
+ assert (interruptedWidget2 == NULL);
+ }
+
+ ((OOFStackingIterator*)iteratorStack->getTop())
+ ->registerWidgetDrawnAfterInterruption (*interruptedWidget);
+
+ // Continue with the current state of "iterator".
+ *interruptedWidget = NULL;
+ DBG_OBJ_MSG ("draw", 1, "done with interruption");
+ }
+ } else {
+ OOFStackingIterator* osi =
+ (OOFStackingIterator*)iteratorStack->getTop();
+ osi->majorLevel++;
+ osi->minorLevel = osi->index = 0;
+ }
+ }
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::drawLevel (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel)
+{
+ DBG_OBJ_ENTER ("draw", 0, "OOFAwareWidget/drawLevel",
+ "(%d, %d, %d * %d), %s",
+ area->x, area->y, area->width, area->height,
+ OOFStackingIterator::majorLevelText (majorLevel));
+
+ switch (majorLevel) {
+ case OOFStackingIterator::START:
+ break;
+
+ case OOFStackingIterator::BACKGROUND:
+ drawWidgetBox (view, area, false);
+ break;
+
+ case OOFStackingIterator::SC_BOTTOM:
+ if (stackingContextMgr) {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+ stackingContextMgr->drawBottom (view, area, iteratorStack,
+ interruptedWidget, &osi->minorLevel,
+ &osi->index);
+ }
+ break;
+
+ case OOFStackingIterator::IN_FLOW:
+ // Should be implemented in the sub class.
+ break;
+
+ case OOFStackingIterator::OOF_REF:
+ // Should be implemented in the sub class (when references are hold).
+ break;
+
+ case OOFStackingIterator::OOF_CONT:
+ drawOOF (view, area, iteratorStack, interruptedWidget);
+ break;
+
+ case OOFStackingIterator::SC_TOP:
+ if (stackingContextMgr) {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+ stackingContextMgr->drawTop (view, area, iteratorStack,
+ interruptedWidget, &osi->minorLevel,
+ &osi->index);
+ }
+ break;
+
+ case OOFStackingIterator::END:
+ break;
+ }
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::drawOOF (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop ();
+ assert (osi->majorLevel == OOFStackingIterator::OOF_CONT);
+
+ while (*interruptedWidget == NULL && osi->minorLevel < NUM_OOFM) {
+ if(outOfFlowMgr[osi->minorLevel])
+ outOfFlowMgr[osi->minorLevel]->draw (view, area, iteratorStack,
+ interruptedWidget, &(osi->index));
+ if (*interruptedWidget == NULL) {
+ osi->minorLevel++;
+ osi->index = 0;
+ }
+ }
+}
+
+Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *widgetAtPoint = NULL;
+
+ if (wasAllocated () && x >= allocation.x && y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ()) {
+ while (widgetAtPoint == NULL && *interruptedWidget == NULL &&
+ ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel
+ > OOFStackingIterator::START) {
+ widgetAtPoint =
+ getWidgetAtPointLevel (x, y, iteratorStack, interruptedWidget,
+ ((OOFStackingIterator*)iteratorStack
+ ->getTop())->majorLevel);
+
+ if (*interruptedWidget) {
+ assert (widgetAtPoint == NULL); // Not both set.
+
+ if ((*interruptedWidget)->getParent () == this) {
+ DBG_OBJ_MSGF ("events", 1,
+ "interrupted at %p, searching widget seperately",
+ *interruptedWidget);
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2, "iteratorStack: %s",
+ sb.getChars ());
+ }
+
+ // Similar to Widget::getWidgetAtPointToplevel. Nested
+ // interruptions are not allowed.
+ StackingIteratorStack iteratorStack2;
+ Widget *interruptedWidget2 = NULL;
+ widgetAtPoint = (*interruptedWidget)
+ ->getWidgetAtPointTotal (x, y, &iteratorStack2,
+ &interruptedWidget2);
+ assert (interruptedWidget2 == NULL);
+
+ ((OOFStackingIterator*)iteratorStack->getTop())
+ ->registerWidgetDrawnAfterInterruption (*interruptedWidget);
+
+ // Continue with the current state of "iterator".
+ *interruptedWidget = NULL;
+ DBG_OBJ_MSG ("events", 1, "done with interruption");
+
+ // The interrupted widget may have returned non-NULL. In this
+ // case, the stack must be cleaned up explicitly, which would
+ // otherwise be done implicitly during the further search.
+ // (Since drawing is never quit completely, this problem only
+ // applies to searching.)
+ if (widgetAtPoint) {
+ iteratorStack->cleanup ();
+
+ DBG_IF_RTFL {
+ StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2,
+ "iteratorStack after cleanup: %s",
+ sb.getChars ());
+ }
+ }
+
+ }
+ } else {
+ OOFStackingIterator* osi =
+ (OOFStackingIterator*)iteratorStack->getTop();
+ osi->majorLevel--;
+ if (osi->majorLevel > OOFStackingIterator::START) {
+ osi->minorLevel = getLastMinorLevel (osi->majorLevel);
+ osi->index =
+ getLastLevelIndex (osi->majorLevel, osi->minorLevel);
+ }
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+Widget *OOFAwareWidget::getWidgetAtPointLevel (int x, int y,
+ StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int majorLevel)
+{
+ DBG_OBJ_ENTER ("events", 0, "OOFAwareWidget/getWidgetAtPointLevel",
+ "%d, %d, %s", x, y,
+ OOFStackingIterator::majorLevelText (majorLevel));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (majorLevel) {
+ case OOFStackingIterator::BACKGROUND:
+ if (wasAllocated () && x >= allocation.x && y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ())
+ widgetAtPoint = this;
+ break;
+
+ case OOFStackingIterator::SC_BOTTOM:
+ if (stackingContextMgr) {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+ widgetAtPoint =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y, iteratorStack,
+ interruptedWidget,
+ &osi->minorLevel,
+ &osi->index);
+ }
+ break;
+
+ case OOFStackingIterator::IN_FLOW:
+ // Should be implemented in the sub class.
+ assertNotReached ();
+ break;
+
+ case OOFStackingIterator::OOF_REF:
+ // Should be implemented in the sub class (when references are hold).
+ break;
+
+ case OOFStackingIterator::OOF_CONT:
+ widgetAtPoint =
+ getWidgetOOFAtPoint (x, y, iteratorStack, interruptedWidget);
+ break;
+
+ case OOFStackingIterator::SC_TOP:
+ if (stackingContextMgr) {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+ widgetAtPoint =
+ stackingContextMgr->getTopWidgetAtPoint (x, y, iteratorStack,
+ interruptedWidget,
+ &osi->minorLevel,
+ &osi->index);
+ }
+ break;
+
+ default:
+ assertNotReached ();
+ }
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget)
+{
+ OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop ();
+ assert (osi->majorLevel == OOFStackingIterator::OOF_CONT);
+
+ Widget *widgetAtPoint = NULL;
+
+ while (*interruptedWidget == NULL && widgetAtPoint == NULL &&
+ osi->minorLevel >= 0) {
+ if (outOfFlowMgr[osi->minorLevel])
+ widgetAtPoint =
+ outOfFlowMgr[osi->minorLevel]->getWidgetAtPoint (x, y,
+ iteratorStack,
+ interruptedWidget,
+ &(osi->index));
+
+ if (*interruptedWidget == NULL) {
+ osi->minorLevel--;
+ if (osi->minorLevel > 0 && outOfFlowMgr[osi->minorLevel] != NULL)
+ osi->index = outOfFlowMgr[osi->minorLevel]->getNumWidgets () - 1;
+ }
+ }
+
+ return widgetAtPoint;
+}
+
+int OOFAwareWidget::getLastMinorLevel (int majorLevel)
+{
+ switch (majorLevel) {
+ case OOFStackingIterator::BACKGROUND:
+ return 0;
+
+ case OOFStackingIterator::SC_BOTTOM:
+ case OOFStackingIterator::SC_TOP:
+ // See StackingContextMgr: refers to list of z-indices; region
+ // (top or bottom) does not play a role.
+ if (stackingContextMgr)
+ return stackingContextMgr->getNumZIndices () - 1;
+ else
+ return 0;
+
+ case OOFStackingIterator::IN_FLOW:
+ return 0;
+
+ case OOFStackingIterator::OOF_REF:
+ case OOFStackingIterator::OOF_CONT:
+ return NUM_OOFM - 1;
+
+
+ default:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+int OOFAwareWidget::getLastLevelIndex (int majorLevel, int minorLevel)
+{
+ switch (majorLevel) {
+ case OOFStackingIterator::BACKGROUND:
+ return 0;
+
+ case OOFStackingIterator::SC_BOTTOM:
+ case OOFStackingIterator::SC_TOP:
+ if (stackingContextMgr)
+ return stackingContextMgr->getNumChildSCWidgets () - 1;
+ else
+ return 0;
+
+ case OOFStackingIterator::IN_FLOW:
+ // Should be implemented in the sub class.
+ assertNotReached ();
+
+ case OOFStackingIterator::OOF_REF:
+ // Should be implemented in the sub class (when references are hold).
+ return 0;
+
+ case OOFStackingIterator::OOF_CONT:
+ if(outOfFlowMgr[minorLevel])
+ return outOfFlowMgr[minorLevel]->getNumWidgets () - 1;
+ else
+ return 0;
+
+ default:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+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));
+}
+
+Object *OOFAwareWidget::stackingIterator (bool atEnd)
+{
+ return new OOFStackingIterator (this, atEnd);
+}
+
+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..17123910
--- /dev/null
+++ b/dw/oofawarewidget.hh
@@ -0,0 +1,276 @@
+#ifndef __DW_OOFAWAREWIDGET_HH__
+#define __DW_OOFAWAREWIDGET_HH__
+
+#include "core.hh"
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+namespace oof {
+
+/**
+ * \brief Base class for widgets which can act as container and
+ * generator for widgets out of flow.
+ *
+ * (Perhaps it should be diffenciated between the two roles, container
+ * and generator, but this would make multiple inheritance necessary.)
+ *
+ * See \ref dw-out-of-flow for an overview.
+ *
+ * Requirements for sub classes (in most cases refer to dw::Textblock
+ * as a good example):
+ *
+ * - A sub class should at least take care to call these methods at the
+ * respective points:
+ *
+ * - dw::oof::OOFAwareWidget::correctRequisitionByOOF (from
+ * dw::core::Widget::getExtremesImpl)
+ * - dw::oof::OOFAwareWidget::correctExtremesByOOF (from
+ * dw::core::Widget::sizeRequestImpl)
+ * - dw::oof::OOFAwareWidget::sizeAllocateStart
+ * - dw::oof::OOFAwareWidget::sizeAllocateEnd (latter two from
+ * dw::core::Widget::sizeAllocateImpl)
+ * - dw::oof::OOFAwareWidget::containerSizeChangedForChildrenOOF
+ * (from dw::core::Widget::containerSizeChangedForChildren)
+ * - dw::oof::OOFAwareWidget::drawOOF (from dw::core::Widget::draw)
+ * - dw::oof::OOFAwareWidget::getWidgetOOFAtPoint (from
+ * dw::core::Widget::getWidgetAtPoint)
+ *
+ * - Implementations of dw::core::Widget::getAvailWidthOfChild and
+ * dw::core::Widget::getAvailHeightOfChild have to distinguish
+ * between widgets in flow and out of flow; 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 };
+ static const char *OOFM_NAME[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 ();
+ };
+
+ 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 bool getOOFMIndex (Widget *widget);
+
+ void initOutOfFlowMgrs ();
+ void correctRequisitionByOOF (core::Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremesByOOF (core::Extremes *extremes);
+ void sizeAllocateStart (core::Allocation *allocation);
+ void sizeAllocateEnd ();
+ void containerSizeChangedForChildrenOOF ();
+
+ virtual void drawLevel (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel);
+ void drawOOF (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+
+ Widget *getWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ virtual Widget *getWidgetAtPointLevel (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int majorLevel);
+ Widget *getWidgetOOFAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+
+ virtual int getLastMinorLevel (int majorLevel);
+ virtual int getLastLevelIndex (int majorLevel, int minorLevel);
+
+ 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);
+
+
+public:
+ static int CLASS_ID;
+
+ class OOFStackingIterator: public lout::object::Object
+ {
+ private:
+ lout::container::typed::HashSet<lout::object::TypedPointer<Widget> >
+ *widgetsDrawnAfterInterruption;
+
+ public:
+ enum { START, BACKGROUND, SC_BOTTOM, IN_FLOW, OOF_REF, OOF_CONT, SC_TOP,
+ END } ;
+ int majorLevel, minorLevel, index;
+
+ static const char *majorLevelText (int majorLevel);
+
+ OOFStackingIterator (OOFAwareWidget *widget, bool atEnd);
+ ~OOFStackingIterator ();
+
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ void registerWidgetDrawnAfterInterruption (Widget *widget);
+ bool hasWidgetBeenDrawnAfterInterruption (Widget *widget);
+ };
+
+ OOFAwareWidget ();
+ ~OOFAwareWidget ();
+
+ static inline bool testStyleFloat (core::style::Style *style)
+ { return style->vloat != core::style::FLOAT_NONE; }
+
+ static inline bool testStyleAbsolutelyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_ABSOLUTE; }
+ static inline bool testStyleFixedlyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_FIXED; }
+ static inline bool testStyleRelativelyPositioned (core::style::Style *style)
+ { return style->position == core::style::POSITION_RELATIVE; }
+
+ static inline bool testStylePositioned (core::style::Style *style)
+ { return testStyleAbsolutelyPositioned (style) ||
+ testStyleRelativelyPositioned (style) ||
+ testStyleFixedlyPositioned (style); }
+
+ static inline bool testStyleOutOfFlow (core::style::Style *style)
+ { return testStyleFloat (style) || testStyleAbsolutelyPositioned (style)
+ || testStyleFixedlyPositioned (style); }
+
+ static inline bool testWidgetFloat (Widget *widget)
+ { return testStyleFloat (widget->getStyle ()); }
+
+ static inline bool testWidgetAbsolutelyPositioned (Widget *widget)
+ { return testStyleAbsolutelyPositioned (widget->getStyle ()); }
+ static inline bool testWidgetFixedlyPositioned (Widget *widget)
+ { return testStyleFixedlyPositioned (widget->getStyle ()); }
+ static inline bool testWidgetRelativelyPositioned (Widget *widget)
+ { return testStyleRelativelyPositioned (widget->getStyle ()); }
+
+ static inline bool testWidgetPositioned (Widget *widget)
+ { return testStylePositioned (widget->getStyle ()); }
+
+ static inline bool testWidgetOutOfFlow (Widget *widget)
+ { return testStyleOutOfFlow (widget->getStyle ()); }
+
+ bool doesWidgetOOFInterruptDrawing (Widget *widget);
+
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ lout::object::Object *stackingIterator (bool atEnd);
+
+ 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..b7a4c8bc
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,2403 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ooffloatsmgr.hh"
+#include "oofawarewidget.hh"
+#include "../lout/debug.hh"
+
+#include <limits.h>
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace dw {
+
+namespace oof {
+
+OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget)
+{
+ this->oofm = oofm;
+ this->widget = widget;
+ wasAllocated = false;
+ xCB = yCB = width = height = -1;
+}
+
+void OOFFloatsMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
+ int width, int height)
+{
+ DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
+ wasAllocated ? "true" : "false", xCB, yCB, width, height);
+
+ this->wasAllocated = wasAllocated;
+ this->xCB = xCB;
+ this->yCB = yCB;
+ this->width = width;
+ this->height = height;
+
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
+ DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
+
+ DBG_OBJ_LEAVE_O (widget);
+}
+
+// ----------------------------------------------------------------------
+
+OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex)
+ : WidgetInfo (oofm, widget)
+{
+ this->generatingBlock = generatingBlock;
+ this->externalIndex = externalIndex;
+
+ yReq = yReal = size.width = size.ascent = size.descent = 0;
+ dirty = sizeChangedSinceLastAllocation = true;
+ indexGBList = indexCBList = -1;
+
+ // Sometimes a float with widget = NULL is created as a key; this
+ // is not interesting for RTFL.
+ if (widget) {
+ DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
+ sizeChangedSinceLastAllocation);
+ }
+}
+
+void OOFFloatsMgr::Float::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ sb->appendPointer (getWidget ());
+
+ if (getWidget ()) {
+ sb->append (" (");
+ sb->append (getWidget()->getClassName ());
+ sb->append (")");
+ }
+
+ sb->append (", indexGBList = ");
+ sb->appendInt (indexGBList);
+ sb->append (", indexCBList = ");
+ sb->appendInt (indexCBList);
+ sb->append (", sideSpanningIndex = ");
+ sb->appendInt (sideSpanningIndex);
+ sb->append (", generatingBlock = ");
+ sb->appendPointer (generatingBlock);
+ sb->append (", yReq = ");
+ sb->appendInt (yReq);
+ sb->append (", yReal = ");
+ sb->appendInt (yReal);
+ sb->append (", size = { ");
+ sb->appendInt (size.width);
+ sb->append (" * ");
+ sb->appendInt (size.ascent);
+ sb->append (" + ");
+ sb->appendInt (size.descent);
+ sb->append (" }, dirty = ");
+ sb->appendBool (dirty);
+ sb->append (", sizeChangedSinceLastAllocation = ");
+ sb->appendBool (sizeChangedSinceLastAllocation);
+ sb->append (" }");
+}
+
+bool OOFFloatsMgr::Float::covers (OOFAwareWidget *textblock, int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%p, %d, %d [vloat: %p]",
+ textblock, y, h, getWidget ());
+
+ bool b;
+
+ if (textblock == generatingBlock) {
+ int reqyGB = y;
+ int flyGB = yReal;
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ int flh = size.ascent + size.descent;
+ b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "for generator: reqyGB = %d, flyGB = %d, "
+ "flh = %d + %d = %d => %s",
+ reqyGB, flyGB, size.ascent, size.descent, flh,
+ b ? "true" : "false");
+ } else {
+ // (If the textblock were not allocated, the GB list would have
+ // been choosen instead of the CB list, and so this else-branch
+ // would not have been not executed.)
+ assert (getOOFFloatsMgr()->wasAllocated (textblock));
+
+ if (!getWidget()->wasAllocated ()) {
+ DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (not allocated) => false");
+ b = false;
+ } else {
+ Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock),
+ *fla = getWidget()->getAllocation ();
+ int reqyCanv = tba->y + y;
+ int flyCanv = fla->y;
+ int flh = fla->ascent + fla->descent;
+ b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (allocated): reqyCanv = %d + %d = %d, "
+ "flyCanv = %d, flh = %d + %d = %d => %s",
+ tba->y, y, reqyCanv, flyCanv,
+ fla->ascent, fla->descent, flh, b ? "true" : "false");
+ }
+ }
+
+ DBG_OBJ_LEAVE_O (getOOFFloatsMgr ());
+
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
+ int r;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm,
+ "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
+ fl1->getIndex (type), fl2->getIndex (type), refTB);
+
+ if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
+ r = fl1->yReal - fl2->yReal;
+ } else {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
+ fl1->generatingBlock, fl2->generatingBlock);
+
+ // (i) Floats may not yet been allocated. Non-allocated floats
+ // do not have an effect yet, they are considered "at the end"
+ // of the list.
+
+ // (ii) Float::widget is NULL for the key used for binary
+ // search. In this case, Float::yReal is used instead (which is
+ // set in SortedFloatsVector::find, too). The generator is the
+ // textblock, and should be allocated. (If not, the GB list
+ // would have been choosen instead of the CB list, and so this
+ // else-branch would not have been not executed.)
+
+ bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
+ bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
+ fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
+ a2 ? "yes" : "no");
+
+ if (a1 && a2) {
+ int fly1, fly2;
+
+ if (fl1->getWidget()) {
+ fly1 = fl1->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
+ } else {
+ assert (oofm->wasAllocated (fl1->generatingBlock));
+ fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
+ oofm->getAllocation(fl1->generatingBlock)->y,
+ fl1->yReal, fly1);
+ }
+
+ if (fl2->getWidget()) {
+ fly2 = fl2->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
+ } else {
+ assert (oofm->wasAllocated (fl2->generatingBlock));
+ fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
+ oofm->getAllocation(fl2->generatingBlock)->y,
+ fl2->yReal, fly2);
+ }
+
+ r = fly1 - fly2;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
+ } else if (a1 && !a2)
+ r = -1;
+ else if (!a1 && a2)
+ r = +1;
+ else // if (!a1 && !a2)
+ return 0;
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
+ Object *o2)
+{
+ return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
+}
+
+int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
+{
+ Float *f1 = (Float*)o1, *f2 = (Float*)o2;
+ int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
+ "#%d -> %p/%d, #%d -> %p/#%d",
+ f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
+ f2->getIndex (type), f2->generatingBlock,
+ f2->externalIndex);
+
+ if (f1->generatingBlock == f2->generatingBlock) {
+ r = f1->externalIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(a) generating blocks equal => %d - %d = %d",
+ f1->externalIndex, f2->externalIndex, r);
+ } else {
+ TBInfo *t1 = oofm->getOOFAwareWidget (f1->generatingBlock),
+ *t2 = oofm->getOOFAwareWidget (f2->generatingBlock);
+ bool rdef = false;
+
+ for (TBInfo *t = t1; t != NULL; t = t->parent)
+ if (t->parent == t2) {
+ rdef = true;
+ r = t->parentExtIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(b) %p is an achestor of %p; direct child is "
+ "%p (%d) => %d - %d = %d\n",
+ t2->getOOFAwareWidget (), t1->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ t->parentExtIndex, f2->externalIndex, r);
+ }
+
+ for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
+ if (t->parent == t1) {
+ r = f1->externalIndex - t->parentExtIndex;
+ rdef = true;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(c) %p is an achestor of %p; direct child is %p "
+ "(%d) => %d - %d = %d\n",
+ t1->getOOFAwareWidget (), t2->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ f1->externalIndex, t->parentExtIndex, r);
+ }
+
+ if (!rdef) {
+ r = t1->index - t2->index;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
+ t1->index, t2->index, r);
+ }
+ }
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
+ lastGB, lastExtIndex);
+
+ Float key (oofm, NULL, lastGB, lastExtIndex);
+ key.setIndex (type, -1); // for debugging
+ Float::CompareGBAndExtIndex comparator (oofm, type);
+ int i = bsearch (&key, false, &comparator);
+
+ // At position i is the next larger element, so element i should
+ // not included, but i - 1 returned; except if the exact element is
+ // found: then include it and so return i.
+ int r;
+ if (i == size())
+ r = i - 1;
+ else {
+ Float *f = get (i);
+ if (comparator.compare (f, &key) == 0)
+ r = i;
+ else
+ r = i - 1;
+ }
+
+ //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
+ // "in %s list %p on the %s side\n",
+ // oofm->container, lastGB, lastExtIndex, i, r, size (),
+ // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
+
+ //for (int i = 0; i < size (); i++) {
+ // Float *f = get(i);
+ // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock);
+ // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
+ // t->index, t->parent ? t->parent->textblock : NULL,
+ // get(i)->externalIndex);
+ //}
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::find (OOFAwareWidget *textblock, int y,
+ int start, int end)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d",
+ textblock, y, start, end);
+
+ Float key (oofm, NULL, NULL, 0);
+ key.generatingBlock = textblock;
+ key.yReal = y;
+ key.setIndex (type, -1); // for debugging
+ Float::ComparePosition comparator (oofm, textblock, type);
+ int result = bsearch (&key, false, start, end, &comparator);
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFirst (OOFAwareWidget *textblock,
+ int y, int h,
+ OOFAwareWidget *lastGB,
+ int lastExtIndex,
+ int *lastReturn)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d",
+ textblock, y, h, lastGB, lastExtIndex);
+
+ DBG_IF_RTFL {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ for (int i = 0; i < size(); i++) {
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), "
+ "%s, %s, ext = %d, GB = %p); widget at (%d, %d)",
+ i, get(i)->getWidget (), get(i)->getIndex (type),
+ get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal,
+ get(i)->size.width, get(i)->size.ascent,
+ get(i)->size.descent,
+ get(i)->dirty ? "dirty" : "clean",
+ get(i)->sizeChangedSinceLastAllocation ? "scsla"
+ : "sNcsla",
+ get(i)->externalIndex, get(i)->generatingBlock,
+ get(i)->getWidget()->getAllocation()->x,
+ get(i)->getWidget()->getAllocation()->y);
+ }
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ int last = findFloatIndex (lastGB, lastExtIndex);
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last);
+ assert (last < size());
+
+ // If the caller wants to reuse this value:
+ if (lastReturn)
+ *lastReturn = last;
+
+ int i = find (textblock, y, 0, last), result;
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i);
+
+ // Note: The smallest value of "i" is 0, which means that "y" is before or
+ // equal to the first float. The largest value is "last + 1", which means
+ // that "y" is after the last float. In both cases, the first or last,
+ // respectively, float is a candidate. Generally, both floats, before and
+ // at the search position, are candidates.
+
+ if (i > 0 && get(i - 1)->covers (textblock, y, h))
+ result = i - 1;
+ else if (i <= last && get(i)->covers (textblock, y, h))
+ result = i;
+ else
+ result = -1;
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result);
+ DBG_OBJ_LEAVE_O (oofm);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex
+ (int sideSpanningIndex)
+{
+ OOFFloatsMgr::Float::CompareSideSpanningIndex comparator;
+ Float key (NULL, NULL, NULL, 0);
+ key.sideSpanningIndex = sideSpanningIndex;
+ return bsearch (&key, false, &comparator) - 1;
+}
+
+void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat)
+{
+ lout::container::typed::Vector<Float>::put (vloat);
+ vloat->setIndex (type, size() - 1);
+}
+
+OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex) :
+ WidgetInfo (oofm, textblock)
+{
+ this->parent = parent;
+ this->parentExtIndex = parentExtIndex;
+
+ leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB);
+ rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB);
+
+ wasAllocated = getWidget()->wasAllocated ();
+ allocation = *(getWidget()->getAllocation ());
+ clearPosition = 0;
+}
+
+OOFFloatsMgr::TBInfo::~TBInfo ()
+{
+ delete leftFloatsGB;
+ delete rightFloatsGB;
+}
+
+void OOFFloatsMgr::TBInfo::updateAllocation ()
+{
+ DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
+
+ update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
+ getNewHeight ());
+
+ DBG_OBJ_LEAVE_O (getWidget ());
+}
+
+OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container)
+{
+ DBG_OBJ_CREATE ("dw::OOFFloatsMgr");
+
+ this->container = (OOFAwareWidget*)container;
+
+ leftFloatsCB = new SortedFloatsVector (this, LEFT, CB);
+ rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB);
+
+ DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
+ DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
+
+ leftFloatsAll = new Vector<Float> (1, true);
+ rightFloatsAll = new Vector<Float> (1, true);
+
+ DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+
+ floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
+
+ tbInfos = new Vector<TBInfo> (1, false);
+ tbInfosByOOFAwareWidget =
+ new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true);
+
+ leftFloatsMark = rightFloatsMark = 0;
+ lastLeftTBIndex = lastRightTBIndex = 0;
+
+ containerWasAllocated = container->wasAllocated ();
+ containerAllocation = *(container->getAllocation());
+
+ addWidgetInFlow (this->container, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ //printf ("OOFFloatsMgr::~OOFFloatsMgr\n");
+
+ delete leftFloatsCB;
+ delete rightFloatsCB;
+
+ // Order is important: tbInfosByOOFAwareWidget is owner of the instances
+ // of TBInfo.tbInfosByOOFAwareWidget
+ delete tbInfos;
+ delete tbInfosByOOFAwareWidget;
+
+ delete floatsByWidget;
+
+ // Order is important, since the instances of Float are owned by
+ // leftFloatsAll and rightFloatsAll, so these should be deleted
+ // last.
+ delete leftFloatsAll;
+ delete rightFloatsAll;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ // Some callers are not registered, especially tables. (Where the
+ // floats manager is actually empty?)
+ TBInfo *oofAWInfo = getOOFAwareWidgetWhenRegistered (caller);
+ if (oofAWInfo) {
+ oofAWInfo->allocation = *allocation;
+ oofAWInfo->wasAllocated = true;
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *first* OOFM method
+ // called is sizeAllocateStart, with the containing block as an
+ // argument. So this is the correct point to initialize size
+ // allocation.
+
+ containerWasAllocated = true;
+ containerAllocation = *allocation;
+
+ // Move floats from GB lists to the one CB list.
+ moveFromGBToCB (LEFT);
+ moveFromGBToCB (RIGHT);
+
+ // These attributes are used to keep track which floats have
+ // been allocated (referring to leftFloatsCB and rightFloatsCB).
+ lastAllocatedLeftFloat = lastAllocatedRightFloat = -1;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (isOOFAwareWidgetRegistered (caller)) {
+ if (caller != container) {
+ // Allocate all floats "before" this textblock.
+ sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
+ sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
+ }
+
+ // The checks below do not cover "clear position" in all cases,
+ // so this is done here separately. This position is stored in
+ // TBInfo and calculated at this points; changes will be noticed
+ // to the textblock.
+ TBInfo *tbInfo = getOOFAwareWidget (caller);
+ int newClearPosition = calcClearPosition (caller);
+ if (newClearPosition != tbInfo->clearPosition) {
+ tbInfo->clearPosition = newClearPosition;
+ caller->clearPositionChanged ();
+ }
+
+ if (caller == container) {
+ // In the size allocation process, the *last* OOFM method called
+ // is sizeAllocateEnd, with the containing block as an
+ // argument. So this is the correct point to finish size
+ // allocation.
+
+ // Allocate all remaining floats.
+ sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1);
+ sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1);
+
+ // Check changes of both textblocks and floats allocation. (All
+ // is checked by hasRelationChanged (...).)
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ int minFloatPos;
+ Widget *minFloat;
+ if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
+ tb->borderChanged (minFloatPos, minFloat);
+ }
+
+ checkAllocatedFloatCollisions (LEFT);
+ checkAllocatedFloatCollisions (RIGHT);
+
+ // Store some information for later use.
+ for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> >
+ it = tbInfosByOOFAwareWidget->iterator ();
+ it.hasNext (); ) {
+ TypedPointer <OOFAwareWidget> *key = it.getNext ();
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key);
+ OOFAwareWidget *tb = key->getTypedValue();
+
+ tbInfo->updateAllocation ();
+ tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
+ }
+
+ // There are cases where some allocated floats exceed the CB size.
+ bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT);
+
+ // Similar for extremes.
+ bool extremesChanged =
+ haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT);
+
+ for (int i = 0; i < leftFloatsCB->size(); i++)
+ leftFloatsCB->get(i)->updateAllocation ();
+
+ for (int i = 0; i < rightFloatsCB->size(); i++)
+ rightFloatsCB->get(i)->updateAllocation ();
+
+ if (sizeChanged || extremesChanged)
+ container->oofSizeChanged (extremesChanged);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < leftFloatsAll->size (); i++)
+ leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloatsAll->size (); i++)
+ rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
+ Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, ...", tbInfo->getWidget ());
+
+ int leftMinPos, rightMinPos;
+ Widget *leftMinFloat, *rightMinFloat;
+ bool c1 =
+ hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
+ bool c2 =
+ hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
+ if (c1 || c2) {
+ if (!c1) {
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ } else if (!c2) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else {
+ if (leftMinPos < rightMinPos) {
+ *minFloatPos = leftMinPos;
+ *minFloat = leftMinFloat;
+ } else{
+ *minFloatPos = rightMinPos;
+ *minFloat = rightMinFloat;
+ }
+ }
+ }
+
+ if (c1 || c2)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "has changed: minFloatPos = %d, minFloat = %p",
+ *minFloatPos, *minFloat);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+ return c1 || c2;
+}
+
+bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
+ int *minFloatPos, Widget **minFloat)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>widget:</i> %p, %s, ...",
+ tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size(); i++) {
+ // TODO binary search?
+ Float *vloat = list->get(i);
+ int floatPos;
+
+ if (tbInfo->getOOFAwareWidget () == vloat->generatingBlock)
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "not checking (generating!) textblock %p against float "
+ "%p", tbInfo->getWidget (), vloat->getWidget ());
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+
+ int newFlx =
+ calcFloatX (vloat, side,
+ gba->x - containerAllocation.x, 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, true)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides, new yReal = %d (old: %d)",
+ yRealNewSame, vloat->yReal);
+ if (vloat->yReal != yRealNewSame) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewSame);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
+ }
+ }
+
+ if (oppList->size () > 0) {
+ // Other side. Iterate to next float on the other side,
+ // before this float.
+ while (oppIndex + 1 < oppList->size () &&
+ oppList->get(oppIndex + 1)->sideSpanningIndex
+ < vloat->sideSpanningIndex)
+ oppIndex++;
+
+ if (oppList->get(oppIndex)->sideSpanningIndex
+ < vloat->sideSpanningIndex) {
+ int oppIndexTmp = oppIndex, yRealNewOpp;
+
+ // Aproach is similar to tellPosition(); see comments
+ // there. Again, loop as long as the vertical dimensions test
+ // is positive (and, of course, there are floats), ...
+ for (bool foundColl = false;
+ !foundColl && oppIndexTmp >= 0 &&
+ collidesV (vloat, oppList->get (oppIndexTmp), CB,
+ &yRealNewOpp, true);
+ oppIndexTmp--) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "opposite side (after collision (v) test): "
+ "checking %p (#%d/%d, GB: %p) against "
+ "%p (#%d/%d, GB: %p)",
+ vloat->getWidget (), index,
+ vloat->sideSpanningIndex,
+ vloat->generatingBlock,
+ oppList->get(oppIndexTmp)->getWidget (),
+ oppList->get(oppIndexTmp)->getIndex (CB),
+ oppList->get(oppIndexTmp)->sideSpanningIndex,
+ oppList->get(oppIndexTmp)->generatingBlock);
+
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides (h), new yReal = %d (old: %d)",
+ yRealNewOpp, vloat->yReal);
+ foundColl = true;
+ if (vloat->yReal != yRealNewOpp) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewOpp);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
+ }
+ }
+ }
+
+ if (needsChange)
+ vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
+ vloat->getWidget ());
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::doFloatsExceedCB (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This method is called to determine whether the *requisition* of
+ // the CB must be recalculated. So, we check the float allocations
+ // against the *requisition* of the CB, which may (e. g. within
+ // tables) differ from the new allocation. (Generally, a widget may
+ // allocated at a different size.)
+ core::Requisition cbReq;
+ container->sizeRequest (&cbReq);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool exceeds = false;
+
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < list->size () && !exceeds; i++) {
+ Float *vloat = list->get (i);
+ if (vloat->getWidget()->wasAllocated ()) {
+ Allocation *fla = vloat->getWidget()->getAllocation ();
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "Does FlA = (%d, %d, %d * %d) exceed CB req+alloc = "
+ "(%d, %d, %d * %d)?",
+ fla->x, fla->y, fla->width, fla->ascent + fla->descent,
+ containerAllocation.x, containerAllocation.y,
+ cbReq.width, cbReq.ascent + cbReq.descent);
+ if (fla->x + fla->width > containerAllocation.x + cbReq.width ||
+ fla->y + fla->ascent + fla->descent
+ > containerAllocation.y + cbReq.ascent + cbReq.descent) {
+ exceeds = true;
+ DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 2, "No.");
+ }
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return exceeds;
+}
+
+bool OOFFloatsMgr::haveExtremesChanged (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This is quite different from doFloatsExceedCB, since there is no
+ // counterpart to getExtremes, as sizeAllocate is a counterpart to
+ // sizeRequest. So we have to determine whether the allocation has
+ // changed the extremes, which is done by examining the part of the
+ // allocation which is part of the extremes calculation (see
+ // getFloatsExtremes). Changes of the extremes are handled by the
+ // normal queueResize mechanism.
+
+ // (This may refer to the old implementation of doFloatsExceedCB,
+ // which checked the container *allocation*, not the *requisition*.
+ //
+ // TODO: (i) Correct the comment. (ii) Is this implementation still
+ // correct, considering the reasoning behind the change of
+ // doFloatsExceedCB?
+ //
+ // See also OOFPositionedMgr::haveExtremesChanged.)
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size () && !changed; i++) {
+ Float *vloat = list->get (i);
+ // When the GB is the CB, an allocation change does not play a
+ // role here.
+ if (vloat->generatingBlock != container) {
+ if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
+ changed = true;
+ else {
+ // This method is called within sizeAllocateEnd, where
+ // containinBlock->getAllocation() (old value) and
+ // containinBlockAllocation (new value) are different.
+
+ Allocation *oldCBA = container->getAllocation ();
+ Allocation *newCBA = &containerAllocation;
+
+ // Compare also to getFloatsExtremes. The box difference
+ // of the GB (from style) has not changed in this context,
+ // so it is ignored.
+
+ int oldDiffLeft = vloat->getOldXCB ();
+ int newDiffLeft = vloat->getNewXCB ();
+ int oldDiffRight =
+ oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
+ int newDiffRight =
+ newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
+
+ if (// regarding minimum
+ (side == LEFT && oldDiffLeft != newDiffLeft) ||
+ (side == RIGHT && oldDiffRight != newDiffRight) ||
+ // regarding maximum
+ oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
+ changed = true;
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return changed;
+}
+
+void OOFFloatsMgr::moveFromGBToCB (Side side)
+{
+ DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
+
+ for (int mark = 0; mark <= *floatsMark; mark++)
+ for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
+ it.hasNext (); ) {
+ TBInfo *tbInfo = it.getNext ();
+ SortedFloatsVector *src =
+ side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ for (int i = 0; i < src->size (); i++) {
+ Float *vloat = src->get (i);
+ // "vloat->indexCBList == -1": prevent copying the vloat twice.
+ if (vloat->indexCBList == -1 && vloat->mark == mark) {
+ dest->put (vloat);
+ DBG_OBJ_MSGF ("oofm.resize", 1,
+ "moving float %p (mark %d) to CB list\n",
+ vloat->getWidget (), vloat->mark);
+ DBG_OBJ_SET_NUM (side == LEFT ?
+ "leftFloatsCB.size" : "rightFloatsCB.size",
+ dest->size());
+ DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
+ "leftFloatsCB" : "rightFloatsCB",
+ dest->size() - 1, "widget",
+ vloat->getWidget ());
+
+ }
+ }
+ }
+
+ *floatsMark = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
+{
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ int *lastAllocatedFloat =
+ side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
+ "%s, [%d ->] %d [size = %d]",
+ side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
+ newLastAllocatedFloat, list->size ());
+
+ Allocation *cba = &containerAllocation;
+
+ for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
+ Float *vloat = list->get(i);
+ ensureFloatSize (vloat);
+
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ 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,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *index)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d]",
+ area->x, area->y, area->width, area->height, *index);
+
+ drawFloats (leftFloatsCB, view, area, iteratorStack, interruptedWidget,
+ index, 0);
+ if (*interruptedWidget == NULL)
+ drawFloats (rightFloatsCB, view, area, iteratorStack, interruptedWidget,
+ index, leftFloatsCB->size ());
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view,
+ Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *index,
+ int startIndex)
+{
+ // 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.
+
+ OOFAwareWidget::OOFStackingIterator *osi =
+ (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (*interruptedWidget == NULL && *index - startIndex < list->size()) {
+ Float *vloat = list->get(*index - startIndex);
+ Widget *childWidget = vloat->getWidget ();
+
+ Rectangle childArea;
+ if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->intersects (area, &childArea))
+ childWidget->drawTotal (view, &childArea, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)++;
+ }
+}
+
+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,
+ core::StackingIteratorStack
+ *iteratorStack,
+ core::Widget **interruptedWidget,
+ int *index)
+{
+ Widget *widgetAtPoint = NULL;
+
+ widgetAtPoint =
+ getFloatWidgetAtPoint (rightFloatsCB, x, y, iteratorStack,
+ interruptedWidget, index,
+ leftFloatsCB->size ());
+ if (widgetAtPoint == NULL && *interruptedWidget == NULL)
+ widgetAtPoint =
+ getFloatWidgetAtPoint (leftFloatsCB, x, y, iteratorStack,
+ interruptedWidget, index, 0);
+ return widgetAtPoint;
+}
+
+Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x,
+ int y,
+ StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int *index, int startIndex)
+{
+ // Could use binary search to be faster (similar to drawing).
+ Widget *widgetAtPoint = NULL;
+ OOFAwareWidget::OOFStackingIterator *osi =
+ (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (widgetAtPoint == NULL && *interruptedWidget == NULL &&
+ *index - startIndex >= 0 &&
+ // In case the list is empty:
+ *index - startIndex < list->size()) {
+ Widget *childWidget = list->get(*index - startIndex)->getWidget ();
+ if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget))
+ widgetAtPoint =
+ childWidget->getWidgetAtPointTotal (x, y, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)--;
+ }
+
+ return widgetAtPoint;
+}
+
+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, false)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ }
+
+ // Test collisions (on the opposite side). There are cases when
+ // more than one float has to be tested. Consider the following
+ // HTML snippet ("id" attribute only used for simple reference
+ // below, as #f1, #f2, and #f3):
+ //
+ // <div style="float:left" id="f1">
+ // Left left left left left left left left left left.
+ // </div>
+ // <div style="float:left" id="f2">Also left.</div>
+ // <div style="float:right" id="f3">Right.</div>
+ //
+ // When displayed with a suitable window width (only slightly wider
+ // than the text within #f1), this should look like this:
+ //
+ // ---------------------------------------------------------
+ // | Left left left left left left left left left left. |
+ // | Also left. Right. |
+ // ---------------------------------------------------------
+ //
+ // Consider float #f3: a collision test with #f2, considering
+ // vertical dimensions, is positive, but not the test with
+ // horizontal dimensions (because #f2 and #f3 are too
+ // narrow). However, a collision has to be tested with #f1;
+ // otherwise #f3 and #f1 would overlap.
+
+ int oppFloatIndex =
+ listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
+ // Generally, the rules are simple: loop as long as the vertical
+ // dimensions test is positive (and, of course, there are floats),
+ // ...
+ for (bool foundColl = false;
+ !foundColl && oppFloatIndex >= 0 &&
+ collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
+ &yRealNew, false);
+ oppFloatIndex--) {
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ foundColl = true;
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
+ vloat->yReq, vloat->yReal);
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, SFVType type,
+ int *yReal, bool useAllocation)
+{
+ // Only checks vertical (possible) collisions, and only refers to
+ // vloat->yReal; never to vloat->allocation->y, even when the GBs are
+ // different. Used only in tellPosition.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
+ vloat->getIndex (type), vloat->getWidget (),
+ other->getIndex (type), other->getWidget ());
+
+ bool result;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
+
+ if (vloat->generatingBlock == other->generatingBlock) {
+ ensureFloatSize (other);
+ int otherBottomGB =
+ other->yReal + other->size.ascent + other->size.descent;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same generators: otherBottomGB = %d + (%d + %d) = %d",
+ other->yReal, other->size.ascent, other->size.descent,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ } else {
+ // If the other float is not allocated, there is no collision. The
+ // allocation of this float (vloat) is not used at all.
+ if (!other->getWidget()->wasAllocated ())
+ result = false;
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ Allocation *gba = getAllocation (vloat->generatingBlock),
+ *flaOther = other->getWidget()->getAllocation ();
+
+ // We distinguish two cases (by different values of useAllocation):
+ // (i) within tellPosition, GB allocation + yReal is used for the
+ // y position of the other float, while (ii) in checkAllocatedFloat-
+ // Collisions, the float allocation is used. The latter is necessary
+ // by the definition of this method, the former increases performance,
+ // as compared to using the float allocation, in some cases, as in
+ // this:
+ //
+ // When '<div><div style="float:left">[Some text]</div></div>' is
+ // repeated n times, the resize idle function (Layout::resizeIdle)
+ // would be repeated roughly n times, when also in case (i) the float
+ // allocation is used, since for the collision test of float n with
+ // float n - 1, the allocation of float n - 1 does not yet reflect the
+ // collision test between n - 1 and n - 2, but yReal does for n - 1.
+ //
+ // On the other hand, the GB allocations will most likely more stable
+ // than the float allocations.
+ //
+ // Cases where this is incorrect will hopefully be rare, and, in any
+ // case, corrected in sizeAllocateEnd, either because hasRelation-
+ // Changed returns true, or in checkAllocatedFloatCollisions.
+
+ int otherFloatY = useAllocation ? flaOther->y :
+ getAllocation(other->generatingBlock)->y + other->yReal;
+ int otherBottomGB =
+ otherFloatY + flaOther->ascent + flaOther->descent - gba->y;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "different generators: "
+ "otherBottomGB = %d + (%d + %d) - %d = %d",
+ otherFloatY, flaOther->ascent, flaOther->descent, gba->y,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ }
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
+
+ DBG_OBJ_LEAVE ();
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other, SFVType type)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generatingBlock == other->generatingBlock)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generatingBlock->boxDiffWidth()
+ > vloat->generatingBlock->getLineBreakWidth();
+ else {
+ // Again, if the other float is not allocated, there is no
+ // collision. Compare to collidesV. (But vloat->size is used
+ // here.)
+ if (!other->getWidget()->wasAllocated ())
+ collidesH = false;
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ int vloatX =
+ calcFloatX (vloat,
+ vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
+ LEFT : RIGHT,
+ gba->x, 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);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p has generator %p (container is %p)",
+ vloat->getWidget (), vloat->generatingBlock, container);
+
+ // BTW: as opposed to positioned elements, those floats which
+ // are not generated by the container, or not yet allocated, and
+ // so not considered here, need not be considered later; since
+ // the relevant cases will trigger a call to borderChanged after
+ // a positive hasRelationChanged test.
+
+ 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 ();
+}
+
+bool OOFFloatsMgr::containerMustAdjustExtraSpace ()
+{
+ return false;
+}
+
+void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ cbExtr->minWidth, cbExtr->maxWidth);
+
+ int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
+ getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
+ getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
+
+ *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
+ *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
+ oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
+ oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
+ int *minWidth, int *maxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
+ cbExtr->minWidth, cbExtr->maxWidth,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ *minWidth = *maxWidth = 0;
+
+ SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ 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..86bf62da
--- /dev/null
+++ b/dw/ooffloatsmgr.hh
@@ -0,0 +1,409 @@
+#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::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget, int *index,
+ int startIndex);
+ core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ core::Widget **interruptedWidget,
+ int *index, int startIndex);
+
+ bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal,
+ bool useAllocation);
+ bool collidesH (Float *vloat, Float *other, SFVType type);
+
+ void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
+ SortedFloatsVector **listOpp, Side *side);
+
+ void getFloatsSize (core::Requisition *cbReq, Side side, int *width,
+ int *height);
+ void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth,
+ int *maxWidth);
+ 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,
+ core::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget, int *index);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget,
+ int *index);
+
+ 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);
+ bool containerMustAdjustExtraSpace ();
+ void getExtremes (core::Extremes *cbExtr,
+ int *oofMinWidth, int *oofMaxWidth);
+
+ int getLeftBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightBorder (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool hasFloatLeft (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ bool hasFloatRight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ int getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+ int getRightFloatHeight (OOFAwareWidget *textblock, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+ bool mayAffectBordersAtAll ();
+
+ int getClearPosition (OOFAwareWidget *textblock);
+
+ bool dealingWithSizeOfChild (core::Widget *child);
+ int getAvailWidthOfChild (core::Widget *child, bool forceValue);
+ int getAvailHeightOfChild (core::Widget *child, bool forceValue);
+
+ int getNumWidgets ();
+ core::Widget *getWidget (int i);
+};
+
+} // namespace oof
+
+} // namespace dw
+
+#endif // __DW_OOFFLOATSMGR_HH__
diff --git a/dw/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..2466086b
--- /dev/null
+++ b/dw/oofpositionedmgr.cc
@@ -0,0 +1,784 @@
+/*
+ * 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);
+
+ containerAllocationState =
+ container->wasAllocated () ? WAS_ALLOCATED : NOT_ALLOCATED;
+ containerAllocation = *(container->getAllocation());
+
+ DBG_OBJ_SET_NUM ("children.size", children->size());
+}
+
+OOFPositionedMgr::~OOFPositionedMgr ()
+{
+ delete children;
+ delete childrenByWidget;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFPositionedMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ if (caller == container) {
+ if (containerAllocationState == NOT_ALLOCATED)
+ containerAllocationState = IN_ALLOCATION;
+ containerAllocation = *allocation;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == container) {
+ sizeAllocateChildren ();
+
+ bool sizeChanged = doChildrenExceedContainer ();
+ bool extremesChanged = haveExtremesChanged ();
+
+ // Consider children which were ignored in getSize (see comment
+ // there). These are children, for which the generator is
+ // different from the container, whose position is not fully
+ // defined, and for which the generator and container were not
+ // allocated. For the container, the latter is the case when
+ // containerAllocationState == IN_ALLOCATION; for the generator,
+ // this is valid in an analogue way, as long as sizeRequest is
+ // immediately followed by sizeAllocate (as in resizeIdle).
+
+ bool notAllChildrenConsideredBefore = false;
+ if (containerAllocationState == IN_ALLOCATION) {
+ for (int i = 0;
+ !notAllChildrenConsideredBefore && i < children->size(); i++) {
+ Child *child = children->get(i);
+ if (child->generator != container && !isPosComplete (child->widget))
+ notAllChildrenConsideredBefore = true;
+ }
+ }
+
+ if (sizeChanged || notAllChildrenConsideredBefore || extremesChanged)
+ container->oofSizeChanged (extremesChanged);
+
+ containerAllocationState = WAS_ALLOCATED;
+ }
+
+ 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 ()
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "haveExtremesChanged");
+
+ Extremes containerExtr;
+ container->getExtremes (&containerExtr);
+ bool changed = false;
+
+ DBG_OBJ_MSG_START ();
+
+ // Search for children which have not yet been considered by getExtremes().
+
+ for (int i = 0; i < children->size () && !changed; i++) {
+ Child *child = children->get (i);
+ if (child->generator != container && !isHPosComplete (child->widget) &&
+ containerAllocationState == IN_ALLOCATION)
+ changed = true;
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return changed;
+}
+
+
+void OOFPositionedMgr::draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *index)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d]",
+ area->x, area->y, area->width, area->height, *index);
+
+ OOFAwareWidget::OOFStackingIterator *osi =
+ (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (*interruptedWidget == NULL && *index < children->size()) {
+ Child *child = children->get(*index);
+
+ Rectangle childArea;
+ if (!osi->hasWidgetBeenDrawnAfterInterruption (child->widget) &&
+ !StackingContextMgr::handledByStackingContextMgr (child->widget) &&
+ child->widget->intersects (area, &childArea))
+ child->widget->drawTotal (view, &childArea, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)++;
+ }
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ 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,
+ StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int *index)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+ OOFAwareWidget::OOFStackingIterator *osi =
+ (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (widgetAtPoint == NULL && *interruptedWidget == NULL && *index >= 0) {
+ Widget *childWidget = children->get(*index)->widget;
+ if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget))
+ widgetAtPoint =
+ childWidget->getWidgetAtPointTotal (x, y, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)--;
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+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);
+
+ // The position of a child (which goes into the return value of
+ // this method) can only be determined when the following
+ // condition (if clause) is is fulfilled. Other children will be
+ // considered later in sizeAllocateEnd.
+ if (child->generator == container ||
+ isPosComplete (child->widget) ||
+ (containerAllocationState != NOT_ALLOCATED
+ && child->generator->wasAllocated ())) {
+ 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_MSGF ("resize.oofm", 0, "=> %d * %d", *oofWidth, *oofHeight);
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFPositionedMgr::containerMustAdjustExtraSpace ()
+{
+ return true;
+}
+
+void OOFPositionedMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ containerExtr->minWidth, containerExtr->maxWidth);
+
+ *oofMinWidth = *oofMaxWidth = 0;
+
+ for (int i = 0; i < children->size(); i++) {
+ Child *child = children->get(i);
+
+ // If clause: see getSize().
+ if (child->generator == container ||
+ isHPosComplete (child->widget) ||
+ (containerAllocationState != NOT_ALLOCATED
+ && child->generator->wasAllocated ())) {
+ int x, width;
+ Extremes childExtr;
+ child->widget->getExtremes (&childExtr);
+
+ // Here, we put the extremes of the container in relation to
+ // the extremes of the child, as sizes are put in relation
+ // for calculating the size. In one case, the allocation is
+ // used: when neither "left" nor "right" is set, and so the
+ // position told by the generator is used.
+ //
+ // If you look at the Textblock widget, you'll find that this
+ // is always boxOffsetX(), and the horizontal position of a
+ // textblock within its parent is also constant; so this is
+ // not a problem.
+ //
+ // (TODO What about a table cell within a table?)
+
+ calcHPosAndSizeChildOfChild (child, containerExtr->minWidth,
+ childExtr.minWidth, &x, &width);
+ *oofMinWidth = max (*oofMinWidth, x + width);
+
+ calcHPosAndSizeChildOfChild (child, containerExtr->maxWidth,
+ childExtr.maxWidth, &x, &width);
+ *oofMaxWidth = max (*oofMaxWidth, x + width);
+ }
+ }
+
+ *oofMinWidth += containerBoxDiffWidth ();
+ *oofMaxWidth += containerBoxDiffWidth ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> %d / %d", *oofMinWidth, *oofMaxWidth);
+ 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;
+}
+
+bool OOFPositionedMgr::isHPosComplete (Widget *child)
+{
+ return (style::isAbsLength (child->getStyle()->left) ||
+ style::isPerLength (child->getStyle()->left)) &&
+ (style::isAbsLength (child->getStyle()->right) ||
+ style::isPerLength (child->getStyle()->right));
+}
+
+bool OOFPositionedMgr::isVPosComplete (Widget *child)
+{
+ return (style::isAbsLength (child->getStyle()->top) ||
+ style::isPerLength (child->getStyle()->top)) &&
+ (style::isAbsLength (child->getStyle()->bottom) ||
+ style::isPerLength (child->getStyle()->bottom));
+}
+
+bool OOFPositionedMgr::isPosComplete (Widget *child)
+{
+ return isHPosComplete (child) && isVPosComplete (child);
+}
+
+void OOFPositionedMgr::calcPosAndSizeChildOfChild (Child *child, int refWidth,
+ int refHeight, int *xPtr,
+ int *yPtr, int *widthPtr,
+ int *ascentPtr,
+ int *descentPtr)
+{
+ // *xPtr and *yPtr refer to reference area; caller must adjust them.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "calcPosAndSizeChildOfChild",
+ "%p, %d, %d, ...", child, refWidth, refHeight);
+
+ // TODO (i) Consider {min|max}-{width|heigt}. (ii) Height is always
+ // apportioned to descent (ascent is preserved), which makes sense
+ // when the children are textblocks. (iii) Consider minimal width
+ // (getMinWidth)?
+
+ Requisition childRequisition;
+ child->widget->sizeRequest (&childRequisition);
+
+ calcHPosAndSizeChildOfChild (child, refWidth, childRequisition.width,
+ xPtr, widthPtr);
+ calcVPosAndSizeChildOfChild (child, refHeight, childRequisition.ascent,
+ childRequisition.descent, yPtr, ascentPtr,
+ descentPtr);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::calcHPosAndSizeChildOfChild (Child *child, int refWidth,
+ int origChildWidth,
+ int *xPtr, int *widthPtr)
+{
+ assert (refWidth != -1 || (xPtr == NULL && widthPtr == NULL));
+
+ int width;
+ bool widthDefined;
+ if (style::isAbsLength (child->widget->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "absolute width: %dpx",
+ style::absLengthVal (child->widget->getStyle()->width));
+ width = style::absLengthVal (child->widget->getStyle()->width)
+ + child->widget->boxDiffWidth ();
+ widthDefined = true;
+ } else if (style::isPerLength (child->widget->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->widget->getStyle()->width));
+ width = style::multiplyWithPerLength (refWidth,
+ child->widget->getStyle()->width)
+ + child->widget->boxDiffWidth ();
+ widthDefined = true;
+ } else {
+ DBG_OBJ_MSG ("resize.oofm", 1, "width not specified");
+ width = origChildWidth;
+ widthDefined = false;
+ }
+
+ int left = 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 (xPtr) {
+ if (left == -1 && right == -1) {
+ assert (child->generator == container ||
+ (containerAllocationState != NOT_ALLOCATED
+ && child->generator->wasAllocated ()));
+ *xPtr =
+ child->x + (child->generator == container ? 0 :
+ child->generator->getAllocation()->x
+ - (containerAllocation.x + containerBoxOffsetX ()));
+ } else if (left == -1 && right != -1)
+ *xPtr = refWidth - width - right;
+ else if (left != -1 && right == -1)
+ *xPtr = left;
+ else {
+ *xPtr = left;
+ if (!widthDefined) {
+ width = refWidth - (left + right);
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> width (corrected) = %d", width);
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> x = %d", *xPtr);
+ }
+
+ if (widthPtr)
+ *widthPtr = width;
+}
+
+void OOFPositionedMgr::calcVPosAndSizeChildOfChild (Child *child, int refHeight,
+ int origChildAscent,
+ int origChildDescent,
+ int *yPtr, int *ascentPtr,
+ int *descentPtr)
+{
+ assert (refHeight != -1 ||
+ (yPtr == NULL && ascentPtr == NULL && descentPtr == NULL));
+
+ int ascent = origChildAscent, descent = origChildDescent;
+ bool heightDefined;
+
+ if (style::isAbsLength (child->widget->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "absolute height: %dpx",
+ style::absLengthVal (child->widget->getStyle()->height));
+ int height = style::absLengthVal (child->widget->getStyle()->height)
+ + child->widget->boxDiffHeight ();
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ heightDefined = true;
+ } else if (style::isPerLength (child->widget->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->widget->getStyle()->height));
+ int height =
+ style::multiplyWithPerLength (refHeight,
+ child->widget->getStyle()->height)
+ + child->widget->boxDiffHeight ();
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ heightDefined = true;
+ } else {
+ DBG_OBJ_MSG ("resize.oofm", 1, "height not specified");
+ heightDefined = false;
+ }
+
+ int top = 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 (yPtr) {
+ if (top == -1 && bottom == -1) {
+ assert (child->generator == container ||
+ (containerAllocationState != NOT_ALLOCATED
+ && child->generator->wasAllocated ()));
+ *yPtr =
+ child->y + (child->generator == container ? 0 :
+ child->generator->getAllocation()->y
+ - (containerAllocation.y + containerBoxOffsetY ()));
+ } else if (top == -1 && bottom != -1)
+ *yPtr = refHeight - (ascent + descent) - bottom;
+ else if (top != -1 && bottom == -1)
+ *yPtr = top;
+ else {
+ *yPtr = top;
+ if (!heightDefined) {
+ int height = refHeight - (top + bottom);
+ splitHeightPreserveAscent (height, &ascent, &descent);
+ DBG_OBJ_MSGF ("resize.oofm", 0,
+ "=> ascent + descent (corrected) = %d + %d",
+ ascent, descent);
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 0, "=> y = %d", *yPtr);
+ }
+
+ if (ascentPtr)
+ *ascentPtr = ascent;
+ if (descentPtr)
+ *descentPtr = descent;
+}
+
+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..04fa1629
--- /dev/null
+++ b/dw/oofpositionedmgr.hh
@@ -0,0 +1,141 @@
+#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;
+ OOFAwareWidget *generator;
+ int x, y;
+
+ inline Child (core::Widget *widget, OOFAwareWidget *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;
+ enum { NOT_ALLOCATED, IN_ALLOCATION, WAS_ALLOCATED }
+ containerAllocationState;
+ 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);
+
+ bool isHPosComplete (core::Widget *child);
+ bool isVPosComplete (core::Widget *child);
+ bool isPosComplete (core::Widget *child);
+
+ void calcPosAndSizeChildOfChild (Child *child, int refWidth, int refHeight,
+ int *xPtr, int *yPtr, int *widthPtr,
+ int *ascentPtr, int *descentPtr);
+ void calcHPosAndSizeChildOfChild (Child *child, int refWidth,
+ int origChildWidth, int *xPtr,
+ int *widthPtr);
+ void calcVPosAndSizeChildOfChild (Child *child, int refHeight,
+ int origChildAscent, int origChildDescent,
+ int *yPtr, int *ascentPtr,
+ int *descentPtr);
+
+public:
+ OOFPositionedMgr (OOFAwareWidget *container);
+ ~OOFPositionedMgr ();
+
+ void sizeAllocateStart (OOFAwareWidget *caller,
+ core::Allocation *allocation);
+ void sizeAllocateEnd (OOFAwareWidget *caller);
+ void containerSizeChangedForChildren ();
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget, int *index);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget,
+ int *index);
+
+ 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);
+ bool containerMustAdjustExtraSpace ();
+ 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 6fc1c325..405c5e62 100644
--- a/dw/outofflowmgr.cc
+++ b/dw/outofflowmgr.cc
@@ -19,2274 +19,22 @@
#include "outofflowmgr.hh"
-#include "textblock.hh"
+#include "oofawarewidget.hh"
#include "../lout/debug.hh"
-using namespace lout::object;
-using namespace lout::container::typed;
-using namespace lout::misc;
-using namespace dw::core;
-using namespace dw::core::style;
namespace dw {
-OutOfFlowMgr::WidgetInfo::WidgetInfo (OutOfFlowMgr *oofm, Widget *widget)
-{
- this->oofm = oofm;
- this->widget = widget;
- wasAllocated = false;
- xCB = yCB = width = height = -1;
-}
-
-void OutOfFlowMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
- int width, int height)
-{
- DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
- wasAllocated ? "true" : "false", xCB, yCB, width, height);
-
- this->wasAllocated = wasAllocated;
- this->xCB = xCB;
- this->yCB = yCB;
- this->width = width;
- this->height = height;
-
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
-
- DBG_OBJ_LEAVE_O (widget);
-}
-
-// ----------------------------------------------------------------------
-
-OutOfFlowMgr::Float::Float (OutOfFlowMgr *oofm, Widget *widget,
- Textblock *generatingBlock, int externalIndex) :
- WidgetInfo (oofm, widget)
-{
- this->generatingBlock = generatingBlock;
- this->externalIndex = externalIndex;
-
- yReq = yReal = size.width = size.ascent = size.descent = 0;
- dirty = sizeChangedSinceLastAllocation = true;
- indexGBList = indexCBList = -1;
-
- // Sometimes a float with widget = NULL is created as a key; this
- // is not interesting for RTFL.
- if (widget) {
- DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
- sizeChangedSinceLastAllocation);
- }
-}
-
-void OutOfFlowMgr::Float::updateAllocation ()
-{
- DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
-
- update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
- getNewHeight ());
-
- DBG_OBJ_LEAVE_O (getWidget ());
-}
-
-void OutOfFlowMgr::Float::intoStringBuffer(StringBuffer *sb)
-{
- sb->append ("{ widget = ");
- sb->appendPointer (getWidget ());
-
- if (getWidget ()) {
- sb->append (" (");
- sb->append (getWidget()->getClassName ());
- sb->append (")");
- }
-
- sb->append (", indexGBList = ");
- sb->appendInt (indexGBList);
- sb->append (", indexCBList = ");
- sb->appendInt (indexCBList);
- sb->append (", sideSpanningIndex = ");
- sb->appendInt (sideSpanningIndex);
- sb->append (", generatingBlock = ");
- sb->appendPointer (generatingBlock);
- sb->append (", yReq = ");
- sb->appendInt (yReq);
- sb->append (", yReal = ");
- sb->appendInt (yReal);
- sb->append (", size = { ");
- sb->appendInt (size.width);
- sb->append (" * ");
- sb->appendInt (size.ascent);
- sb->append (" + ");
- sb->appendInt (size.descent);
- sb->append (" }, dirty = ");
- sb->appendBool (dirty);
- sb->append (", sizeChangedSinceLastAllocation = ");
- sb->appendBool (sizeChangedSinceLastAllocation);
- sb->append (" }");
-}
-
-bool OutOfFlowMgr::Float::covers (Textblock *textblock, int y, int h)
-{
- DBG_OBJ_ENTER_O ("border", 0, getOutOfFlowMgr (), "covers",
- "%p, %d, %d [vloat: %p]",
- textblock, y, h, getWidget ());
-
- bool b;
-
- if (textblock == generatingBlock) {
- int reqyGB = y;
- int flyGB = yReal;
- getOutOfFlowMgr()->ensureFloatSize (this);
- int flh = size.ascent + size.descent;
- b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "for generator: reqyGB = %d, flyGB = %d, "
- "flh = %d + %d = %d => %s",
- reqyGB, flyGB, size.ascent, size.descent, flh,
- b ? "true" : "false");
- } else {
- // (If the textblock were not allocated, the GB list would have
- // been choosen instead of the CB list, and so this else-branch
- // would not have been not executed.)
- assert (getOutOfFlowMgr()->wasAllocated (textblock));
-
- if (!getWidget()->wasAllocated ()) {
- DBG_OBJ_MSG_O ("border", 1, getOutOfFlowMgr (),
- "not generator (not allocated) => false");
- b = false;
- } else {
- Allocation *tba = getOutOfFlowMgr()->getAllocation(textblock),
- *fla = getWidget()->getAllocation ();
- int reqyCanv = tba->y + y;
- int flyCanv = fla->y;
- int flh = fla->ascent + fla->descent;
- b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "not generator (allocated): reqyCanv = %d + %d = %d, "
- "flyCanv = %d, flh = %d + %d = %d => %s",
- tba->y, y, reqyCanv, flyCanv,
- fla->ascent, fla->descent, flh, b ? "true" : "false");
- }
- }
+namespace oof {
- DBG_OBJ_LEAVE_O (getOutOfFlowMgr ());
-
- return b;
-}
-
-int OutOfFlowMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+OutOfFlowMgr::OutOfFlowMgr ()
{
- Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
- int r;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm,
- "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
- fl1->getIndex (type), fl2->getIndex (type), refTB);
-
- if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
- r = fl1->yReal - fl2->yReal;
- } else {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
- DBG_OBJ_MSG_START_O (oofm);
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
- fl1->generatingBlock, fl2->generatingBlock);
-
- // (i) Floats may not yet been allocated. Non-allocated floats
- // do not have an effect yet, they are considered "at the end"
- // of the list.
-
- // (ii) Float::widget is NULL for the key used for binary
- // search. In this case, Float::yReal is used instead (which is
- // set in SortedFloatsVector::find, too). The generator is the
- // textblock, and should be allocated. (If not, the GB list
- // would have been choosen instead of the CB list, and so this
- // else-branch would not have been not executed.)
-
- bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
- bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
- fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
- a2 ? "yes" : "no");
-
- if (a1 && a2) {
- int fly1, fly2;
-
- if (fl1->getWidget()) {
- fly1 = fl1->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
- } else {
- assert (oofm->wasAllocated (fl1->generatingBlock));
- fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
- oofm->getAllocation(fl1->generatingBlock)->y,
- fl1->yReal, fly1);
- }
-
- if (fl2->getWidget()) {
- fly2 = fl2->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
- } else {
- assert (oofm->wasAllocated (fl2->generatingBlock));
- fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
- oofm->getAllocation(fl2->generatingBlock)->y,
- fl2->yReal, fly2);
- }
-
- r = fly1 - fly2;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
- } else if (a1 && !a2)
- r = -1;
- else if (!a1 && a2)
- r = +1;
- else // if (!a1 && !a2)
- return 0;
-
- DBG_OBJ_MSG_END_O (oofm);
- }
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
- Object *o2)
-{
- return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
-}
-
-int OutOfFlowMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
-{
- Float *f1 = (Float*)o1, *f2 = (Float*)o2;
- int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
- "#%d -> %p/%d, #%d -> %p/#%d",
- f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
- f2->getIndex (type), f2->generatingBlock,
- f2->externalIndex);
-
- if (f1->generatingBlock == f2->generatingBlock) {
- r = f1->externalIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(a) generating blocks equal => %d - %d = %d",
- f1->externalIndex, f2->externalIndex, r);
- } else {
- TBInfo *t1 = oofm->getTextblock (f1->generatingBlock),
- *t2 = oofm->getTextblock (f2->generatingBlock);
- bool rdef = false;
-
- for (TBInfo *t = t1; t != NULL; t = t->parent)
- if (t->parent == t2) {
- rdef = true;
- r = t->parentExtIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(b) %p is an achestor of %p; direct child is "
- "%p (%d) => %d - %d = %d\n",
- t2->getTextblock (), t1->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- t->parentExtIndex, f2->externalIndex, r);
- }
-
- for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
- if (t->parent == t1) {
- r = f1->externalIndex - t->parentExtIndex;
- rdef = true;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(c) %p is an achestor of %p; direct child is %p "
- "(%d) => %d - %d = %d\n",
- t1->getTextblock (), t2->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- f1->externalIndex, t->parentExtIndex, r);
- }
-
- if (!rdef) {
- r = t1->index - t2->index;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
- t1->index, t2->index, r);
- }
- }
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::findFloatIndex (Textblock *lastGB,
- int lastExtIndex)
-{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
- lastGB, lastExtIndex);
-
- Float key (oofm, NULL, lastGB, lastExtIndex);
- key.setIndex (type, -1); // for debugging
- Float::CompareGBAndExtIndex comparator (oofm, type);
- int i = bsearch (&key, false, &comparator);
-
- // At position i is the next larger element, so element i should
- // not included, but i - 1 returned; except if the exact element is
- // found: then include it and so return i.
- int r;
- if (i == size())
- r = i - 1;
- else {
- Float *f = get (i);
- if (comparator.compare (f, &key) == 0)
- r = i;
- else
- r = i - 1;
- }
-
- //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
- // "in %s list %p on the %s side\n",
- // oofm->containingBlock, lastGB, lastExtIndex, i, r, size (),
- // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
-
- //for (int i = 0; i < size (); i++) {
- // Float *f = get(i);
- // TBInfo *t = oofm->getTextblock(f->generatingBlock);
- // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
- // t->index, t->parent ? t->parent->textblock : NULL,
- // get(i)->externalIndex);
- //}
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-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::Float::CompareSideSpanningIndex comparator;
- Float key (NULL, NULL, NULL, 0);
- key.sideSpanningIndex = sideSpanningIndex;
- return bsearch (&key, false, &comparator) - 1;
-}
-
-void OutOfFlowMgr::SortedFloatsVector::put (Float *vloat)
-{
- lout::container::typed::Vector<Float>::put (vloat);
- vloat->setIndex (type, size() - 1);
-}
-
-OutOfFlowMgr::TBInfo::TBInfo (OutOfFlowMgr *oofm, Textblock *textblock,
- TBInfo *parent, int parentExtIndex) :
- WidgetInfo (oofm, textblock)
-{
- this->parent = parent;
- this->parentExtIndex = parentExtIndex;
-
- leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB);
- rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB);
-
- wasAllocated = getWidget()->wasAllocated ();
- allocation = *(getWidget()->getAllocation ());
- clearPosition = 0;
-}
-
-OutOfFlowMgr::TBInfo::~TBInfo ()
-{
- delete leftFloatsGB;
- delete rightFloatsGB;
-}
-
-void OutOfFlowMgr::TBInfo::updateAllocation ()
-{
- DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
-
- update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
- getNewHeight ());
-
- DBG_OBJ_LEAVE_O (getWidget ());
-}
-
-OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock)
-{
- DBG_OBJ_CREATE ("dw::OutOfFlowMgr");
-
- this->containingBlock = containingBlock;
-
- leftFloatsCB = new SortedFloatsVector (this, LEFT, CB);
- rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB);
-
- DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
- DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
-
- leftFloatsAll = new Vector<Float> (1, true);
- rightFloatsAll = new Vector<Float> (1, true);
-
- DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
- DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
-
- floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
-
- tbInfos = new Vector<TBInfo> (1, false);
- tbInfosByTextblock =
- new HashTable <TypedPointer <Textblock>, TBInfo> (true, true);
-
- leftFloatsMark = rightFloatsMark = 0;
- lastLeftTBIndex = lastRightTBIndex = 0;
-
- containingBlockWasAllocated = containingBlock->wasAllocated ();
- containingBlockAllocation = *(containingBlock->getAllocation());
-
- addWidgetInFlow (containingBlock, NULL, 0);
}
OutOfFlowMgr::~OutOfFlowMgr ()
{
- //printf ("OutOfFlowMgr::~OutOfFlowMgr\n");
-
- delete leftFloatsCB;
- delete rightFloatsCB;
-
- // Order is important: tbInfosByTextblock is owner of the instances
- // of TBInfo.tbInfosByTextblock
- delete tbInfos;
- delete tbInfosByTextblock;
-
- delete floatsByWidget;
-
- // Order is important, since the instances of Float are owned by
- // leftFloatsAll and rightFloatsAll, so these should be deleted
- // last.
- delete leftFloatsAll;
- delete rightFloatsAll;
-
- DBG_OBJ_DELETE ();
-}
-
-void OutOfFlowMgr::sizeAllocateStart (Textblock *caller, Allocation *allocation)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
- "%p, (%d, %d, %d * (%d + %d))",
- caller, allocation->x, allocation->y, allocation->width,
- allocation->ascent, allocation->descent);
-
- getTextblock(caller)->allocation = *allocation;
- getTextblock(caller)->wasAllocated = true;
-
- if (caller == containingBlock) {
- // In the size allocation process, the *first* OOFM method
- // called is sizeAllocateStart, with the containing block as an
- // argument. So this is the correct point to initialize size
- // allocation.
-
- containingBlockAllocation = *allocation;
- containingBlockWasAllocated = true;
-
- // Move floats from GB lists to the one CB list.
- moveFromGBToCB (LEFT);
- moveFromGBToCB (RIGHT);
-
- // These attributes are used to keep track which floats have
- // been allocated (referring to leftFloatsCB and rightFloatsCB).
- lastAllocatedLeftFloat = lastAllocatedRightFloat = -1;
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
-
- // (Later, absolutely positioned blocks have to be allocated.)
-
- if (caller != containingBlock) {
- // Allocate all floats "before" this textblock.
- sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
- sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
- }
-
- // The checks below do not cover "clear position" in all cases, so
- // this is done here separately. This position is stored in TBInfo
- // and calculated at this points; changes will be noticed to the
- // textblock.
- TBInfo *tbInfo = getTextblock (caller);
- int newClearPosition = calcClearPosition (caller);
- if (newClearPosition != tbInfo->clearPosition) {
- tbInfo->clearPosition = newClearPosition;
- caller->clearPositionChanged ();
- }
-
- if (caller == containingBlock) {
- // In the size allocation process, the *last* OOFM method called
- // is sizeAllocateEnd, with the containing block as an
- // argument. So this is the correct point to finish size
- // allocation.
-
- // Allocate all remaining floats.
- sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1);
- sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1);
-
- // Check changes of both textblocks and floats allocation. (All
- // is checked by hasRelationChanged (...).)
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- int minFloatPos;
- Widget *minFloat;
- if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
- tb->borderChanged (minFloatPos, minFloat);
- }
-
- checkAllocatedFloatCollisions (LEFT);
- checkAllocatedFloatCollisions (RIGHT);
-
- // Store some information for later use.
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- tbInfo->updateAllocation ();
- tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
- }
-
- // There are cases where some allocated floats (TODO: later also
- // absolutely positioned elements?) exceed the CB allocation.
- bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT);
-
- // Similar for extremes. (TODO: here also absolutely positioned
- // elements?)
- bool extremesChanged =
- haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT);
-
- for (int i = 0; i < leftFloatsCB->size(); i++)
- leftFloatsCB->get(i)->updateAllocation ();
-
- for (int i = 0; i < rightFloatsCB->size(); i++)
- rightFloatsCB->get(i)->updateAllocation ();
-
- if (sizeChanged || extremesChanged)
- containingBlock->oofSizeChanged (extremesChanged);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::containerSizeChangedForChildren ()
-{
- DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
-
- DBG_OBJ_MSGF ("resize", 0, "%d left floats, %d right floats",
- leftFloatsAll->size (), rightFloatsAll->size ());
-
- for (int i = 0; i < leftFloatsAll->size (); i++)
- leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
- for (int i = 0; i < rightFloatsAll->size (); i++)
- rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
- Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, ...", tbInfo->getWidget ());
-
- int leftMinPos, rightMinPos;
- Widget *leftMinFloat, *rightMinFloat;
- bool c1 =
- hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
- bool c2 =
- hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
- if (c1 || c2) {
- if (!c1) {
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- } else if (!c2) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else {
- if (leftMinPos < rightMinPos) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else{
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- }
- }
- }
-
- if (c1 || c2)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "has changed: minFloatPos = %d, minFloat = %p",
- *minFloatPos, *minFloat);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
- return c1 || c2;
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
- int *minFloatPos, Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, %s, ...",
- tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size(); i++) {
- // TODO binary search?
- Float *vloat = list->get(i);
- int floatPos;
-
- if (tbInfo->getTextblock () == vloat->generatingBlock)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "not checking (generating!) textblock %p against float "
- "%p", tbInfo->getWidget (), vloat->getWidget ());
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock);
-
- int newFlx =
- calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x, 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, true)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides, new yReal = %d (old: %d)",
- yRealNewSame, vloat->yReal);
- if (vloat->yReal != yRealNewSame) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewSame);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
- }
- }
-
- if (oppList->size () > 0) {
- // Other side. Iterate to next float on the other side,
- // before this float.
- while (oppIndex + 1 < oppList->size () &&
- oppList->get(oppIndex + 1)->sideSpanningIndex
- < vloat->sideSpanningIndex)
- oppIndex++;
-
- if (oppList->get(oppIndex)->sideSpanningIndex
- < vloat->sideSpanningIndex) {
- int oppIndexTmp = oppIndex, yRealNewOpp;
-
- // Aproach is similar to tellPosition(); see comments
- // there. Again, loop as long as the vertical dimensions test
- // is positive (and, of course, there are floats), ...
- for (bool foundColl = false;
- !foundColl && oppIndexTmp >= 0 &&
- collidesV (vloat, oppList->get (oppIndexTmp), CB,
- &yRealNewOpp, true);
- oppIndexTmp--) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "opposite side (after collision (v) test): "
- "checking %p (#%d/%d, GB: %p) against "
- "%p (#%d/%d, GB: %p)",
- vloat->getWidget (), index,
- vloat->sideSpanningIndex,
- vloat->generatingBlock,
- oppList->get(oppIndexTmp)->getWidget (),
- oppList->get(oppIndexTmp)->getIndex (CB),
- oppList->get(oppIndexTmp)->sideSpanningIndex,
- oppList->get(oppIndexTmp)->generatingBlock);
-
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides (h), new yReal = %d (old: %d)",
- yRealNewOpp, vloat->yReal);
- foundColl = true;
- if (vloat->yReal != yRealNewOpp) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewOpp);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
- }
- }
- }
-
- if (needsChange)
- vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
- vloat->getWidget ());
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::doFloatsExceedCB (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This method is called to determine whether the *requisition* of
- // the CB must be recalculated. So, we check the float allocations
- // against the *requisition* of the CB, which may (e. g. within
- // tables) differ from the new allocation. (Generally, a widget may
- // allocated at a different size.)
- core::Requisition cbReq;
- containingBlock->sizeRequest (&cbReq);
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool exceeds = false;
-
- DBG_OBJ_MSG_START ();
-
- for (int i = 0; i < list->size () && !exceeds; i++) {
- Float *vloat = list->get (i);
- if (vloat->getWidget()->wasAllocated ()) {
- Allocation *fla = vloat->getWidget()->getAllocation ();
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "Does FlA = (%d, %d, %d * %d) exceed CBA = "
- "(%d, %d, %d * %d)?",
- fla->x, fla->y, fla->width, fla->ascent + fla->descent,
- containingBlockAllocation.x, containingBlockAllocation.y,
- cbReq.width, cbReq.ascent + cbReq.descent);
- if (fla->x + fla->width > containingBlockAllocation.x + cbReq.width ||
- fla->y + fla->ascent + fla->descent
- > containingBlockAllocation.y + cbReq.ascent + cbReq.descent) {
- exceeds = true;
- DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
- } else
- DBG_OBJ_MSG ("resize.oofm", 2, "No.");
- }
- }
-
- DBG_OBJ_MSG_END ();
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return exceeds;
-}
-
-bool OutOfFlowMgr::haveExtremesChanged (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This is quite different from doFloatsExceedCB, since there is no
- // counterpart to getExtremes, as sizeAllocate is a counterpart to
- // sizeRequest. So we have to determine whether the allocation has
- // changed the extremes, which is done by examining the part of the
- // allocation which is part of the extremes calculation (see
- // getFloatsExtremes). Changes of the extremes are handled by the
- // normal queueResize mechanism.
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size () && !changed; i++) {
- Float *vloat = list->get (i);
- // When the GB is the CB, an allocation change does not play a
- // role here.
- if (vloat->generatingBlock != containingBlock) {
- if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
- changed = true;
- else {
- // This method is called within sizeAllocateEnd, where
- // containinBlock->getAllocation() (old value) and
- // containinBlockAllocation (new value) are different.
-
- Allocation *oldCBA = containingBlock->getAllocation ();
- Allocation *newCBA = &containingBlockAllocation;
-
- // Compare also to getFloatsExtremes. The box difference
- // of the GB (from style) has not changed in this context,
- // so it is ignored.
-
- int oldDiffLeft = vloat->getOldXCB ();
- int newDiffLeft = vloat->getNewXCB ();
- int oldDiffRight =
- oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
- int newDiffRight =
- newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
-
- if (// regarding minimum
- (side == LEFT && oldDiffLeft != newDiffLeft) ||
- (side == RIGHT && oldDiffRight != newDiffRight) ||
- // regarding maximum
- oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
- changed = true;
- }
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return changed;
-}
-
-void OutOfFlowMgr::moveFromGBToCB (Side side)
-{
- DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
-
- for (int mark = 0; mark <= *floatsMark; mark++)
- for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
- it.hasNext (); ) {
- TBInfo *tbInfo = it.getNext ();
- SortedFloatsVector *src =
- side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
- for (int i = 0; i < src->size (); i++) {
- Float *vloat = src->get (i);
- // "vloat->indexCBList == -1": prevent copying the vloat twice.
- if (vloat->indexCBList == -1 && vloat->mark == mark) {
- dest->put (vloat);
- DBG_OBJ_MSGF ("oofm.resize", 1,
- "moving float %p (mark %d) to CB list\n",
- vloat->getWidget (), vloat->mark);
- DBG_OBJ_SET_NUM (side == LEFT ?
- "leftFloatsCB.size" : "rightFloatsCB.size",
- dest->size());
- DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
- "leftFloatsCB" : "rightFloatsCB",
- dest->size() - 1, "widget",
- vloat->getWidget ());
-
- }
- }
- }
-
- *floatsMark = 0;
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
-{
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *lastAllocatedFloat =
- side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
- "%s, [%d ->] %d [size = %d]",
- side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
- newLastAllocatedFloat, list->size ());
-
- Allocation *cba = &containingBlockAllocation;
-
- for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
- Float *vloat = list->get(i);
- ensureFloatSize (vloat);
-
- Allocation *gba = getAllocation (vloat->generatingBlock);
- 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.common", 1, "left: x = %d + %d = %d",
- gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x);
- // ... but when the float exceeds the line break width of the
- // container, it is corrected (but not left of the container).
- // This way, we save space and, especially within tables, avoid
- // some problems.
- if (wasAllocated (containingBlock) &&
- x + vloat->size.width > containingBlock->getLineBreakWidth ()) {
- x = max (0, containingBlock->getLineBreakWidth () - vloat->size.width);
- DBG_OBJ_MSGF ("resize.common", 1,
- "corrected to: max (0, %d - %d) = %d",
- containingBlock->getLineBreakWidth (), vloat->size.width,
- x);
- }
- break;
-
- case RIGHT:
- // Similar for right floats, but in this case, floats are
- // shifted to the right when they are too big (instead of
- // shifting the generator to the right).
-
- // 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);
-}
-
-void OutOfFlowMgr::drawFloats (SortedFloatsVector *list, View *view,
- Rectangle *area)
-{
- // This could be improved, since the list is sorted: search the
- // first float fitting into the area, and iterate until one is
- // found below the area.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- Rectangle childArea;
- if (vloat->getWidget()->intersects (area, &childArea))
- vloat->getWidget()->draw (view, &childArea);
- }
-}
-
-void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock,
- Textblock *parentBlock, int externalIndex)
-{
- //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
- // containingBlock, textblock, parentBlock, externalIndex);
-
- TBInfo *tbInfo =
- new TBInfo (this, textblock,
- parentBlock ? getTextblock (parentBlock) : NULL,
- externalIndex);
- tbInfo->index = tbInfos->size();
-
- tbInfos->put (tbInfo);
- tbInfosByTextblock->put (new TypedPointer<Textblock> (textblock), tbInfo);
-}
-
-void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
- int externalIndex)
-{
- DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
- widget, generatingBlock, externalIndex);
-
- if (isWidgetFloat (widget)) {
- TBInfo *tbInfo = getTextblock (generatingBlock);
-
- Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
-
- // Note: Putting the float first in the GB list, and then,
- // possibly into the CB list (in that order) will trigger
- // setting Float::inCBList to the right value.
-
- switch (widget->getStyle()->vloat) {
- case FLOAT_LEFT:
- leftFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefLeftFloat (leftFloatsAll->size() - 1);
- DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
- tbInfo->leftFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- leftFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastLeftTBIndex)
- leftFloatsMark++;
-
- vloat->mark = leftFloatsMark;
- //printf ("[%p] adding left float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastLeftTBIndex);
-
- lastLeftTBIndex = tbInfo->index;
- }
- break;
-
- case FLOAT_RIGHT:
- rightFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefRightFloat (rightFloatsAll->size() - 1);
- DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
- tbInfo->rightFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- rightFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastRightTBIndex)
- rightFloatsMark++;
-
- vloat->mark = rightFloatsMark;
- //printf ("[%p] adding right float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastRightTBIndex);
-
- lastRightTBIndex = tbInfo->index;
- }
-
- break;
-
- default:
- assertNotReached();
- }
-
- // "sideSpanningIndex" is only compared, so this simple
- // assignment is sufficient; differenciation between GB and CB
- // lists is not neccessary. TODO: Can this also be applied to
- // "index", to simplify the current code? Check: where is
- // "index" used.
- vloat->sideSpanningIndex =
- leftFloatsAll->size() + rightFloatsAll->size() - 1;
-
- floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
- } else
- // May be extended.
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::moveExternalIndices (Textblock *generatingBlock,
- int oldStartIndex, int diff)
-{
- TBInfo *tbInfo = getTextblock (generatingBlock);
- moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff);
- moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff);
-}
-
-void OutOfFlowMgr::moveExternalIndices (SortedFloatsVector *list,
- int oldStartIndex, int diff)
-{
- // Could be faster with binary search, but the GB (not CB!) lists
- // should be rather small.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- if (vloat->externalIndex >= oldStartIndex) {
- vloat->externalIndex += diff;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
- vloat->externalIndex);
- }
- }
-}
-
-OutOfFlowMgr::Float *OutOfFlowMgr::findFloatByWidget (Widget *widget)
-{
- TypedPointer <Widget> key (widget);
- Float *vloat = floatsByWidget->get (&key);
- assert (vloat != NULL);
- return vloat;
-}
-
-void OutOfFlowMgr::markSizeChange (int ref)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
-
- if (isRefFloat (ref)) {
- Float *vloat;
-
- if (isRefLeftFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = leftFloatsAll->get (i);
- //printf (" => left float %d\n", i);
- } else if (isRefRightFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = rightFloatsAll->get (i);
- //printf (" => right float %d\n", i);
- } else {
- assertNotReached();
- vloat = NULL; // compiler happiness
- }
-
- vloat->dirty = vloat->sizeChangedSinceLastAllocation = true;
-
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (),
- "<Float>.sizeChangedSinceLastAllocation",
- vloat->sizeChangedSinceLastAllocation);
-
- // The generating block is told directly about this. (Others later, in
- // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which
- // differentiates many special cases), but the size is not known yet,
- vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ());
- } else
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-
-void OutOfFlowMgr::markExtremesChange (int ref)
-{
- // Nothing to do here.
-}
-
-Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level)
-{
- Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level);
- if (childAtPoint == NULL)
- childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level);
- return childAtPoint;
-}
-
-Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list,
- int x, int y, int level)
-{
- for (int i = 0; i < list->size(); i++) {
- // Could use binary search to be faster.
- Float *vloat = list->get(i);
- if (vloat->getWidget()->wasAllocated ()) {
- Widget *childAtPoint =
- vloat->getWidget()->getWidgetAtPoint (x, y, level + 1);
- if (childAtPoint)
- return childAtPoint;
- }
- }
-
- return NULL;
-}
-
-void OutOfFlowMgr::tellPosition (Widget *widget, int yReq)
-{
- if (isWidgetFloat (widget))
- tellFloatPosition (widget, yReq);
-
- // Nothing to do for absolutely positioned blocks.
-}
-
-
-void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "tellFloatPosition", "%p, %d",
- widget, yReq);
-
- assert (yReq >= 0);
-
- Float *vloat = findFloatByWidget(widget);
-
- SortedFloatsVector *listSame, *listOpp;
- Side side;
- getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
- ensureFloatSize (vloat);
-
- // "yReal" may change due to collisions (see below).
- vloat->yReq = vloat->yReal = yReq;
-
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
-
- // Test collisions (on this side). Although there are (rare) cases
- // where it could make sense, the horizontal dimensions are not
- // tested; especially since searching and border calculation would
- // be confused. For this reaspn, only the previous float is
- // relevant. (Cf. below, collisions on the other side.)
- int index = vloat->getIndex (listSame->type), yRealNew;
- if (index >= 1 &&
- collidesV (vloat, listSame->get (index - 1), listSame->type,
- &yRealNew, false)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- }
-
- // Test collisions (on the opposite side). There are cases when
- // more than one float has to be tested. Consider the following
- // HTML snippet ("id" attribute only used for simple reference
- // below, as #f1, #f2, and #f3):
- //
- // <div style="float:left" id="f1">
- // Left left left left left left left left left left.
- // </div>
- // <div style="float:left" id="f2">Also left.</div>
- // <div style="float:right" id="f3">Right.</div>
- //
- // When displayed with a suitable window width (only slightly wider
- // than the text within #f1), this should look like this:
- //
- // ---------------------------------------------------------
- // | Left left left left left left left left left left. |
- // | Also left. Right. |
- // ---------------------------------------------------------
- //
- // Consider float #f3: a collision test with #f2, considering
- // vertical dimensions, is positive, but not the test with
- // horizontal dimensions (because #f2 and #f3 are too
- // narrow). However, a collision has to be tested with #f1;
- // otherwise #f3 and #f1 would overlap.
-
- int oppFloatIndex =
- listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
- // Generally, the rules are simple: loop as long as the vertical
- // dimensions test is positive (and, of course, there are floats),
- // ...
- for (bool foundColl = false;
- !foundColl && oppFloatIndex >= 0 &&
- collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
- &yRealNew, false);
- oppFloatIndex--) {
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- foundColl = true;
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
- vloat->yReq, vloat->yReal);
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::collidesV (Float *vloat, Float *other, SFVType type,
- int *yReal, bool useAllocation)
-{
- // Only checks vertical (possible) collisions, and only refers to
- // vloat->yReal; never to vloat->allocation->y, even when the GBs are
- // different. Used only in tellPosition.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
- vloat->getIndex (type), vloat->getWidget (),
- other->getIndex (type), other->getWidget ());
-
- bool result;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
-
- if (vloat->generatingBlock == other->generatingBlock) {
- ensureFloatSize (other);
- int otherBottomGB =
- other->yReal + other->size.ascent + other->size.descent;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "same generators: otherBottomGB = %d + (%d + %d) = %d",
- other->yReal, other->size.ascent, other->size.descent,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- } else {
- // If the other float is not allocated, there is no collision. The
- // allocation of this float (vloat) is not used at all.
- if (!other->getWidget()->wasAllocated ())
- result = false;
- else {
- assert (wasAllocated (vloat->generatingBlock));
- Allocation *gba = getAllocation (vloat->generatingBlock),
- *flaOther = other->getWidget()->getAllocation ();
-
- // We distinguish two cases (by different values of useAllocation):
- // (i) within tellPosition, GB allocation + yReal is used for the
- // y position of the other float, while (ii) in checkAllocatedFloat-
- // Collisions, the float allocation is used. The latter is necessary
- // by the definition of this method, the former increases performance,
- // as compared to using the float allocation, in some cases, as in
- // this:
- //
- // When '<div><div style="float:left">[Some text]</div></div>' is
- // repeated n times, the resize idle function (Layout::resizeIdle)
- // would be repeated roughly n times, when also in case (i) the float
- // allocation is used, since for the collision test of float n with
- // float n - 1, the allocation of float n - 1 does not yet reflect the
- // collision test between n - 1 and n - 2, but yReal does for n - 1.
- //
- // On the other hand, the GB allocations will most likely more stable
- // than the float allocations.
- //
- // Cases where this is incorrect will hopefully be rare, and, in any
- // case, corrected in sizeAllocateEnd, either because hasRelation-
- // Changed returns true, or in checkAllocatedFloatCollisions.
-
- int otherFloatY = useAllocation ? flaOther->y :
- getAllocation(other->generatingBlock)->y + other->yReal;
- int otherBottomGB =
- otherFloatY + flaOther->ascent + flaOther->descent - gba->y;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "different generators: "
- "otherBottomGB = %d + (%d + %d) - %d = %d",
- otherFloatY, flaOther->ascent, flaOther->descent, gba->y,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- }
- }
-
- if (result)
- DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
-
- DBG_OBJ_LEAVE ();
- return result;
-}
-
-
-bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type)
-{
- // Only checks horizontal collision. For a complete test, use
- // collidesV (...) && collidesH (...).
- bool collidesH;
-
- if (vloat->generatingBlock == other->generatingBlock)
- collidesH = vloat->size.width + other->size.width
- + vloat->generatingBlock->getStyle()->boxDiffWidth()
- > vloat->generatingBlock->getLineBreakWidth();
- else {
- // Again, if the other float is not allocated, there is no
- // collision. Compare to collidesV. (But vloat->size is used
- // here.)
- if (!other->getWidget()->wasAllocated ())
- collidesH = false;
- else {
- assert (wasAllocated (vloat->generatingBlock));
- Allocation *gba = getAllocation (vloat->generatingBlock);
- int vloatX =
- calcFloatX (vloat,
- vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
- LEFT : RIGHT,
- gba->x, 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 oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
- getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
- getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
-
- *oofWidth = max (oofWidthtLeft, oofWidthRight);
- *oofHeight = max (oofHeightLeft, oofHeightRight);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)",
- oofWidthtLeft, oofWidthRight, *oofWidth,
- oofHeightLeft, oofHeightRight, *oofHeight);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
- int *height)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
- cbReq->width, cbReq->ascent, cbReq->descent,
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
-
- *width = *height = 0;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "float %p has generator %p (container is %p)",
- vloat->getWidget (), vloat->generatingBlock,
- containingBlock);
-
- if (vloat->generatingBlock == containingBlock ||
- wasAllocated (vloat->generatingBlock)) {
- ensureFloatSize (vloat);
- int x, y;
-
- 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 oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
- getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
- getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
-
- *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
- *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
- oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
- oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
- int *minWidth, int *maxWidth)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
- cbExtr->minWidth, cbExtr->maxWidth,
- side == LEFT ? "LEFT" : "RIGHT");
-
- *minWidth = *maxWidth = 0;
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- 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 ();
-}
+} // namespace oof
} // namespace dw
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index 24607bad..151c29f5 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -5,432 +5,88 @@
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 (); }
- };
-
- // These two lists store all floats, in the order in which they are
- // defined. Only used for iterators.
- lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll;
-
- // These two lists store all floats whose generators are already
- // allocated.
- SortedFloatsVector *leftFloatsCB, *rightFloatsCB;
-
- // These two attributes are used in the size allocation process;
- // see sizeAllocateStart and sizeAllocateEnd.
- int lastAllocatedLeftFloat, lastAllocatedRightFloat;
-
- lout::container::typed::HashTable<lout::object::TypedPointer
- <dw::core::Widget>, Float> *floatsByWidget;
-
- lout::container::typed::Vector<TBInfo> *tbInfos;
- lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>,
- TBInfo> *tbInfosByTextblock;
-
- int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
-
- /**
- * 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);
- core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
- int level);
-
- bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal,
- bool useAllocation);
- bool collidesH (Float *vloat, Float *other, SFVType type);
-
- void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
- SortedFloatsVector **listOpp, Side *side);
-
- void getFloatsSize (core::Requisition *cbReq, Side side, int *width,
- int *height);
- void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth,
- int *maxWidth);
- 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);
-
- static inline bool isStyleFloat (core::style::Style *style)
- { return style->vloat != core::style::FLOAT_NONE; }
- static inline bool isWidgetFloat (core::Widget *widget)
- { return isStyleFloat (widget->getStyle()); }
-
- /*
- * Format for parent ref (see also below for isRefOutOfFlow,
- * createRefNormalFlow, and getLineNoFromRef.
- *
- * Widget in flow:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | line number | 0 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * So, anything with the least signifant bit set to 1 is out of flow.
- *
- * Floats:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | left float index | 0 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | right float index | 1 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * Absolutely positioned blocks: solved differently in the
- * "dillo_grows" repository.
- */
-
- inline static bool isRefFloat (int ref)
- { return ref != -1 && (ref & 3) == 1; }
- inline static bool isRefLeftFloat (int ref)
- { return ref != -1 && (ref & 7) == 1; }
- inline static bool isRefRightFloat (int ref)
- { return ref != -1 && (ref & 7) == 5; }
-
- inline static int createRefLeftFloat (int index)
- { return (index << 3) | 1; }
- inline static int createRefRightFloat (int index)
- { return (index << 3) | 5; }
-
- inline static int getFloatIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 3); }
-
public:
- OutOfFlowMgr (Textblock *containingBlock);
- ~OutOfFlowMgr ();
-
- void sizeAllocateStart (Textblock *caller, core::Allocation *allocation);
- void sizeAllocateEnd (Textblock *caller);
- void containerSizeChangedForChildren ();
- void draw (core::View *view, core::Rectangle *area);
-
- void markSizeChange (int ref);
- void markExtremesChange (int ref);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
-
- static bool isStyleOutOfFlow (core::style::Style *style)
- { return isStyleFloat (style); }
- static inline bool isWidgetOutOfFlow (core::Widget *widget)
- { return isStyleOutOfFlow (widget->getStyle()); }
-
- void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
- int externalIndex);
- void addWidgetOOF (core::Widget *widget, Textblock *generatingBlock,
- int externalIndex);
- void moveExternalIndices (Textblock *generatingBlock, int oldStartIndex,
- int diff);
-
- void tellPosition (core::Widget *widget, int yReq);
-
- void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
- void getExtremes (core::Extremes *cbExtr,
- int *oofMinWidth, int *oofMaxWidth);
-
- int getLeftBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- int getRightBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- bool hasFloatLeft (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- bool hasFloatRight (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- int getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- int getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getClearPosition (Textblock *tb);
-
- 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,
+ core::StackingIteratorStack *iteratorStack,
+ core::Widget **interruptedWidget, int *index) = 0;
+
+ virtual void markSizeChange (int ref) = 0;
+ virtual void markExtremesChange (int ref) = 0;
+ virtual core::Widget *getWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ core::Widget **interruptedWidget,
+ int *index)= 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 bool containerMustAdjustExtraSpace ()= 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(); }
-
- inline core::Widget *getWidget (int i) {
- if (i < leftFloatsAll->size())
- return leftFloatsAll->get(i)->getWidget ();
- else
- return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
- }
-
- inline bool affectsLeftBorder (core::Widget *widget) {
- return widget->getStyle()->vloat == core::style::FLOAT_LEFT; }
- inline bool affectsRightBorder (core::Widget *widget) {
- return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; }
+ virtual int getNumWidgets () = 0;
+ virtual core::Widget *getWidget (int i) = 0;
};
+} // namespace oof
+
} // namespace dw
#endif // __DW_OUTOFFLOWMGR_HH__
diff --git a/dw/ruler.cc b/dw/ruler.cc
index 3fdbfb6d..979cb03c 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);
@@ -63,7 +62,9 @@ bool Ruler::usesAvailWidth ()
return true;
}
-void Ruler::draw (core::View *view, core::Rectangle *area)
+void Ruler::draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
drawWidgetBox (view, area, false);
}
diff --git a/dw/ruler.hh b/dw/ruler.hh
index 1f3491bc..c94c2e55 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -20,7 +20,9 @@ protected:
void getExtremesImpl (core::Extremes *extremes);
void containerSizeChangedForChildren ();
bool usesAvailWidth ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
public:
Ruler ();
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..c9039e73
--- /dev/null
+++ b/dw/stackingcontextmgr.cc
@@ -0,0 +1,283 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.hh"
+#include "../lout/debug.hh"
+
+using namespace lout::misc;
+using namespace lout::container::typed;
+
+namespace dw {
+
+namespace core {
+
+StackingContextMgr::StackingContextMgr (Widget *widget)
+{
+ DBG_OBJ_CREATE ("dw::core::StackingContextMgr");
+
+ this->widget = widget;
+
+ childSCWidgets = new Vector<Widget> (1, false);
+ DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size());
+
+ numZIndices = 0;
+ zIndices = NULL;
+ DBG_OBJ_SET_NUM ("numZIndices", numZIndices);
+}
+
+StackingContextMgr::~StackingContextMgr ()
+{
+ delete childSCWidgets;
+ if (zIndices)
+ free (zIndices);
+ DBG_OBJ_DELETE ();
+}
+
+void StackingContextMgr::addChildSCWidget (Widget *widget)
+{
+ DBG_OBJ_ENTER ("common.scm", 0, "addChildSCWidget", "%p [z-index = %d]",
+ widget, widget->getStyle()->zIndex);
+
+ int pos = findZIndex (widget->getStyle()->zIndex, true);
+ DBG_OBJ_MSGF ("common.scm", 1, "pos = %d", pos);
+ if (pos == -1) {
+ pos = findZIndex (widget->getStyle()->zIndex, false);
+ DBG_OBJ_MSGF ("common.scm", 1, "pos = %d", pos);
+
+ numZIndices++;
+ DBG_OBJ_SET_NUM ("numZIndices", numZIndices);
+ zIndices = (int*)(zIndices ?
+ realloc (zIndices, numZIndices * sizeof (int)) :
+ malloc (numZIndices * sizeof (int)));
+
+ for (int i = numZIndices - 1; i >= pos + 1; i--) {
+ zIndices[i] = zIndices[i - 1];
+ DBG_OBJ_ARRSET_NUM ("zIndex", i, zIndices[i]);
+ }
+
+ zIndices[pos] = widget->getStyle()->zIndex;
+ DBG_OBJ_ARRSET_NUM ("zIndex", pos, zIndices[pos]);
+ }
+
+ childSCWidgets->put (widget);
+ DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size());
+ DBG_OBJ_ARRSET_PTR ("childSCWidgets", childSCWidgets->size() - 1, widget);
+
+ DBG_OBJ_LEAVE ();
+}
+
+int StackingContextMgr::findZIndex (int zIndex, bool mustExist)
+{
+ int result = -123; // Compiler happiness: GCC 4.7 does not handle this?
+
+ if (numZIndices == 0)
+ result = mustExist ? -1 : 0;
+ else {
+ int low = 0, high = numZIndices - 1;
+ bool found = false;
+
+ while (!found) {
+ int index = (low + high) / 2;
+ if (zIndex == zIndices[index]) {
+ found = true;
+ result = index;
+ } else {
+ if (low >= high) {
+ if (mustExist) {
+ found = true;
+ result = -1;
+ } else {
+ found = true;
+ result = zIndex > zIndices[index] ? index + 1 : index;
+ }
+ }
+
+ if (zIndex < zIndices[index])
+ high = index - 1;
+ else
+ low = index + 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+void StackingContextMgr::drawBottom (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex, int *index)
+{
+ DBG_OBJ_ENTER ("draw", 0, "drawBottom", "(%d, %d, %d * %d), [%d], [%d]",
+ area->x, area->y, area->width, area->height, *zIndexIndex,
+ *index);
+ draw (view, area, iteratorStack, interruptedWidget, index, INT_MIN, -1,
+ zIndexIndex);
+ DBG_OBJ_LEAVE ();
+}
+
+void StackingContextMgr::drawTop (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex, int *index)
+{
+ DBG_OBJ_ENTER ("draw", 0, "drawTop", "(%d, %d, %d * %d), [%d], [%d]",
+ area->x, area->y, area->width, area->height, *zIndexIndex,
+ *index);
+ draw (view, area, iteratorStack, interruptedWidget, index, 0, INT_MAX,
+ zIndexIndex);
+ DBG_OBJ_LEAVE ();
+}
+
+void StackingContextMgr::draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *zIndexIndex,
+ int startZIndex, int endZIndex, int *index)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d], %d, %d, [%d]",
+ area->x, area->y, area->width, area->height,
+ *zIndexIndex, startZIndex, endZIndex, *index);
+
+ DBG_OBJ_MSGF ("draw", 1, "initially: index = %d (of %d)",
+ *index, childSCWidgets->size ());
+
+ while (*interruptedWidget == NULL &&
+ *zIndexIndex < numZIndices) {
+ // Wrong region of z-indices (top or bottom) is simply ignored
+ // (as well as non-defined zIndices).
+ if (zIndices != NULL && zIndices[*zIndexIndex] >= startZIndex &&
+ zIndices[*zIndexIndex] <= endZIndex) {
+ DBG_OBJ_MSGF ("draw", 1, "drawing zIndex = %d",
+ zIndices[*zIndexIndex]);
+ DBG_OBJ_MSG_START ();
+
+ while (*interruptedWidget == NULL &&
+ *index < childSCWidgets->size ()) {
+ Widget *child = childSCWidgets->get (*index);
+ DBG_OBJ_MSGF ("draw", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ Rectangle childArea;
+ if (child->getStyle()->zIndex == zIndices[*zIndexIndex] &&
+ child->intersects (area, &childArea))
+ child->drawTotal (view, &childArea, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)++;
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ if (*interruptedWidget == NULL) {
+ (*zIndexIndex)++;
+ *index = 0;
+ }
+ }
+
+ DBG_OBJ_MSGF ("draw", 1, "finally: index = %d (of %d)",
+ *index, childSCWidgets->size ());
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+
+Widget *StackingContextMgr::getTopWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex, int *index)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTop", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget,
+ zIndexIndex, 0, INT_MAX, index);
+ DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", widget, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getBottomWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex,
+ int *index)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget,
+ zIndexIndex, INT_MIN, -1, index);
+ DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", widget, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getWidgetAtPoint (int x, int y,
+ StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex,
+ int startZIndex, int endZIndex,
+ int *index)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+
+ while (*interruptedWidget == NULL && widgetAtPoint == NULL &&
+ *zIndexIndex >= 0) {
+ // Wrong region of z-indices (top or bottom) is simply ignored
+ // (as well as non-defined zIndices).
+ if (zIndices != NULL && zIndices[*zIndexIndex] >= startZIndex &&
+ zIndices[*zIndexIndex] <= endZIndex) {
+ DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d",
+ zIndices[*zIndexIndex]);
+ DBG_OBJ_MSG_START ();
+
+ while (*interruptedWidget == NULL && widgetAtPoint == NULL &&
+ *index >= 0) {
+ Widget *child = childSCWidgets->get (*index);
+ DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ if (child->getStyle()->zIndex == zIndices[*zIndexIndex])
+ widgetAtPoint =
+ child->getWidgetAtPointTotal (x, y, iteratorStack,
+ interruptedWidget);
+
+ if (*interruptedWidget == NULL)
+ (*index)--;
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ if (*interruptedWidget == NULL) {
+ (*zIndexIndex)--;
+ *index = childSCWidgets->size () - 1;
+ }
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ 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..4fb0368d
--- /dev/null
+++ b/dw/stackingcontextmgr.hh
@@ -0,0 +1,77 @@
+#ifndef __DW_STACKINGCONTEXTMGR_HH__
+#define __DW_STACKINGCONTEXTMGR_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include "../lout/container.hh"
+
+#include <limits.h>
+
+namespace dw {
+
+namespace core {
+
+/**
+ * \brief See \ref dw-stacking-context.
+ */
+class StackingContextMgr
+{
+private:
+ Widget *widget;
+ lout::container::typed::Vector<Widget> *childSCWidgets;
+ int *zIndices, numZIndices;
+
+ int findZIndex (int zIndex, bool mustExist);
+ void draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack, Widget **interruptedWidget,
+ int *zIndexIndex, int startZIndex, int endZIndex, int *index);
+ Widget *getWidgetAtPoint (int x, int y, StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *zIndexIndex,
+ int startZIndex, int endZIndex, int *index);
+
+public:
+ StackingContextMgr (Widget *widget);
+ ~StackingContextMgr ();
+
+ inline static bool isEstablishingStackingContext (Widget *widget) {
+ return widget->getStyle()->position != style::POSITION_STATIC &&
+ widget->getStyle()->zIndex != style::Z_INDEX_AUTO;
+ }
+
+ inline static bool handledByStackingContextMgr (Widget *widget) {
+ // Each widget establishing a stacking context is child of another
+ // stacking context, so drawn by StackingContextMgr::drawTop or
+ // StackingContextMgr::drawBottom etc.
+ return widget->getParent () != NULL
+ && isEstablishingStackingContext (widget);
+ }
+
+ void addChildSCWidget (Widget *widget);
+
+ inline int getNumZIndices () { return numZIndices; }
+ inline int getNumChildSCWidgets () { return childSCWidgets->size (); }
+
+ void drawBottom (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *zIndexIndex, int *index);
+ void drawTop (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int *zIndexIndex, int *index);
+
+ Widget *getTopWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex, int *index);
+ Widget *getBottomWidgetAtPoint (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget,
+ int *zIndexIndex, int *index);
+};
+
+} // namespace core
+
+} // namespace dw
+
+#endif // __DW_STACKINGCONTEXTMGR_HH__
diff --git a/dw/style.cc b/dw/style.cc
index 54d9af4b..32a33a9e 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -93,6 +93,7 @@ void StyleAttrs::initValues ()
display = DISPLAY_INLINE;
whiteSpace = WHITE_SPACE_NORMAL;
cursor = CURSOR_DEFAULT;
+ zIndex = Z_INDEX_AUTO;
}
/**
@@ -203,6 +204,7 @@ bool StyleAttrs::equals (object::Object *other) {
listStylePosition == otherAttrs->listStylePosition &&
listStyleType == otherAttrs->listStyleType &&
cursor == otherAttrs->cursor &&
+ zIndex == otherAttrs->zIndex &&
x_link == otherAttrs->x_link &&
x_lang[0] == otherAttrs->x_lang[0] &&
x_lang[1] == otherAttrs->x_lang[1] &&
@@ -260,6 +262,7 @@ int StyleAttrs::hashValue () {
listStylePosition +
listStyleType +
cursor +
+ zIndex +
x_link +
x_lang[0] + x_lang[1] +
x_img +
@@ -381,6 +384,7 @@ void Style::copyAttrs (StyleAttrs *attrs)
listStylePosition = attrs->listStylePosition;
listStyleType = attrs->listStyleType;
cursor = attrs->cursor;
+ zIndex = attrs->zIndex;
x_link = attrs->x_link;
x_lang[0] = attrs->x_lang[0];
x_lang[1] = attrs->x_lang[1];
diff --git a/dw/style.hh b/dw/style.hh
index 230baa24..12ca1664 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -7,6 +7,8 @@
# error Do not include this file directly, use "core.hh" instead.
#endif
+#include <limits.h>
+
#include "../lout/signal.hh"
#include "../lout/debug.hh"
@@ -374,6 +376,17 @@ enum ClearType {
CLEAR_NONE
};
+enum {
+ /**
+ * \brief 'z-index' is stored as int; use this for the value 'auto'.
+ *
+ * Only some random value, which has to be checked explicitly; do
+ * not compare this (less or greater) to integer values of
+ * 'z-index'.
+ */
+ Z_INDEX_AUTO = INT_MAX
+};
+
/**
* \brief Type for representing all lengths within dw::core::style.
*
@@ -553,6 +566,7 @@ public:
ListStylePosition listStylePosition;
ListStyleType listStyleType;
Cursor cursor;
+ int zIndex;
int x_link;
int x_img;
diff --git a/dw/table.cc b/dw/table.cc
index 30ee99c7..2d820035 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 ();
}
@@ -341,18 +356,22 @@ bool Table::isBlockLevel ()
return true;
}
-void Table::draw (core::View *view, core::Rectangle *area)
+void Table::drawLevel (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel)
{
- // Can be optimized, by iterating on the lines in area.
- drawWidgetBox (view, area, false);
+ DBG_OBJ_ENTER ("draw", 0, "Table/drawLevel", "(%d, %d, %d * %d), %s",
+ area->x, area->y, area->width, area->height,
+ OOFStackingIterator::majorLevelText (majorLevel));
#if 0
+ // This old code belongs perhaps to the background. Check when reactivated.
int offx = getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
int offy = getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
int width = getContentWidth ();
-
+
// This part seems unnecessary. It also segfaulted sometimes when
- // cumHeight size was less than numRows. --jcid
+ // cumHeight size was less than numRows. --jcid
for (int row = 0; row < numRows; row++) {
if (rowStyle->get (row))
drawBox (view, rowStyle->get (row), area,
@@ -363,14 +382,95 @@ void Table::draw (core::View *view, core::Rectangle *area)
}
#endif
- for (int i = 0; i < children->size (); i++) {
- if (childDefined (i)) {
- Widget *child = children->get(i)->cell.widget;
- core::Rectangle childArea;
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (*interruptedWidget == NULL && osi->index < children->size ()) {
+ if (childDefined (osi->index)) {
+ Widget *child = children->get(osi->index)->cell.widget;
+ core::Rectangle childArea;
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child)
+ && child->intersects (area, &childArea))
+ child->drawTotal (view, &childArea, iteratorStack,
+ interruptedWidget);
+ }
+
+ if (*interruptedWidget == NULL)
+ osi->index++;
+ }
+ }
+ break;
+
+ default:
+ OOFAwareWidget::drawLevel (view, area, iteratorStack, interruptedWidget,
+ majorLevel);
+ break;
+ }
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+
+core::Widget *Table::getWidgetAtPointLevel (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int majorLevel)
+{
+ DBG_OBJ_ENTER ("events", 0, "Table/getWidgetAtPointLevel", "%d, %d, %s",
+ x, y, OOFStackingIterator::majorLevelText (majorLevel));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+
+ while (widgetAtPoint == NULL && *interruptedWidget == NULL &&
+ osi->index >= 0) {
+ if (childDefined (osi->index)) {
+ Widget *child = children->get(osi->index)->cell.widget;
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child))
+ widgetAtPoint =
+ child->getWidgetAtPointTotal (x, y, iteratorStack,
+ interruptedWidget);
+ }
+
+ if (*interruptedWidget == NULL)
+ osi->index--;
+ }
}
+ break;
+
+ default:
+ widgetAtPoint =
+ OOFAwareWidget::getWidgetAtPointLevel (x, y, iteratorStack,
+ interruptedWidget, majorLevel);
+ break;
}
+
+ DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
+int Table::getLastLevelIndex (int majorLevel, int minorLevel)
+{
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ return children->size () - 1;
+
+ default:
+ return OOFAwareWidget::getLastLevelIndex (majorLevel, minorLevel);
+ }
}
void Table::removeChild (Widget *child)
@@ -465,6 +565,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..44abc42f 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);
@@ -474,7 +471,14 @@ protected:
bool isBlockLevel ();
- void draw (core::View *view, core::Rectangle *area);
+ void drawLevel (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel);
+
+ Widget *getWidgetAtPointLevel (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel);
+ int getLastLevelIndex (int majorLevel, int minorLevel);
//bool buttonPressImpl (core::EventButton *event);
//bool buttonReleaseImpl (core::EventButton *event);
diff --git a/dw/table_iterator.cc b/dw/table_iterator.cc
index 4da0ef4f..9ba61619 100644
--- a/dw/table_iterator.cc
+++ b/dw/table_iterator.cc
@@ -28,107 +28,62 @@ namespace dw {
Table::TableIterator::TableIterator (Table *table,
core::Content::Type mask, bool atEnd):
- core::Iterator (table, mask, atEnd)
+ OOFAwareWidgetIterator (table, mask, atEnd, table->children->size ())
{
- index = atEnd ? table->children->size () : -1;
- content.type = atEnd ? core::Content::END : core::Content::START;
-}
-
-Table::TableIterator::TableIterator (Table *table,
- core::Content::Type mask, int index):
- core::Iterator (table, mask, false)
-{
- this->index = index;
-
- if (index < 0)
- content.type = core::Content::START;
- else if (index >= table->children->size ())
- content.type = core::Content::END;
- else {
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- }
}
object::Object *Table::TableIterator::clone()
{
- return new TableIterator ((Table*)getWidget(), getMask(), index);
-}
-
-int Table::TableIterator::compareTo(object::Comparable *other)
-{
- return index - ((TableIterator*)other)->index;
+ TableIterator *tIt =
+ new TableIterator ((Table*)getWidget(), getMask(), false);
+ cloneValues (tIt);
+ return tIt;
}
-bool Table::TableIterator::next ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::END)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::END;
- return false;
- }
-
- do {
- index++;
- if (index >= table->children->size ()) {
- content.type = core::Content::END;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
-
-bool Table::TableIterator::prev ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::START)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::START;
- return false;
- }
-
- do {
- index--;
- if (index < 0) {
- content.type = core::Content::START;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
void Table::TableIterator::highlight (int start, int end,
core::HighlightLayer layer)
{
- /** todo Needs this an implementation? */
+ if (inFlow ()) {
+ /** todo Needs this an implementation? */
+ } else
+ highlightOOF (start, end, layer);
}
void Table::TableIterator::unhighlight (int direction,
core::HighlightLayer layer)
{
+ if (inFlow ()) {
+ // ???
+ } else
+ unhighlightOOF (direction, layer);
}
void Table::TableIterator::getAllocation (int start, int end,
core::Allocation *allocation)
{
- /** \bug Not implemented. */
+ if (inFlow ()) {
+ /** \bug Not implemented. */
+ } else
+ getAllocationOOF (start, end, allocation);
+}
+
+int Table::TableIterator::numContentsInFlow ()
+{
+ return ((Table*)getWidget())->children->size ();
+}
+
+void Table::TableIterator::getContentInFlow (int index,
+ core::Content *content)
+{
+ Table *table = (Table*)getWidget();
+
+ if (table->children->get(index) != NULL &&
+ table->children->get(index)->type == Child::CELL) {
+ content->type = core::Content::WIDGET_IN_FLOW;
+ content->widget = table->children->get(index)->cell.widget;
+ } else
+ content->type = core::Content::INVALID;
}
} // namespace dw
diff --git a/dw/tablecell.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 9b4d5380..56b3a6d6 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,9 +265,6 @@ Textblock::Textblock (bool limitTextWidth)
lineBreakWidth = -1;
DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
- verticalOffset = 0;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
-
this->limitTextWidth = limitTextWidth;
for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
@@ -278,6 +273,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 +285,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 +302,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;
@@ -347,14 +335,15 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
// Note: the breakSpace of the last line is ignored, so breaks
// at the end of a textblock are not visible.
- requisition->width = lastLine->maxLineWidth + leftInnerPadding
- + getStyle()->boxDiffWidth ();
+ requisition->width =
+ lastLine->maxLineWidth + leftInnerPadding + boxDiffWidth ();
// Also regard collapsing of this widget top margin and the top
// margin of the first line box:
requisition->ascent = calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top
+ + extraSpace.top,
firstLine->borderAscent,
firstLine->marginAscent);
@@ -367,16 +356,14 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
// for this case is not necessary.)
calcVerticalBorder (getStyle()->padding.bottom,
getStyle()->borderWidth.bottom,
- getStyle()->margin.bottom,
+ getStyle()->margin.bottom + extraSpace.bottom,
lastLine->borderDescent, lastLine->marginDescent);
} else {
- requisition->width = leftInnerPadding + getStyle()->boxDiffWidth ();
- requisition->ascent = getStyle()->boxOffsetY ();
- requisition->descent = getStyle()->boxRestHeight ();;
+ requisition->width = leftInnerPadding + boxDiffWidth ();
+ requisition->ascent = boxOffsetY ();
+ requisition->descent = boxRestHeight ();
}
- requisition->ascent += verticalOffset;
-
if (mustBeWidenedToAvailWidth ()) {
DBG_OBJ_MSGF ("resize", 1,
"before considering lineBreakWidth (= %d): %d * (%d + %d)",
@@ -407,25 +394,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);
@@ -512,7 +481,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;
@@ -530,20 +499,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)",
@@ -595,10 +551,10 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
(lines->size () > 0 ?
calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top + extraSpace.top,
lines->getRef(0)->borderAscent,
lines->getRef(0)->marginAscent) :
- getStyle()->boxOffsetY ()) + verticalOffset);
+ boxOffsetY ()));
childBaseAllocation.descent =
allocation->ascent + allocation->descent - childBaseAllocation.ascent;
@@ -608,8 +564,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;
@@ -747,9 +702,8 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_MSG_END ();
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->sizeAllocateEnd (this);
-
+ sizeAllocateEnd ();
+
for (int i = 0; i < anchors->size(); i++) {
Anchor *anchor = anchors->getRef(i);
int y;
@@ -769,6 +723,20 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_LEAVE ();
}
+void Textblock::calcExtraSpaceImpl ()
+{
+ OOFAwareWidget::calcExtraSpaceImpl ();
+
+ int clearPosition = 0;
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (searchOutOfFlowMgr(i))
+ clearPosition =
+ misc::max (clearPosition,
+ searchOutOfFlowMgr(i)->getClearPosition (this));
+
+ extraSpace.top = misc::max (extraSpace.top, clearPosition);
+}
+
int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
{
DBG_OBJ_ENTER ("resize", 0, "Textblock/getAvailWidthOfChild", "%p, %s",
@@ -776,25 +744,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 - boxDiffWidth () - leftInnerPadding)
- width = extremes.maxWidth - boxDiffWidth () - leftInnerPadding;
+ if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ width =
+ getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
+ else {
+ if (child->getStyle()->width == core::style::LENGTH_AUTO) {
+ // No width specified: similar to standard implementation (see
+ // there), but "leftInnerPadding" has to be considered, too.
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ if (forceValue)
+ width = misc::max (getAvailWidth (true) - boxDiffWidth ()
+ - leftInnerPadding,
+ 0);
+ else
+ width = -1;
+ } else
+ width = Widget::getAvailWidthOfChild (child, forceValue);
+
+ if (forceValue && this == child->getContainer () &&
+ !mustBeWidenedToAvailWidth ()) {
+ core::Extremes extremes;
+ getExtremes (&extremes);
+ if (width > extremes.maxWidth - boxDiffWidth () - leftInnerPadding)
+ width = extremes.maxWidth - boxDiffWidth () - leftInnerPadding;
+ }
}
DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
@@ -802,7 +776,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 ()
{
@@ -814,9 +796,8 @@ void Textblock::containerSizeChangedForChildren ()
word->content.widget->containerSizeChanged ();
}
- if (outOfFlowMgr)
- outOfFlowMgr->containerSizeChangedForChildren ();
-
+ containerSizeChangedForChildrenOOF ();
+
DBG_OBJ_LEAVE ();
}
@@ -825,7 +806,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 () &&
@@ -868,13 +849,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
@@ -882,10 +860,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);
@@ -905,13 +883,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
@@ -919,11 +894,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);
@@ -932,61 +906,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;
@@ -1076,6 +995,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;
@@ -1205,11 +1126,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;
}
@@ -1530,10 +1457,14 @@ void Textblock::drawSpace(int wordIndex, core::View *view,
* - area is used always (ev. set it to event->area)
* - event is only used when is_expose
*/
-void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
+void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., %d, %d, %d * %d",
area->x, area->y, area->width, area->height);
+
+ OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop ();
int xWidget = line->textOffset;
int yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
@@ -1541,13 +1472,15 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)",
line->firstWord, line->lastWord, words->size (),
xWidget, yWidgetBase);
- DBG_MSG_WORD ("draw", 0, "<i>line starts with: </i>", line->firstWord, "");
- DBG_MSG_WORD ("draw", 0, "<i>line ends with: </i>", line->lastWord, "");
+ DBG_MSG_WORD ("draw", 1, "<i>line starts with: </i>", line->firstWord, "");
+ DBG_MSG_WORD ("draw", 1, "<i>line ends with: </i>", line->lastWord, "");
- for (int wordIndex = line->firstWord;
- wordIndex <= line->lastWord && xWidget < area->x + area->width;
- wordIndex++) {
- Word *word = words->getRef(wordIndex);
+ if (osi->index < line->firstWord)
+ osi->index = line->firstWord;
+
+ while (*interruptedWidget == NULL && osi->index <= line->lastWord
+ && xWidget < area->x + area->width) {
+ Word *word = words->getRef (osi->index);
int wordSize = word->size.width;
if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) {
@@ -1558,45 +1491,51 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
if (word->content.type == core::Content::WIDGET_IN_FLOW) {
core::Widget *child = word->content.widget;
core::Rectangle childArea;
-
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (child) &&
+ child->intersects (area, &childArea))
+ child->drawTotal (view, &childArea, iteratorStack,
+ interruptedWidget);
} else {
- int wordIndex2 = wordIndex;
+ int wordIndex2 = osi->index;
while (wordIndex2 < line->lastWord &&
(words->getRef(wordIndex2)->flags
& Word::DRAW_AS_ONE_TEXT) &&
word->style == words->getRef(wordIndex2 + 1)->style)
wordIndex2++;
- drawWord(line, wordIndex, wordIndex2, view, area,
+ drawWord(line, osi->index, wordIndex2, view, area,
xWidget, yWidgetBase);
wordSize = 0;
- for (int i = wordIndex; i <= wordIndex2; i++)
+ for (int i = osi->index; i <= wordIndex2; i++)
wordSize += words->getRef(i)->size.width;
- wordIndex = wordIndex2;
- word = words->getRef(wordIndex);
+ osi->index = wordIndex2;
+ word = words->getRef (osi->index);
}
}
- if (word->effSpace > 0 && wordIndex < line->lastWord &&
- words->getRef(wordIndex + 1)->content.type !=
+ if (word->effSpace > 0 && osi->index < line->lastWord &&
+ words->getRef(osi->index + 1)->content.type !=
core::Content::BREAK) {
if (word->spaceStyle->hasBackground ())
drawBox (view, word->spaceStyle, area,
xWidget + wordSize,
yWidgetBase - line->borderAscent, word->effSpace,
line->borderAscent + line->borderDescent, false);
- drawSpace(wordIndex, view, area, xWidget + wordSize,
- yWidgetBase);
+ drawSpace (osi->index, view, area, xWidget + wordSize,
+ yWidgetBase);
}
}
}
xWidget += wordSize + word->effSpace;
+
+ if (*interruptedWidget == NULL)
+ osi->index++;
}
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
DBG_OBJ_LEAVE ();
}
@@ -1618,7 +1557,8 @@ int Textblock::findLineIndexWhenNotAllocated (int y)
return
findLineIndex (y, calcVerticalBorder (getStyle()->padding.top,
getStyle()->borderWidth.top,
- getStyle()->margin.top,
+ getStyle()->margin.top
+ + extraSpace.top,
lines->getRef(0)->borderAscent,
lines->getRef(0)->marginAscent));
}
@@ -1764,38 +1704,97 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
return NULL;
}
-void Textblock::draw (core::View *view, core::Rectangle *area)
+void Textblock::drawLevel (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel)
{
- DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
- area->x, area->y, area->width, area->height);
-
- 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);
+ DBG_OBJ_ENTER ("draw", 0, "Textblock/drawLevel", "(%d, %d, %d * %d), %s",
+ area->x, area->y, area->width, area->height,
+ OOFStackingIterator::majorLevelText (majorLevel));
- lineIndex = findLineIndexWhenAllocated (area->y);
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ // Osi->index (word index) is regarded in drawLine.
+ for (int lineIndex = findLineIndexWhenAllocated (area->y);
+ *interruptedWidget == NULL && lineIndex < lines->size ();
+ lineIndex++) {
+ Line *line = lines->getRef (lineIndex);
+ if (lineYOffsetWidget (line) >= area->y + area->height)
+ break;
+
+ DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
+ drawLine (line, view, area, iteratorStack, interruptedWidget);
+ }
+ break;
- for (; lineIndex < lines->size (); lineIndex++) {
- line = lines->getRef (lineIndex);
- if (lineYOffsetWidget (line) >= area->y + area->height)
- break;
+ case OOFStackingIterator::OOF_REF:
+ handleOOFReferences (iteratorStack, interruptedWidget, false);
+ break;
- DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
- drawLine (line, view, area);
+ default:
+ OOFAwareWidget::drawLevel (view, area, iteratorStack, interruptedWidget,
+ majorLevel);
+ break;
}
- if(outOfFlowMgr)
- outOfFlowMgr->draw(view, area);
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+}
+/**
+ * \brief Used both for drawing and getting the widget at a point,
+ * since this method only interrupts, but does not do actual
+ * drawing or searching, respectively.
+ */
+void Textblock::handleOOFReferences (core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, bool backwards)
+{
+ // TODO Inefficient. Store Widgets OOF references in seperate list?
+
+ DBG_OBJ_ENTER ("common", 0, "Textblock/handleOOFReferences", "..., %s",
+ backwards ? "true [backwards]" : "false [forwards]");
+
+ OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop ();
+ assert (osi->majorLevel == OOFStackingIterator::OOF_REF);
+
+ while (*interruptedWidget == NULL &&
+ (backwards ? (osi->minorLevel >= 0) : (osi->minorLevel < NUM_OOFM))) {
+ while (*interruptedWidget == NULL &&
+ (backwards ? (osi->index >= 0) : (osi->index < words->size ()))) {
+
+ //DBG_IF_RTFL {
+ // misc::StringBuffer sb;
+ // osi->intoStringBuffer (&sb);
+ // DBG_OBJ_MSGF ("common", 2, "osi = %s",
+ // sb.getChars ());
+ //}
+
+ Word *word = words->getRef (osi->index);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ getOOFMIndex (word->content.widget) == osi->minorLevel &&
+ doesWidgetOOFInterruptDrawing (word->content.widget))
+ *interruptedWidget = word->content.widget;
+
+ // The index is increased in any case: the iterator must
+ // point to the next element.
+ if (backwards)
+ osi->index--;
+ else
+ osi->index++;
+ }
+
+ if (*interruptedWidget == NULL) {
+ if (backwards) {
+ osi->minorLevel--;
+ osi->index = words->size () - 1;
+ } else {
+ osi->minorLevel++;
+ osi->index = 0;
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("common", 1, "=> %p", *interruptedWidget);
DBG_OBJ_LEAVE ();
}
@@ -2356,21 +2355,23 @@ 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 (testWidgetOutOfFlow (widget)) {
+ int oofmIndex = getOOFMIndex (widget);
+ widget->setParent (oofContainer[oofmIndex]);
+ widget->setGenerator (this);
- if (OutOfFlowMgr::isWidgetOutOfFlow (widget)) {
- PRINTF (" -> out of flow.\n");
+ 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);
- widget->setParent (containingBlock);
- widget->setGenerator (this);
- containingBlock->outOfFlowMgr->addWidgetOOF (widget, this,
- words->size ());
Word *word = addWord (0, 0, 0, 0, style);
word->content.type = core::Content::WIDGET_OOF_REF;
word->content.widget = widget;
@@ -2379,14 +2380,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;
widget->sizeRequest (&size);
@@ -2624,7 +2627,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;
@@ -2635,7 +2638,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 =
@@ -2644,8 +2647,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;
}
}
@@ -2744,60 +2746,74 @@ void Textblock::breakAdded ()
words->getRef(words->size () - 2)->effSpace = 0;
}
-/**
- * \brief Search recursively through widget.
- *
- * This is an optimized version of the general
- * dw::core::Widget::getWidgetAtPoint method.
- */
-core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
-{
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
- int lineIndex, wordIndex;
- Line *line;
-
- if (x < allocation.x ||
- y < allocation.y ||
- x > allocation.x + allocation.width ||
- y > allocation.y + getHeight ()) {
- return NULL;
- }
-
- // First, search for widgets out of flow, notably floats, since
- // there are cases where they overlap child textblocks. Should
- // later be refined using z-index.
- Widget *oofWidget =
- outOfFlowMgr ? outOfFlowMgr->getWidgetAtPoint (x, y, level) : NULL;
- if (oofWidget)
- return oofWidget;
+core::Widget *Textblock::getWidgetAtPointLevel (int x, int y,
+ core::StackingIteratorStack
+ *iteratorStack,
+ Widget **interruptedWidget,
+ int majorLevel)
+{
+ DBG_OBJ_ENTER ("events", 0, "Textblock/getWidgetAtPointLevel", "%d, %d, %s",
+ x, y, OOFStackingIterator::majorLevelText (majorLevel));
+
+ Widget *widgetAtPoint = NULL;
+
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ {
+ OOFStackingIterator *osi =
+ (OOFStackingIterator*)iteratorStack->getTop ();
+
+ int lineIndex = findLineIndexWhenAllocated (y - allocation.y);
+
+ if (lineIndex >= 0 && lineIndex < lines->size ()) {
+ Line *line = lines->getRef (lineIndex);
+ if (osi->index > line->lastWord)
+ osi->index = line->lastWord;
+
+ while (widgetAtPoint == NULL && *interruptedWidget == NULL &&
+ osi->index >= 0) {
+ Word *word = words->getRef (osi->index);
+ if (word->content.type == core::Content::WIDGET_IN_FLOW &&
+ !core::StackingContextMgr::handledByStackingContextMgr
+ (word->content.widget))
+ widgetAtPoint = word->content.widget
+ ->getWidgetAtPointTotal (x, y, iteratorStack,
+ interruptedWidget);
+ if (*interruptedWidget == NULL)
+ osi->index--;
+ }
+ }
+ }
+ break;
- lineIndex = findLineIndexWhenAllocated (y - allocation.y);
+ case OOFStackingIterator::OOF_REF:
+ handleOOFReferences (iteratorStack, interruptedWidget, true);
+ // No searching, only interruption.
+ break;
- if (lineIndex < 0 || lineIndex >= lines->size ()) {
- return this;
+ default:
+ widgetAtPoint =
+ OOFAwareWidget::getWidgetAtPointLevel (x, y, iteratorStack,
+ interruptedWidget, majorLevel);
+ break;
}
- line = lines->getRef (lineIndex);
-
- for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
- Word *word = words->getRef (wordIndex);
+ DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)",
+ widgetAtPoint, *interruptedWidget);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
- 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;
- }
- }
- }
- }
+int Textblock::getLastLevelIndex (int majorLevel, int minorLevel)
+{
+ switch (majorLevel) {
+ case OOFStackingIterator::IN_FLOW:
+ case OOFStackingIterator::OOF_REF:
+ return words->size () - 1;
- return this;
+ default:
+ return OOFAwareWidget::getLastLevelIndex (majorLevel, minorLevel);
+ }
}
@@ -2901,6 +2917,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);
@@ -2922,24 +2940,12 @@ void Textblock::queueDrawRange (int index1, int index2)
queueDrawArea (0, y, allocation.width, h);
}
-}
-
-void Textblock::setVerticalOffset (int verticalOffset)
-{
- DBG_OBJ_ENTER ("resize", 0, "setVerticalOffset", "%d", verticalOffset);
-
- if (this->verticalOffset != verticalOffset) {
- this->verticalOffset = verticalOffset;
- DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
- mustQueueResize = true;
- queueDraw (); // Could perhaps be optimized.
- }
DBG_OBJ_LEAVE ();
}
/**
- * 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
@@ -3068,7 +3074,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)
@@ -3104,7 +3110,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 ();
@@ -3112,6 +3118,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,16 +3165,10 @@ Textblock *Textblock::getTextblockForLine (int firstWord, int lastWord)
if (word->content.type == core::Content::WIDGET_IN_FLOW) {
Widget *widget = word->content.widget;
if (widget->instanceOf (Textblock::CLASS_ID) &&
- // Exclude some cases where a textblock constitutes a new
- // container (see definition of float container in
- // Textblock::isContainingBlock).
- widget->getStyle()->display != core::style::DISPLAY_INLINE_BLOCK &&
- widget->getStyle()->overflow == core::style::OVERFLOW_VISIBLE)
+ // Exclude cases where a textblock constitutes a new floats
+ // container.
+ !isOOFContainer (widget, OOFM_FLOATS))
textblock = (Textblock*)widget;
-
- // (TODO: It would look nicer if there is one common place
- // for such definitions. Will be fixed in "dillo_grows", not
- // here.)
}
}
@@ -3185,18 +3200,17 @@ int Textblock::yOffsetOfLineToBeCreated ()
int result;
if (lines->size () == 0) {
- result = verticalOffset + calcVerticalBorder (getStyle()->padding.top,
- getStyle()->borderWidth.top,
- getStyle()->margin.top,
- 0, 0);
+ result = calcVerticalBorder (getStyle()->padding.top,
+ getStyle()->borderWidth.top + extraSpace.top,
+ getStyle()->margin.top, 0, 0);
DBG_OBJ_MSGF ("line.yoffset", 1, "first line: ... = %d", result);
} else {
Line *firstLine = lines->getRef (0), *lastLine = lines->getLastRef ();
- result = verticalOffset + calcVerticalBorder (getStyle()->padding.top,
- getStyle()->borderWidth.top,
- getStyle()->margin.top,
- firstLine->borderAscent,
- firstLine->marginAscent)
+ result = calcVerticalBorder (getStyle()->padding.top,
+ getStyle()->borderWidth.top,
+ getStyle()->margin.top + extraSpace.top,
+ firstLine->borderAscent,
+ firstLine->marginAscent)
- firstLine->borderAscent + lastLine->top + lastLine->totalHeight (0);
DBG_OBJ_MSGF ("line.yoffset", 1, "other line: ... = %d", result);
}
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 4bc74669..4a8290a8 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.
@@ -24,10 +23,9 @@ namespace dw {
*
* <div style="border: 2px solid #ffff00; margin-top: 0.5em;
* margin-bottom: 0.5em; padding: 0.5em 1em; background-color:
- * #ffffe0"><b>Info:</b> The recent changes (line breaking and
- * hyphenation on one hand, floats on the other hand) have not yet
- * been incorporated into this documentation. See \ref
- * dw-line-breaking and \ref dw-out-of-flow.</div>
+ * #ffffe0"><b>Info:</b> Some (not so) recent changes, line breaking
+ * and hyphenation, have not yet been incorporated into this
+ * documentation. See \ref dw-line-breaking.</div>
*
* <h3>Signals</h3>
*
@@ -164,11 +162,11 @@ namespace dw {
* Anchors associate the anchor name with the index of the next word at
* the point of the anchor.
*
- * <h4>Incremental Resizing</h4>
+ * <h3>Incremental Resizing</h3>
*
* dw::Textblock makes use of incremental resizing as described in \ref
* dw-widget-sizes. The parentRef is, for children of a dw::Textblock, simply
- * the number of the line.
+ * the number of the line. [<b>Update:</b> Incorrect; see \ref dw-out-of-flow.]
*
* Generally, there are three cases which may change the size of the
* widget:
@@ -195,8 +193,14 @@ namespace dw {
* dw::Textblock, which has the value -1 if no rewrapping of lines
* necessary, or otherwise the line from which a rewrap is necessary.
*
+ * <h3>Widgets Ouf Of Flow</h3>
+ *
+ * See
+ *
+ * - dw::oof::OOFAwareWidget (base class) and
+ * - \ref dw-out-of-flow.
*/
-class Textblock: public core::Widget
+class Textblock: public oof::OOFAwareWidget
{
private:
/**
@@ -290,10 +294,8 @@ private:
static const char *hyphenDrawChar;
- Textblock *containingBlock;
- OutOfFlowMgr *outOfFlowMgr;
-
protected:
+
/**
* \brief Implementation used for words.
*/
@@ -505,27 +507,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;
@@ -583,9 +582,6 @@ protected:
/* This value is (currently) set by setAscent(). */
int lineBreakWidth;
- // Additional vertical offset, used for the "clear" attribute.
- int verticalOffset;
-
int wrapRefLines, wrapRefParagraphs; /* 0-based. Important: Both
are the line numbers, not
the value stored in
@@ -635,7 +631,6 @@ protected:
void calcBorders (int lastOofRef, int height);
void showMissingLines ();
void removeTemporaryLines ();
- void setVerticalOffset (int verticalOffset);
void decorateText (core::View *view, core::style::Style *style,
core::style::Color::Shading shading,
@@ -652,7 +647,12 @@ protected:
core::Rectangle *area, int xWidget, int yWidgetBase);
void drawSpace (int wordIndex, core::View *view, core::Rectangle *area,
int xWidget, int yWidgetBase);
- void drawLine (Line *line, core::View *view, core::Rectangle *area);
+ void drawLine (Line *line, core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ void handleOOFReferences (core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, bool backwards);
+
int findLineIndex (int y);
int findLineIndexWhenNotAllocated (int y);
int findLineIndexWhenAllocated (int y);
@@ -772,6 +772,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,
@@ -806,10 +807,24 @@ protected:
void alignLine (int lineIndex);
void calcTextOffset (int lineIndex, int totalWidth);
+ void drawLevel (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel);
+
+ Widget *getWidgetAtPointLevel (int x, int y,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget, int majorLevel);
+ int getLastLevelIndex (int majorLevel, int minorLevel);
+
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 ();
@@ -818,13 +833,8 @@ protected:
void markSizeChange (int ref);
void markExtremesChange (int ref);
- void notifySetAsTopLevel();
- void notifySetParent();
-
bool isBlockLevel ();
- void draw (core::View *view, core::Rectangle *area);
-
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
bool motionNotifyImpl (core::EventMotion *event);
@@ -839,17 +849,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;
}
@@ -864,8 +880,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);
@@ -874,8 +890,6 @@ public:
void addText (const char *text, size_t len, core::style::Style *style);
inline void addText (const char *text, core::style::Style *style)
{ addText (text, strlen(text), style); }
- static bool isStyleOutOfFlow (core::style::Style *style)
- { return OutOfFlowMgr::isStyleOutOfFlow (style); }
void addWidget (core::Widget *widget, core::style::Style *style);
bool addAnchor (const char *name, core::style::Style *style);
void addSpace (core::style::Style *style);
@@ -883,7 +897,6 @@ public:
void addParbreak (int space, core::style::Style *style);
void addLinebreak (core::style::Style *style);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
void handOverBreak (core::style::Style *style);
void changeLinkColor (int link, int newColor);
void changeWordStyle (int from, int to, core::style::Style *style,
@@ -892,7 +905,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 b6423a29..95e2ce65 100644
--- a/dw/textblock_iterator.cc
+++ b/dw/textblock_iterator.cc
@@ -33,173 +33,48 @@ namespace dw {
Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
core::Content::Type mask,
bool atEnd):
- core::Iterator (textblock, mask, atEnd)
+ OOFAwareWidgetIterator (textblock, mask, atEnd, textblock->words->size ())
{
- if (atEnd) {
- if (textblock->outOfFlowMgr) {
- oofm = true;
- index = textblock->outOfFlowMgr->getNumWidgets();
- } else {
- oofm = false;
- index = textblock->words->size();
- }
- } else {
- oofm = false;
- index = -1;
- }
-
- content.type = atEnd ? core::Content::END : core::Content::START;
}
-Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
- core::Content::Type mask,
- bool oofm, int index):
- core::Iterator (textblock, mask, false)
+Textblock::TextblockIterator
+ *Textblock::TextblockIterator::createWordIndexIterator (Textblock *textblock,
+ core::Content::Type
+ mask,
+ int wordIndex)
{
- this->oofm = oofm;
- this->index = index;
-
- // TODO To be completely exact, oofm should be considered here.
- if (index < 0)
- content.type = core::Content::START;
- else if (index >= textblock->words->size())
- content.type = core::Content::END;
- else
- content = textblock->words->getRef(index)->content;
+ TextblockIterator *tbIt = new TextblockIterator (textblock, mask, false);
+ tbIt->setValues (0, wordIndex);
+ return tbIt;
}
object::Object *Textblock::TextblockIterator::clone()
{
- return
- new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index);
-}
-
-int Textblock::TextblockIterator::compareTo(object::Comparable *other)
-{
- TextblockIterator *otherTI = (TextblockIterator*)other;
-
- if (oofm && !otherTI->oofm)
- return +1;
- else if (!oofm && otherTI->oofm)
- return -1;
- else
- return index - otherTI->index;
-}
-
-bool Textblock::TextblockIterator::next ()
-{
- Textblock *textblock = (Textblock*)getWidget();
-
- if (content.type == core::Content::END)
- return false;
-
- short type;
-
- do {
- index++;
-
- if (oofm) {
- // Iterating over OOFM.
- if (index >= textblock->outOfFlowMgr->getNumWidgets()) {
- // End of OOFM list reached.
- content.type = core::Content::END;
- return false;
- }
- type = core::Content::WIDGET_OOF_CONT;
- } else {
- // Iterating over words list.
- if (index < textblock->words->size ())
- // Still words left.
- type = textblock->words->getRef(index)->content.type;
- else {
- // End of words list reached.
- if (textblock->outOfFlowMgr) {
- oofm = true;
- index = 0;
- if (textblock->outOfFlowMgr->getNumWidgets() > 0)
- // Start with OOFM widgets.
- type = core::Content::WIDGET_OOF_CONT;
- else {
- // No OOFM widgets (number is 0).
- content.type = core::Content::END;
- return false;
- }
- } else {
- // No OOFM widgets (no OOFM agt all).
- content.type = core::Content::END;
- return false;
- }
- }
- }
- } while ((type & getMask()) == 0);
-
- if (oofm) {
- content.type = core::Content::WIDGET_OOF_CONT;
- content.widget = textblock->outOfFlowMgr->getWidget (index);
- } else
- content = textblock->words->getRef(index)->content;
-
- return true;
-}
-
-bool Textblock::TextblockIterator::prev ()
-{
- Textblock *textblock = (Textblock*)getWidget();
-
- if (content.type == core::Content::START)
- return false;
-
- short type;
-
- do {
- index--;
-
- if (oofm) {
- // Iterating over OOFM.
- if (index >= 0)
- // Still widgets left.
- type = core::Content::WIDGET_OOF_CONT;
- else {
- // Beginning of OOFM list reached. Continue with words.
- oofm = false;
- index = textblock->words->size() - 1;
- if (index < 0) {
- // There are no words. (Actually, this case should not
- // happen: When there are OOF widgets, ther must be OOF
- // references, or widgets in flow, which contain
- // references.
- content.type = core::Content::END;
- return false;
- }
- type = textblock->words->getRef(index)->content.type;
- }
- } else {
- // Iterating over words list.
- if (index < 0) {
- // Beginning of words list reached.
- content.type = core::Content::START;
- return false;
- }
- type = textblock->words->getRef(index)->content.type;
- }
- } while ((type & getMask()) == 0);
-
- if (oofm) {
- content.type = core::Content::WIDGET_OOF_CONT;
- content.type = false;
- content.widget = textblock->outOfFlowMgr->getWidget (index);
- } else
- content = textblock->words->getRef(index)->content;
-
- return true;
+ TextblockIterator *tbIt =
+ new TextblockIterator ((Textblock*)getWidget(), getMask(), false);
+ cloneValues (tbIt);
+ return tbIt;
}
void Textblock::TextblockIterator::highlight (int start, int end,
core::HighlightLayer layer)
{
- if (!oofm) {
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget (), "TextblockIterator/highlight",
+ "..., %d, %d, %d", start, end, layer);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s",
+ sb.getChars ());
+ }
+
+ if (inFlow ()) {
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d",
+ getInFlowIndex ());
+
Textblock *textblock = (Textblock*)getWidget();
- int index1 = index, index2 = index;
+ int index = getInFlowIndex (), index1 = index, index2 = index;
int oldStartIndex = textblock->hlStart[layer].index;
int oldStartChar = textblock->hlStart[layer].nChar;
@@ -224,22 +99,46 @@ void Textblock::TextblockIterator::highlight (int start, int end,
textblock->hlEnd[layer].nChar = end;
}
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index",
+ textblock->hlStart[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar",
+ textblock->hlStart[layer].nChar);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index",
+ textblock->hlEnd[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar",
+ textblock->hlEnd[layer].nChar);
+
if (oldStartIndex != textblock->hlStart[layer].index ||
oldStartChar != textblock->hlStart[layer].nChar ||
oldEndIndex != textblock->hlEnd[layer].index ||
oldEndChar != textblock->hlEnd[layer].nChar)
textblock->queueDrawRange (index1, index2);
- }
+ } else
+ highlightOOF (start, end, layer);
- // TODO What about OOF widgets?
+ DBG_OBJ_LEAVE_O (getWidget ());
}
void Textblock::TextblockIterator::unhighlight (int direction,
core::HighlightLayer layer)
{
- if (!oofm) {
+ DBG_OBJ_ENTER_O ("iterator", 0, getWidget (),
+ "TextblockIterator/unhighlight", "..., %d, %d",
+ direction, layer);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ intoStringBuffer (&sb);
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s",
+ sb.getChars ());
+ }
+
+ if (inFlow ()) {
+ DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d",
+ getInFlowIndex ());
+
Textblock *textblock = (Textblock*)getWidget();
- int index1 = index, index2 = index;
+ int index = getInFlowIndex (), index1 = index, index2 = index;
if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index)
return;
@@ -264,26 +163,33 @@ void Textblock::TextblockIterator::unhighlight (int direction,
textblock->hlEnd[layer].nChar = INT_MAX;
}
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index",
+ textblock->hlStart[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar",
+ textblock->hlStart[layer].nChar);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index",
+ textblock->hlEnd[layer].index);
+ DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar",
+ textblock->hlEnd[layer].nChar);
+
if (oldStartIndex != textblock->hlStart[layer].index ||
oldStartChar != textblock->hlStart[layer].nChar ||
oldEndIndex != textblock->hlEnd[layer].index ||
oldEndChar != textblock->hlEnd[layer].nChar)
textblock->queueDrawRange (index1, index2);
- }
+ } else
+ unhighlightOOF (direction, layer);
- // TODO What about OOF widgets?
+ DBG_OBJ_LEAVE_O (getWidget ());
}
void Textblock::TextblockIterator::getAllocation (int start, int end,
core::Allocation *allocation)
{
- Textblock *textblock = (Textblock*)getWidget();
+ if (inFlow ()) {
+ Textblock *textblock = (Textblock*)getWidget();
- if (oofm) {
- // TODO Consider start and end?
- *allocation =
- *(textblock->outOfFlowMgr->getWidget(index)->getAllocation());
- } else {
+ int index = getInFlowIndex ();
Word *word = textblock->words->getRef (index);
int firstWordOfLine, textOffset, lineYOffsetCanvas, lineBorderAscent;
@@ -360,14 +266,19 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
}
allocation->ascent = word->size.ascent;
allocation->descent = word->size.descent;
- }
+ } else
+ getAllocationOOF (start, end, allocation);
}
-void Textblock::TextblockIterator::print ()
+int Textblock::TextblockIterator::numContentsInFlow ()
{
- Iterator::print ();
- printf (", oofm = %s, index = %d", oofm ? "true" : "false", index);
+ return ((Textblock*)getWidget())->words->size ();
+}
+void Textblock::TextblockIterator::getContentInFlow (int index,
+ core::Content *content)
+{
+ *content = ((Textblock*)getWidget())->words->getRef(index)->content;
}
} // namespace dw
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index 38d325bc..5cc6ad65 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -591,7 +591,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);
@@ -754,14 +754,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);
@@ -772,10 +773,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,
@@ -841,8 +849,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
firstWordWithoutLine = lines->getLastRef()->lastWord + 1;
if (wordIndex >= firstWordWithoutLine) {
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lines->size ());
+ word->content.widget->parentRef = makeParentRefInFlow (lines->size ());
DBG_OBJ_SET_NUM_O (word->content.widget, "parentRef",
word->content.widget->parentRef);
}
@@ -853,6 +860,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 = yOffsetOfLineToBeCreated ();
+
+ // 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,
@@ -1434,8 +1464,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);
@@ -1507,8 +1538,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
borderDescent =
marginDescent - word->content.widget->getStyle()->margin.bottom;
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lineIndex);
+ word->content.widget->parentRef = makeParentRefInFlow (lineIndex);
DBG_OBJ_SET_NUM_O (word->content.widget, "parentRef",
word->content.widget->parentRef);
} else {
@@ -1634,8 +1664,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;
@@ -1647,8 +1676,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);
@@ -1922,17 +1951,6 @@ void Textblock::initNewLine ()
{
DBG_OBJ_ENTER0 ("construct.line", 0, "initNewLine");
- // At the very beginning, in Textblock::Textblock, where this
- // method is called, containingBlock is not yet defined.
-
- if (containingBlock && containingBlock->outOfFlowMgr) {
- if (lines->size () == 0) {
- int clearPosition =
- containingBlock->outOfFlowMgr->getClearPosition (this);
- setVerticalOffset (misc::max (clearPosition, 0));
- }
- }
-
calcBorders (lines->size() > 0 ?
lines->getLastRef()->lastOofRefPositionedBeforeThisLine : -1,
1);
@@ -1950,81 +1968,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 = yOffsetOfLineToBeCreated ();
-
- newLineHasFloatLeft =
- containingBlock->outOfFlowMgr->hasFloatLeft (this, y, height, this,
- effOofRef);
- newLineHasFloatRight =
- containingBlock->outOfFlowMgr->hasFloatRight (this, y, height, this,
- effOofRef);
- newLineLeftBorder =
- containingBlock->outOfFlowMgr->getLeftBorder (this, y, height, this,
- effOofRef);
- newLineRightBorder =
- containingBlock->outOfFlowMgr->getRightBorder (this, y, height, this,
- effOofRef);
- newLineLeftFloatHeight = newLineHasFloatLeft ?
- containingBlock->outOfFlowMgr->getLeftFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
- newLineRightFloatHeight = newLineHasFloatRight ?
- containingBlock->outOfFlowMgr->getRightFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
-
- DBG_OBJ_MSGF ("construct.line", 1,
- "%d * %d (%s) / %d * %d (%s), at %d (%d), until %d = "
- "max (%d, %d - 1)",
- newLineLeftBorder, newLineLeftFloatHeight,
- newLineHasFloatLeft ? "true" : "false",
- newLineRightBorder, newLineRightFloatHeight,
- newLineHasFloatRight ? "true" : "false",
- y, height, effOofRef, lastOofRef, firstWordOfLine);
- } else {
- newLineHasFloatLeft = newLineHasFloatRight = false;
- newLineLeftBorder = newLineRightBorder = 0;
- newLineLeftFloatHeight = newLineRightFloatHeight = 0;
-
- DBG_OBJ_MSG ("construct.line", 0, "<i>no CB of OOFM</i>");
+
+ 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/ui.cc b/dw/ui.cc
index 67e3fabc..2aed65de 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -128,7 +128,9 @@ void Embed::setEnabled (bool enabled)
resource->setEnabled (enabled);
}
-void Embed::draw (View *view, Rectangle *area)
+void Embed::draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
drawWidgetBox (view, area, false);
resource->draw (view, area);
diff --git a/dw/ui.hh b/dw/ui.hh
index 6703ccca..1ff896f5 100644
--- a/dw/ui.hh
+++ b/dw/ui.hh
@@ -253,7 +253,8 @@ public:
void setDisplayed (bool displayed);
void setEnabled (bool enabled);
- void draw (View *view, Rectangle *area);
+ void draw (View *view, Rectangle *area, StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
Iterator *iterator (Content::Type mask, bool atEnd);
void setStyle (style::Style *style);
diff --git a/dw/widget.cc b/dw/widget.cc
index ed2c2b8e..c02b007f 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,25 +130,218 @@ Widget::~Widget ()
*/
bool Widget::intersects (Rectangle *area, Rectangle *intersection)
{
- Rectangle parentArea, childArea;
+ DBG_OBJ_ENTER ("draw", 0, "intersects", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ bool r;
+
+ if (wasAllocated ()) {
+ Rectangle parentArea, childArea;
+
+ parentArea = *area;
+ parentArea.x += parent->allocation.x;
+ parentArea.y += parent->allocation.y;
+
+ DBG_OBJ_MSGF ("draw", 2, "parentArea: %d, %d, %d * %d",
+ parentArea.x, parentArea.y, parentArea.width,
+ parentArea.height);
+
+ childArea.x = allocation.x;
+ childArea.y = allocation.y;
+ childArea.width = allocation.width;
+ childArea.height = getHeight ();
+
+ DBG_OBJ_MSGF ("draw", 2, "childArea: %d, %d, %d * %d",
+ childArea.x, childArea.y, childArea.width,
+ childArea.height);
+
+ if (parentArea.intersectsWith (&childArea, intersection)) {
+ DBG_OBJ_MSGF ("draw", 2, "intersection: %d, %d, %d * %d",
+ intersection->x, intersection->y, intersection->width,
+ intersection->height);
+
+ intersection->x -= allocation.x;
+ intersection->y -= allocation.y;
+ r = true;
+
+ DBG_OBJ_MSGF ("draw", 1, "=> %d, %d, %d * %d",
+ intersection->x, intersection->y, intersection->width,
+ intersection->height);
+ } else {
+ r = false;
+ DBG_OBJ_MSG ("draw", 1, "=> no intersection");
+ }
+ } else {
+ r = false;
+ DBG_OBJ_MSG ("draw", 1, "=> not allocated");
+ }
+
+ DBG_OBJ_LEAVE ();
+ return r;
+}
+
+void Widget::drawTotal (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ DBG_OBJ_ENTER ("draw", 0, "drawTotal", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "initial iteratorStack: %s", sb.getChars ());
+ }
+
+ Object *si = NULL;
+
+ if (iteratorStack->atRealTop ()) {
+ si = stackingIterator (false);
+ if (si) {
+ iteratorStack->push (si);
+ }
+ } else
+ iteratorStack->forward ();
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "iteratorStack before: %s",
+ sb.getChars ());
+ }
+
+ draw (view, area, iteratorStack, interruptedWidget);
+ DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "iteratorStack after: %s",
+ sb.getChars ());
+ }
+
+ // A value for *interruptedWidget other than NULL indicates a
+ // widget with a complex drawing process, for which
+ // stackingIterator() must return something non-NULL, so that the
+ // interrupted drawing process can be continued. (TODO: Not quite
+ // correct when forward() was called instead of push().)
+
+ // assert (*interruptedWidget == NULL || si != NULL);
+
+ if (*interruptedWidget == NULL) {
+ if (si)
+ iteratorStack->pop ();
+ } else
+ iteratorStack->backward ();
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "final iteratorStack: %s", sb.getChars ());
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::drawToplevel (View *view, Rectangle *area)
+{
+ assert (parent == NULL);
+
+ StackingIteratorStack iteratorStack;
+ Widget *interruptedWidget = NULL;
+ drawTotal (view, area, &iteratorStack, &interruptedWidget);
+
+ // Everything should be finished at this point.
+ assert (interruptedWidget == NULL);
+}
+
+Widget *Widget::getWidgetAtPoint (int x, int y,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ // Suitable for simple widgets, without children.
+
+ if (wasAllocated () && x >= allocation.x && y >= allocation.y &&
+ x <= allocation.x + allocation.width && y <= allocation.y + getHeight ())
+ return this;
+ else
+ return NULL;
+}
+
+Widget *Widget::getWidgetAtPointTotal (int x, int y,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTotal", "%d, %d", x, y);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2, "initial iteratorStack: %s", sb.getChars ());
+ }
+
+ Object *si = NULL;
+
+ if (iteratorStack->atRealTop ()) {
+ si = stackingIterator (true);
+ if (si) {
+ iteratorStack->push (si);
+ }
+ } else
+ iteratorStack->forward ();
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2, "iteratorStack before: %s",
+ sb.getChars ());
+ }
+
+ Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget);
+ DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", widget, *interruptedWidget);
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2, "iteratorStack after: %s",
+ sb.getChars ());
+ }
- parentArea = *area;
- parentArea.x += parent->allocation.x;
- parentArea.y += parent->allocation.y;
+ // See comment in drawTotal().
- childArea.x = allocation.x;
- childArea.y = allocation.y;
- childArea.width = allocation.width;
- childArea.height = getHeight ();
+ // assert (*interruptedWidget == NULL || si != NULL);
- if (parentArea.intersectsWith (&childArea, intersection)) {
- intersection->x -= allocation.x;
- intersection->y -= allocation.y;
- return true;
+ if (*interruptedWidget == NULL) {
+ if (si)
+ iteratorStack->pop ();
} else
- return false;
+ iteratorStack->backward ();
+
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("events", 2, "final iteratorStack: %s", sb.getChars ());
+ }
+
+ DBG_OBJ_LEAVE ();
+ return widget;
}
+Widget *Widget::getWidgetAtPointToplevel (int x, int y)
+{
+ assert (parent == NULL);
+
+ StackingIteratorStack iteratorStack;
+ Widget *interruptedWidget = NULL;
+ Widget *widget =
+ getWidgetAtPointTotal (x, y, &iteratorStack, &interruptedWidget);
+
+ // Everything should be finished at this point.
+ assert (interruptedWidget == NULL);
+
+ return widget;
+}
+
+
void Widget::setParent (Widget *parent)
{
this->parent = parent;
@@ -170,6 +368,18 @@ void Widget::setParent (Widget *parent)
// Textblock.
DBG_OBJ_SET_PTR ("container", container);
+ // If at all, stackingContextMgr should have set *before*, see also
+ // Widget::setStyle() and Layout::addWidget().
+ if (stackingContextMgr) {
+ Widget *stackingContextWidget = parent;
+ while (stackingContextWidget &&
+ stackingContextWidget->stackingContextMgr == NULL)
+ stackingContextWidget = stackingContextWidget->parent;
+ assert (stackingContextWidget);
+ stackingContextWidget->stackingContextMgr->addChildSCWidget (this);
+ } else
+ stackingContextWidget = parent->stackingContextWidget;
+
notifySetParent();
}
@@ -490,6 +700,7 @@ void Widget::sizeRequest (Requisition *requisition)
}
if (needsResize ()) {
+ calcExtraSpace ();
/** \todo Check requisition == &(this->requisition) and do what? */
sizeRequestImpl (requisition);
this->requisition = *requisition;
@@ -613,7 +824,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
@@ -894,6 +1105,8 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ calcExtraSpace ();
+
// For backward compatibility (part 1/2):
extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
@@ -923,6 +1136,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.
*/
@@ -1066,6 +1297,16 @@ void Widget::setStyle (style::Style *style)
layout->updateCursor ();
}
+ // After Layout::addWidget() (as toplevel widget) or Widget::setParent()
+ // (which also sets layout), changes of the style cannot be considered
+ // anymore. (Should print a warning?)
+ if (layout == NULL &&
+ StackingContextMgr::isEstablishingStackingContext (this)) {
+ stackingContextMgr = new StackingContextMgr (this);
+ DBG_OBJ_ASSOC_CHILD (stackingContextMgr);
+ stackingContextWidget = this;
+ }
+
if (sizeChanged)
queueResize (0, true);
else
@@ -1180,7 +1421,7 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area,
// TODO Handle inverse drawing the same way as in drawWidgetBox?
// Maybe this method (drawBox) is anyway obsolete when extraSpace
- // is fully supported (as in the "dillo_grows" repository).
+ // is fully supported (as here, in the "dillo_grows" repository).
int xPad, yPad, widthPad, heightPad;
getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
@@ -1210,8 +1451,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);
@@ -1347,53 +1590,6 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
return widget1;
}
-
-/**
- * \brief Search recursively through widget.
- *
- * Used by dw::core::Layout:getWidgetAtPoint.
- */
-Widget *Widget::getWidgetAtPoint (int x, int y, int level)
-{
- Iterator *it;
- Widget *childAtPoint;
-
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
- if (x >= allocation.x &&
- y >= allocation.y &&
- x <= allocation.x + allocation.width &&
- y <= allocation.y + getHeight ()) {
- //_MSG ("%*s -> inside\n", 3 * level, "");
- /*
- * Iterate over the children of this widget. Test recursively, whether
- * the point is within the child (or one of its children...). If there
- * is such a child, it is returned. Otherwise, this widget is returned.
- */
- childAtPoint = NULL;
- it = iterator ((Content::Type)
- (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
- false);
-
- while (childAtPoint == NULL && it->next ()) {
- Widget *child = it->getContent()->widget;
- if (child->wasAllocated ())
- childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
- }
-
- it->unref ();
-
- if (childAtPoint)
- return childAtPoint;
- else
- return this;
- } else
- return NULL;
-}
-
-
void Widget::scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height)
{
@@ -1401,6 +1597,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).
*
@@ -1410,18 +1624,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)
{
}
@@ -1734,6 +1961,11 @@ void Widget::leaveNotifyImpl (EventCrossing *)
tooltip->onLeave();
}
+lout::object::Object *Widget::stackingIterator (bool atEnd)
+{
+ return NULL;
+}
+
void Widget::removeChild (Widget *child)
{
// Should be implemented.
diff --git a/dw/widget.hh b/dw/widget.hh
index 0f3e2d37..1a1bf41e 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -180,19 +180,36 @@ protected:
Allocation allocation;
inline int getHeight () { return allocation.ascent + allocation.descent; }
- inline int getContentWidth() { return allocation.width
- - style->boxDiffWidth (); }
- inline int getContentHeight() { return getHeight ()
- - style->boxDiffHeight (); }
+ inline int getContentWidth() { return allocation.width - boxDiffWidth (); }
+ inline int getContentHeight() { return getHeight () - boxDiffHeight (); }
Layout *layout;
/**
* \brief Space around the margin box. Allocation is extraSpace +
- * margin + border + padding + contents;
+ * margin + border + padding + contents.
+ *
+ * See also dw::core::Widget::calcExtraSpace and
+ * dw::core::Widget::calcExtraSpaceImpl. Also, it is feasible to
+ * correct this value within dw::core::Widget::sizeRequestImpl.
*/
style::Box extraSpace;
+ /**
+ * \brief Set iff this widget constitutes a stacking context, as defined by
+ * CSS.
+ */
+ StackingContextMgr *stackingContextMgr;
+
+ /**
+ * \brief The bottom-most ancestor (or this) for which stackingContextMgr is
+ * set.
+ */
+ Widget *stackingContextWidget;
+
+ inline StackingContextMgr *getNextStackingContextMgr ()
+ { return stackingContextWidget->stackingContextMgr; }
+
/*inline void printFlags () {
DBG_IF_RTFL {
char buf[10 * 3 - 1 + 1];
@@ -254,7 +271,6 @@ protected:
inline void unsetFlags (Flags f)
{ flags = (Flags)(flags & ~f); printFlag (f); }
-
inline void queueDraw ()
{ queueDrawArea (0, 0, allocation.width, getHeight()); }
void queueDrawArea (int x, int y, int width, int height);
@@ -271,6 +287,8 @@ protected:
*/
virtual void getExtremesImpl (Extremes *extremes) = 0;
+ virtual void calcExtraSpaceImpl ();
+
/**
* \brief See \ref dw-widget-sizes.
*/
@@ -292,8 +310,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 +441,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 +459,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 ();
@@ -449,7 +469,21 @@ public:
bool intersects (Rectangle *area, Rectangle *intersection);
/** Area is given in widget coordinates. */
- virtual void draw (View *view, Rectangle *area) = 0;
+ virtual void draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget) = 0;
+ void drawTotal (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ void drawToplevel (View *view, Rectangle *area);
+
+ virtual Widget *getWidgetAtPoint (int x, int y,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ Widget *getWidgetAtPointTotal (int x, int y,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
+ Widget *getWidgetAtPointToplevel (int x, int y);
bool buttonPress (EventButton *event);
bool buttonRelease (EventButton *event);
@@ -480,11 +514,11 @@ public:
inline Layout *getLayout () { return layout; }
- virtual Widget *getWidgetAtPoint (int x, int y, int level);
-
void scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height);
+ void getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar);
+ void getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor);
void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad);
/**
@@ -501,6 +535,14 @@ public:
* dw::core::Iterator::prev in this case.
*/
virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+
+ /**
+ * \brief ...
+ *
+ * May return NULL.
+ */
+ virtual lout::object::Object *stackingIterator (bool atEnd);
+
virtual void removeChild (Widget *child);
};
diff --git a/lout/debug.hh b/lout/debug.hh
index e2839196..5c0169e3 100644
--- a/lout/debug.hh
+++ b/lout/debug.hh
@@ -29,359 +29,7 @@
# define DEBUG_MSG(level, ...)
# endif /* DEBUG_LEVEL */
-
-
-/*
- * See <http://home.gna.org/rtfl/>.
- */
-
-#ifdef DBG_RTFL
-
-#include <unistd.h>
-#include <stdio.h>
-
-#define DBG_IF_RTFL if(1)
-
-// "\n" at the beginning just in case that the previous line is not finished
-// yet.
-#define RTFL_PREFIX_FMT "\n[rtfl]%s:%d:%d:"
-#define RTFL_PREFIX_ARGS CUR_WORKING_DIR "/" __FILE__, __LINE__, getpid()
-
-#define DBG_OBJ_MSG(aspect, prio, msg) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, msg); \
- fflush (stdout); \
- } D_STMT_END
-
-// Variant which does not use "this", but an explicitly passed
-// object. Should be applied to other macros. (Also, for use in C.)
-#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, msg); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, __VA_ARGS__); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, __VA_ARGS__); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSG_START() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSG_START_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_MSG_END() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-// See DBG_OBJ_MSG_O.
-#define DBG_OBJ_MSG_END_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER0(aspect, prio, funname) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, funname); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, funname); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
- D_STMT_START { \
- fflush (stdout); \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
- RTFL_PREFIX_ARGS, this, aspect, prio, funname, __VA_ARGS__); \
- } D_STMT_END
-
-#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
- D_STMT_START { \
- fflush (stdout); \
- printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
- RTFL_PREFIX_ARGS, obj, aspect, prio, funname, __VA_ARGS__); \
- } D_STMT_END
-
-#define DBG_OBJ_LEAVE() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_LEAVE_O(obj) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
- RTFL_PREFIX_ARGS, obj); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_CREATE(klass) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-create:%p:%s\n", \
- RTFL_PREFIX_ARGS, this, klass); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_DELETE() \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-delete:%p\n", \
- RTFL_PREFIX_ARGS, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_BASECLASS(klass) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-ident:%p:%p\n", \
- RTFL_PREFIX_ARGS, this, (klass*)this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC(parent, child) \
- D_STMT_START { \
- if (child) { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, parent, child); \
- fflush (stdout); \
- } \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC_PARENT(parent) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, parent, this); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ASSOC_CHILD(child) \
- D_STMT_START { \
- if (child) { \
- printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
- RTFL_PREFIX_ARGS, this, child); \
- fflush (stdout); \
- } \
- } D_STMT_END
-
-#define DBG_OBJ_SET_NUM(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_NUM_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
- RTFL_PREFIX_ARGS, obj, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_SYM(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_STR(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_PTR(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_PTR_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
- RTFL_PREFIX_ARGS, obj, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_BOOL(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
- RTFL_PREFIX_ARGS, obj, var, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_SET_COL(var, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s:#%06x\n", \
- RTFL_PREFIX_ARGS, this, var, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%d\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_STR(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%p\n", \
- RTFL_PREFIX_ARGS, this, var, ind, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%d\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val ? "true" : "false"); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:\"%s\"\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%p\n", \
- RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
- fflush (stdout); \
- } D_STMT_END
-
-#define DBG_OBJ_COLOR(klass, color) \
- D_STMT_START { \
- printf (RTFL_PREFIX_FMT "obj-color:%s:%s\n", \
- RTFL_PREFIX_ARGS, color, klass); \
- fflush (stdout); \
- } D_STMT_END
-
-#else /* DBG_RTFL */
-
-#define DBG_IF_RTFL if(0)
-
-#define DBG_OBJ_MSG(aspect, prio, msg) D_STMT_NOP
-#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) D_STMT_NOP
-#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_MSG_START() D_STMT_NOP
-#define DBG_OBJ_MSG_START_O(obj) D_STMT_NOP
-#define DBG_OBJ_MSG_END() D_STMT_NOP
-#define DBG_OBJ_MSG_END_O(obj) D_STMT_NOP
-#define DBG_OBJ_ENTER0(aspect, prio, funname) D_STMT_NOP
-#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) D_STMT_NOP
-#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) D_STMT_NOP
-#define DBG_OBJ_LEAVE() D_STMT_NOP
-#define DBG_OBJ_LEAVE_O(obj) D_STMT_NOP
-#define DBG_OBJ_CREATE(klass) D_STMT_NOP
-#define DBG_OBJ_DELETE() D_STMT_NOP
-#define DBG_OBJ_BASECLASS(klass) D_STMT_NOP
-#define DBG_OBJ_ASSOC_PARENT(parent) D_STMT_NOP
-#define DBG_OBJ_ASSOC_CHILD(child) D_STMT_NOP
-#define DBG_OBJ_ASSOC(parent, child) D_STMT_NOP
-#define DBG_OBJ_SET_NUM(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_NUM_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_SYM(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_STR(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_PTR(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_PTR_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_BOOL(var, val) D_STMT_NOP
-#define DBG_OBJ_SET_BOOL_O(obj, var, val) D_STMT_NOP
-#define DBG_OBJ_SET_COL(var, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_NUM(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_SYM(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_STR(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_PTR(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRSET_BOOL(var, ind, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) D_STMT_NOP
-#define DBG_OBJ_COLOR(klass, color) D_STMT_NOP
-
-#endif /* DBG_RTFL */
+#include "debug_rtfl.hh"
#endif /* __LOUT_DEBUG_H__ */
diff --git a/lout/debug_rtfl.hh b/lout/debug_rtfl.hh
new file mode 100644
index 00000000..7a93b5ce
--- /dev/null
+++ b/lout/debug_rtfl.hh
@@ -0,0 +1,370 @@
+// WARNING: This file has been generated. Do not edit!
+
+/*
+ * This file is part of RTFL, see <http://home.gna.org/rtfl/>
+ * for details.
+ *
+ * This file (but not RTFL itself) is in the public domain, since it is only a
+ * simple implementation of a protocol, containing nothing more than trivial
+ * work. However, it would be nice to keep this notice, along with the URL
+ * above.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Defines macros for printing RTFL commands. See documentation for detail
+ * (online at <http://home.gna.org/rtfl/doc/rtfl.html>). These macros are only
+ * active, when the pre-processor variable DBG_RTFL is defined. If not,
+ * alternatives are defined, which have no effect.
+ *
+ * This variant assumes that __FILE__ is only the base of the source file name,
+ * so, to get the full path, CUR_WORKING_DIR has to be defined. See RTFL
+ * documentation for more details.
+ */
+
+#ifndef __DEBUG_RTFL_HH__
+#define __DEBUG_RTFL_HH__
+
+#ifdef DBG_RTFL
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define DBG_IF_RTFL if(1)
+
+#define STMT_START do
+#define STMT_END while (0)
+
+// Prints an RTFL message to stdout. "fmt" contains simple format
+// characters how to deal with the additional arguments (no "%"
+// preceeding, as in printf), or "c" (short for "#%06x" and used for
+// colors), or other characters, which are simply printed. No quoting:
+// this function cannot be used to print the characters "d", "p", and
+// "s" directly.
+
+inline void rtfl_print (const char *version, const char *file, int line,
+ const char *fmt, ...)
+{
+ // "\n" at the beginning just in case that the previous line is not
+ // finished yet.
+ printf ("\n[rtfl-%s]%s:%d:%d:", version, file, line, getpid ());
+
+ va_list args;
+ va_start (args, fmt);
+
+ for (int i = 0; fmt[i]; i++) {
+ int n;
+ void *p;
+ char *s;
+
+ switch (fmt[i]) {
+ case 'd':
+ n = va_arg(args, int);
+ printf ("%d", n);
+ break;
+
+ case 'p':
+ p = va_arg(args, void*);
+ printf ("%p", p);
+ break;
+
+ case 's':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ putchar (s[j]);
+ }
+ break;
+
+ case 'c':
+ n = va_arg(args, int);
+ printf ("#%06x", n);
+ break;
+
+ default:
+ putchar (fmt[i]);
+ break;
+ }
+ }
+
+ va_end (args);
+
+ putchar ('\n');
+ fflush (stdout);
+}
+
+#define RTFL_PRINT(version, cmd, fmt, ...) \
+ rtfl_print (version, CUR_WORKING_DIR "/" __FILE__, __LINE__, "s:" fmt, \
+ cmd, __VA_ARGS__)
+
+#define RTFL_OBJ_VERSION "1.0"
+
+#define RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT (RTFL_OBJ_VERSION, "obj-" cmd, fmt, __VA_ARGS__)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) \
+ DBG_OBJ_MSG_O (aspect, prio, this, msg)
+
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
+ RTFL_OBJ_PRINT ("msg", "p:s:d:s", obj, aspect, prio, msg)
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG (aspect, prio, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG_O (aspect, prio, obj, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MSG_START() \
+ DBG_OBJ_MSG_START_O (this)
+
+#define DBG_OBJ_MSG_START_O(obj) \
+ RTFL_OBJ_PRINT ("msg-start", "p", obj)
+
+#define DBG_OBJ_MSG_END() \
+ DBG_OBJ_MSG_END_O (this)
+
+#define DBG_OBJ_MSG_END_O(obj) \
+ RTFL_OBJ_PRINT ("msg-end", "p", obj)
+
+#define DBG_OBJ_ENTER0(aspect, prio, funname) \
+ DBG_OBJ_ENTER0_O (aspect, prio, this, funname)
+
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:", obj, aspect, prio, funname);
+
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", this, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", obj, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE() \
+ DBG_OBJ_LEAVE_O (this)
+
+#define DBG_OBJ_LEAVE_O(obj) \
+ RTFL_OBJ_PRINT ("leave", "p", obj);
+
+#define DBG_OBJ_CREATE(klass) \
+ DBG_OBJ_CREATE_O (this, klass)
+
+#define DBG_OBJ_CREATE_O(obj, klass) \
+ RTFL_OBJ_PRINT ("create", "p:s", obj, klass);
+
+#define DBG_OBJ_DELETE() \
+ DBG_OBJ_DELETE_O (this)
+
+#define DBG_OBJ_DELETE_O(obj) \
+ RTFL_OBJ_PRINT ("delete", "p", obj);
+
+#define DBG_OBJ_BASECLASS(klass) \
+ RTFL_OBJ_PRINT ("ident", "p:p", this, (klass*)this);
+
+#define DBG_OBJ_ASSOC(parent, child) \
+ RTFL_OBJ_PRINT ("assoc", "p:p", parent, child); \
+
+#define DBG_OBJ_ASSOC_PARENT(parent) \
+ DBG_OBJ_ASSOC (parent, this);
+
+#define DBG_OBJ_ASSOC_CHILD(child) \
+ DBG_OBJ_ASSOC (this, child);
+
+#define DBG_OBJ_SET_NUM(var, val) \
+ DBG_OBJ_SET_NUM_O (this, var, val)
+
+#define DBG_OBJ_SET_NUM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:d", obj, var, val)
+
+#define DBG_OBJ_SET_SYM(var, val) \
+ DBG_OBJ_SET_SYM_O (this, var, val)
+
+#define DBG_OBJ_SET_SYM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, val)
+
+#define DBG_OBJ_SET_BOOL(var, val) \
+ DBG_OBJ_SET_BOOL_O (this, var, val)
+
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, (val) ? "true" : "false")
+
+#define DBG_OBJ_SET_STR(var, val) \
+ DBG_OBJ_SET_STR_O (this, var, val)
+
+#define DBG_OBJ_SET_STR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:\"s\"", obj, var, val)
+
+#define DBG_OBJ_SET_PTR(var, val) \
+ DBG_OBJ_SET_PTR_O (this, var, val)
+
+#define DBG_OBJ_SET_PTR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:p", obj, var, val)
+
+#define DBG_OBJ_SET_COL(var, val) \
+ DBG_OBJ_SET_COL_O (this, var, val)
+
+#define DBG_OBJ_SET_COL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:c", obj, var, val)
+
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
+ DBG_OBJ_ARRSET_NUM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:d", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
+ DBG_OBJ_ARRSET_SYM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
+ DBG_OBJ_ARRSET_BOOL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRSET_STR(var, ind, val) \
+ DBG_OBJ_ARRSET_STR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:\"s\"", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
+ DBG_OBJ_ARRSET_PTR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:p", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL(var, ind, val) \
+ DBG_OBJ_ARRSET_COL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:c", obj, var, ind, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_NUM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:d", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_SYM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_BOOL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, \
+ (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_STR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:\"s\"", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_PTR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:p", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_COL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:c", obj, var, ind, attr, val)
+
+#define DBG_OBJ_CLASS_COLOR(klass, color) \
+ RTFL_OBJ_PRINT ("class-color", "s:s", klass, color)
+
+#else /* DBG_RTFL */
+
+#define STMT_NOP do { } while (0)
+
+#define DBG_IF_RTFL if(0)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) STMT_NOP
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) STMT_NOP
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSG_START() STMT_NOP
+#define DBG_OBJ_MSG_START_O(obj) STMT_NOP
+#define DBG_OBJ_MSG_END() STMT_NOP
+#define DBG_OBJ_MSG_END_O(obj) STMT_NOP
+#define DBG_OBJ_ENTER0(aspect, prio, funname) STMT_NOP
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) STMT_NOP
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE() STMT_NOP
+#define DBG_OBJ_LEAVE_O(obj) STMT_NOP
+#define DBG_OBJ_CREATE(klass) STMT_NOP
+#define DBG_OBJ_CREATE_O(obj, klass) STMT_NOP
+#define DBG_OBJ_DELETE() STMT_NOP
+#define DBG_OBJ_DELETE_O(obj) STMT_NOP
+#define DBG_OBJ_BASECLASS(klass) STMT_NOP
+#define DBG_OBJ_ASSOC(parent, child) STMT_NOP
+#define DBG_OBJ_ASSOC_PARENT(parent) STMT_NOP
+#define DBG_OBJ_ASSOC_CHILD(child) STMT_NOP
+#define DBG_OBJ_SET_NUM(var, val) STMT_NOP
+#define DBG_OBJ_SET_NUM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM(var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL(var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_STR(var, val) STMT_NOP
+#define DBG_OBJ_SET_STR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR(var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_COL(var, val) STMT_NOP
+#define DBG_OBJ_SET_COL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_CLASS_COLOR(klass, color) STMT_NOP
+
+#endif /* DBG_RTFL */
+
+#endif /* __DEBUG_RTFL_HH__ */
diff --git a/src/cssparser.cc b/src/cssparser.cc
index 1487a605..f4291797 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -198,7 +198,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
Css_border_style_enum_vals},
{"border-top-width", {CSS_TYPE_ENUM, CSS_TYPE_LENGTH, CSS_TYPE_UNUSED},
Css_border_width_enum_vals},
- {"bottom", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"bottom", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"caption-side", {CSS_TYPE_UNUSED}, NULL},
{"clear", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_clear_enum_vals},
{"clip", {CSS_TYPE_UNUSED}, NULL},
@@ -222,7 +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_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"letter-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_letter_spacing_enum_vals},
{"line-height",
@@ -261,7 +261,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"padding-top", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"position", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_position_enum_vals},
{"quotes", {CSS_TYPE_UNUSED}, NULL},
- {"right", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"right", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"text-align", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_text_align_enum_vals},
{"text-decoration", {CSS_TYPE_MULTI_ENUM, CSS_TYPE_UNUSED},
Css_text_decoration_enum_vals},
@@ -269,7 +269,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"text-shadow", {CSS_TYPE_UNUSED}, NULL},
{"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
Css_text_transform_enum_vals},
- {"top", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"top", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
{"unicode-bidi", {CSS_TYPE_UNUSED}, NULL},
{"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals},
{"visibility", {CSS_TYPE_UNUSED}, NULL},
@@ -277,7 +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/dillo.cc b/src/dillo.cc
index 44a8d754..f4925dd2 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -379,18 +379,18 @@ static DilloUrl *makeStartUrl(char *str, bool local)
*/
int main(int argc, char **argv)
{
- DBG_OBJ_COLOR ("dw::*", "#c0ff80");
- DBG_OBJ_COLOR ("dw::fltk::*", "#c0c0ff");
- DBG_OBJ_COLOR ("dw::core::*", "#ffa0a0");
- DBG_OBJ_COLOR ("dw::core::style::*", "#ffe0a0");
-
- DBG_OBJ_COLOR ("dw::Image", "#80ffa0");
- DBG_OBJ_COLOR ("dw::Textblock", "#f0ff80");
- DBG_OBJ_COLOR ("dw::OutOfFlowMgr", "#d0ff80");
- DBG_OBJ_COLOR ("dw::AlignedTextblock", "#e0ff80");
- DBG_OBJ_COLOR ("dw::ListItem", "#b0ff80");
- DBG_OBJ_COLOR ("dw::TableCell", "#80ff80");
- DBG_OBJ_COLOR ("dw::Table", "#80ffc0");
+ DBG_OBJ_CLASS_COLOR ("dw::*", "#c0ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::fltk::*", "#c0c0ff");
+ DBG_OBJ_CLASS_COLOR ("dw::core::*", "#ffa0a0");
+ DBG_OBJ_CLASS_COLOR ("dw::core::style::*", "#ffe0a0");
+
+ DBG_OBJ_CLASS_COLOR ("dw::Image", "#80ffa0");
+ DBG_OBJ_CLASS_COLOR ("dw::Textblock", "#f0ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::OutOfFlowMgr", "#d0ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::AlignedTextblock", "#e0ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::ListItem", "#b0ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::TableCell", "#80ff80");
+ DBG_OBJ_CLASS_COLOR ("dw::Table", "#80ffc0");
uint_t opt_id;
uint_t options_got = 0;
diff --git a/src/html.cc b/src/html.cc
index 0c1ac37b..c17db53a 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -376,7 +376,7 @@ static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace)
static bool Html_will_textblock_be_out_of_flow(DilloHtml *html)
{
- return HT2TB(html)->isStyleOutOfFlow (html->style ());
+ return HT2TB(html)->testStyleOutOfFlow (html->style ());
}
/*
diff --git a/src/styleengine.cc b/src/styleengine.cc
index 98b02b69..4192a9ef 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/dw_simple_container.cc b/test/dw_simple_container.cc
index e19511a6..94dec2d5 100644
--- a/test/dw_simple_container.cc
+++ b/test/dw_simple_container.cc
@@ -27,190 +27,192 @@ using namespace lout::misc;
namespace dw {
-int SimpleContainer::CLASS_ID = -1;
+ int SimpleContainer::CLASS_ID = -1;
-// ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
-SimpleContainer::SimpleContainerIterator::SimpleContainerIterator
+ SimpleContainer::SimpleContainerIterator::SimpleContainerIterator
(SimpleContainer *simpleContainer, Content::Type mask, bool atEnd) :
- Iterator (simpleContainer, mask, atEnd)
-{
- content.type = atEnd ? Content::END : Content::START;
-}
+ Iterator (simpleContainer, mask, atEnd)
+ {
+ content.type = atEnd ? Content::END : Content::START;
+ }
-lout::object::Object *SimpleContainer::SimpleContainerIterator::clone ()
-{
- SimpleContainerIterator *sci =
- new SimpleContainerIterator ((SimpleContainer*)getWidget(),
- getMask(), false);
- sci->content = content;
- return sci;
-}
+ lout::object::Object *SimpleContainer::SimpleContainerIterator::clone ()
+ {
+ SimpleContainerIterator *sci =
+ new SimpleContainerIterator ((SimpleContainer*)getWidget(),
+ getMask(), false);
+ sci->content = content;
+ return sci;
+ }
-int SimpleContainer::SimpleContainerIterator::index ()
-{
- switch (content.type) {
- case Content::START:
- return 0;
- case Content::WIDGET_IN_FLOW:
- return 1;
- case Content::END:
- return 2;
- default:
- assertNotReached ();
- return 0;
+ int SimpleContainer::SimpleContainerIterator::index ()
+ {
+ switch (content.type) {
+ case Content::START:
+ return 0;
+ case Content::WIDGET_IN_FLOW:
+ return 1;
+ case Content::END:
+ return 2;
+ default:
+ assertNotReached ();
+ return 0;
+ }
}
-}
-int SimpleContainer::SimpleContainerIterator::compareTo
+ int SimpleContainer::SimpleContainerIterator::compareTo
(lout::object::Comparable *other)
-{
- return index () - ((SimpleContainerIterator*)other)->index ();
-}
+ {
+ return index () - ((SimpleContainerIterator*)other)->index ();
+ }
-bool SimpleContainer::SimpleContainerIterator::next ()
-{
- SimpleContainer *simpleContainer = (SimpleContainer*)getWidget();
+ bool SimpleContainer::SimpleContainerIterator::next ()
+ {
+ SimpleContainer *simpleContainer = (SimpleContainer*)getWidget();
- if (content.type == Content::END)
- return false;
+ if (content.type == Content::END)
+ return false;
- // simple containers only contain widgets:
- if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
- content.type = Content::END;
- return false;
- }
+ // simple containers only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::END;
+ return false;
+ }
- if (content.type == Content::START) {
- if (simpleContainer->child != NULL) {
- content.type = Content::WIDGET_IN_FLOW;
- content.widget = simpleContainer->child;
- return true;
- } else {
+ if (content.type == Content::START) {
+ if (simpleContainer->child != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = simpleContainer->child;
+ return true;
+ } else {
+ content.type = Content::END;
+ return false;
+ }
+ } else /* if (content.type == Content::WIDGET) */ {
content.type = Content::END;
return false;
}
- } else /* if (content.type == Content::WIDGET) */ {
- content.type = Content::END;
- return false;
}
-}
-bool SimpleContainer::SimpleContainerIterator::prev ()
-{
- SimpleContainer *simpleContainer = (SimpleContainer*)getWidget();
+ bool SimpleContainer::SimpleContainerIterator::prev ()
+ {
+ SimpleContainer *simpleContainer = (SimpleContainer*)getWidget();
- if (content.type == Content::START)
- return false;
+ if (content.type == Content::START)
+ return false;
- // simple containers only contain widgets:
- if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
- content.type = Content::START;
- return false;
- }
+ // simple containers only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::START;
+ return false;
+ }
- if (content.type == Content::END) {
- if (simpleContainer->child != NULL) {
- content.type = Content::WIDGET_IN_FLOW;
- content.widget = simpleContainer->child;
- return true;
- } else {
+ if (content.type == Content::END) {
+ if (simpleContainer->child != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = simpleContainer->child;
+ return true;
+ } else {
+ content.type = Content::START;
+ return false;
+ }
+ } else /* if (content.type == Content::WIDGET) */ {
content.type = Content::START;
return false;
}
- } else /* if (content.type == Content::WIDGET) */ {
- content.type = Content::START;
- return false;
}
-}
-void SimpleContainer::SimpleContainerIterator::highlight (int start,
- int end,
- HighlightLayer layer)
-{
- /** todo Needs this an implementation? */
-}
+ void SimpleContainer::SimpleContainerIterator::highlight (int start,
+ int end,
+ HighlightLayer layer)
+ {
+ /** todo Needs this an implementation? */
+ }
-void SimpleContainer::SimpleContainerIterator::unhighlight (int direction,
- HighlightLayer
- layer)
-{
- /** todo Needs this an implementation? */
-}
+ void SimpleContainer::SimpleContainerIterator::unhighlight (int direction,
+ HighlightLayer
+ layer)
+ {
+ /** todo Needs this an implementation? */
+ }
-void SimpleContainer::SimpleContainerIterator::getAllocation (int start,
- int end,
- Allocation
- *allocation)
-{
- /** \bug Not implemented. */
-}
+ void SimpleContainer::SimpleContainerIterator::getAllocation (int start,
+ int end,
+ Allocation
+ *allocation)
+ {
+ /** \bug Not implemented. */
+ }
-// ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
-SimpleContainer::SimpleContainer ()
-{
- registerName ("dw::SimpleContainer", &CLASS_ID);
- child = NULL;
-}
+ SimpleContainer::SimpleContainer ()
+ {
+ registerName ("dw::SimpleContainer", &CLASS_ID);
+ child = NULL;
+ }
-SimpleContainer::~SimpleContainer ()
-{
- if (child)
- delete child;
-}
+ SimpleContainer::~SimpleContainer ()
+ {
+ if (child)
+ delete child;
+ }
-void SimpleContainer::sizeRequestImpl (Requisition *requisition)
-{
- Requisition childReq;
- if (child)
- child->sizeRequest (&childReq);
- else
- childReq.width = childReq.ascent = childReq.descent = 0;
+ void SimpleContainer::sizeRequestImpl (Requisition *requisition)
+ {
+ Requisition childReq;
+ if (child)
+ child->sizeRequest (&childReq);
+ else
+ childReq.width = childReq.ascent = childReq.descent = 0;
- requisition->width = childReq.width + boxDiffWidth ();
- requisition->ascent = childReq.ascent + boxOffsetY ();
- requisition->descent = childReq.descent + boxRestHeight ();
+ requisition->width = childReq.width + boxDiffWidth ();
+ requisition->ascent = childReq.ascent + boxOffsetY ();
+ requisition->descent = childReq.descent + boxRestHeight ();
- correctRequisition (requisition, splitHeightPreserveAscent);
-}
+ correctRequisition (requisition, splitHeightPreserveAscent);
+ }
-void SimpleContainer::getExtremesImpl (Extremes *extremes)
-{
- Extremes childExtr;
- if (child)
- child->getExtremes (&childExtr);
- else
- childExtr.minWidth = childExtr.maxWidth = 0;
+ void SimpleContainer::getExtremesImpl (Extremes *extremes)
+ {
+ Extremes childExtr;
+ if (child)
+ child->getExtremes (&childExtr);
+ else
+ childExtr.minWidth = childExtr.maxWidth = 0;
- extremes->minWidth = childExtr.minWidth + boxDiffWidth ();
- extremes->maxWidth = childExtr.maxWidth + boxDiffWidth ();
+ extremes->minWidth = childExtr.minWidth + boxDiffWidth ();
+ extremes->maxWidth = childExtr.maxWidth + boxDiffWidth ();
- correctExtremes (extremes);
-}
+ correctExtremes (extremes);
+ }
-void SimpleContainer::sizeAllocateImpl (Allocation *allocation)
-{
- Allocation childAlloc;
-
- if (child) {
- childAlloc.x = allocation->x + boxOffsetX ();
- childAlloc.y = allocation->y + boxOffsetY ();
- childAlloc.width = allocation->width - boxDiffWidth ();
- childAlloc.ascent = allocation->ascent - boxOffsetY ();
- childAlloc.descent = allocation->descent - boxRestHeight ();
- child->sizeAllocate (&childAlloc);
+ void SimpleContainer::sizeAllocateImpl (Allocation *allocation)
+ {
+ Allocation childAlloc;
+
+ if (child) {
+ childAlloc.x = allocation->x + boxOffsetX ();
+ childAlloc.y = allocation->y + boxOffsetY ();
+ childAlloc.width = allocation->width - boxDiffWidth ();
+ childAlloc.ascent = allocation->ascent - boxOffsetY ();
+ childAlloc.descent = allocation->descent - boxRestHeight ();
+ child->sizeAllocate (&childAlloc);
+ }
}
-}
-void SimpleContainer::draw (View *view, Rectangle *area)
+void SimpleContainer::draw (View *view, Rectangle *area,
+ StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget)
{
drawWidgetBox (view, area, false);
Rectangle childArea;
if (child && child->intersects (area, &childArea))
- child->draw (view, &childArea);
+ child->drawTotal (view, &childArea, iteratorStack, interruptedWidget);
}
Iterator *SimpleContainer::iterator (Content::Type mask, bool atEnd)
diff --git a/test/dw_simple_container.hh b/test/dw_simple_container.hh
index fdb67bec..423b1fab 100644
--- a/test/dw_simple_container.hh
+++ b/test/dw_simple_container.hh
@@ -44,7 +44,9 @@ public:
SimpleContainer ();
~SimpleContainer ();
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area,
+ core::StackingIteratorStack *iteratorStack,
+ Widget **interruptedWidget);
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
void removeChild (Widget *child);
diff --git a/test/identity.cc b/test/identity.cc
new file mode 100644
index 00000000..a1a136eb
--- /dev/null
+++ b/test/identity.cc
@@ -0,0 +1,55 @@
+/*
+ * This small program tests how IdentifiableObject works with multiple
+ * inheritance ("diamond" inheritance, more precisely, since all
+ * classes have there root in IdentifiableObject.)
+ *
+ * Current status: With virtual superclasses, you get a class
+ * hierarchie "root -> A -> B -> C", so that the first part of this
+ * example works actually (C is a subclass of A and of B), but the
+ * second fails (it should print "false", but it is erroneously
+ * assumed that B is a subclass of A.)
+ */
+
+#include "../lout/identity.hh"
+
+using namespace lout::identity;
+
+class A: virtual public IdentifiableObject
+{
+public:
+ static int CLASS_ID;
+ inline A () { registerName ("A", &CLASS_ID); }
+};
+
+class B: virtual public IdentifiableObject
+{
+public:
+ static int CLASS_ID;
+ inline B () { registerName ("B", &CLASS_ID); }
+};
+
+class C: public A, public B
+{
+public:
+ static int CLASS_ID;
+ inline C () { registerName ("C", &CLASS_ID); }
+};
+
+int A::CLASS_ID = -1, B::CLASS_ID = -1, C::CLASS_ID = -1;
+
+int main (int argc, char *argv[])
+{
+ printf ("A: %d, B: %d, C: %d\n", A::CLASS_ID, B::CLASS_ID, C::CLASS_ID);
+
+ C x;
+ assert (x.instanceOf (A::CLASS_ID));
+ assert (x.instanceOf (B::CLASS_ID));
+ assert (x.instanceOf (C::CLASS_ID));
+ printf ("x: %d\n", x.getClassId ());
+
+ B y;
+ printf ("y: %d; instance of A: %s\n",
+ y.getClassId (), y.instanceOf (B::CLASS_ID) ? "true" : "false");
+
+ return 0;
+}