aboutsummaryrefslogtreecommitdiff
path: root/dw/ooffloatsmgr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/ooffloatsmgr.cc')
-rw-r--r--dw/ooffloatsmgr.cc1308
1 files changed, 1308 insertions, 0 deletions
diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc
new file mode 100644
index 00000000..06bab82b
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,1308 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ooffloatsmgr.hh"
+#include "oofawarewidget.hh"
+#include "../lout/debug.hh"
+
+#include <limits.h>
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace dw {
+
+namespace oof {
+
+OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget)
+{
+ this->oofm = oofm;
+ this->widget = widget;
+}
+
+// ----------------------------------------------------------------------
+
+OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget,
+ OOFAwareWidget *generatingBlock, int externalIndex)
+ : WidgetInfo (oofm, widget)
+{
+ this->generator = generatingBlock;
+ this->externalIndex = externalIndex;
+
+ yReq = yReal = size.width = size.ascent = size.descent = 0;
+ dirty = true;
+ index = -1;
+
+ // Sometimes a float with widget = NULL is created as a key; this
+ // is not interesting for RTFL.
+ if (widget) {
+ DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
+ DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
+ DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
+ }
+}
+
+void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ sb->appendPointer (getWidget ());
+
+ if (getWidget ()) {
+ sb->append (" (");
+ sb->append (getWidget()->getClassName ());
+ sb->append (")");
+ }
+
+ sb->append (", index = ");
+ sb->appendInt (index);
+ sb->append (", sideSpanningIndex = ");
+ sb->appendInt (sideSpanningIndex);
+ sb->append (", generator = ");
+ sb->appendPointer (generator);
+ sb->append (", yReq = ");
+ sb->appendInt (yReq);
+ sb->append (", yReal = ");
+ sb->appendInt (yReal);
+ sb->append (", size = { ");
+ sb->appendInt (size.width);
+ sb->append (" * ");
+ sb->appendInt (size.ascent);
+ sb->append (" + ");
+ sb->appendInt (size.descent);
+ sb->append (" }, dirty = ");
+ sb->appendBool (dirty);
+ sb->append (", sizeChangedSinceLastAllocation = ");
+ sb->append (" }");
+}
+
+/**
+ * `y` is given relative to the container.
+ */
+bool OOFFloatsMgr::Float::covers (int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%d, %d [vloat: %p]", y, h, getWidget ());
+
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ bool b = yReal + size.ascent + size.descent > y && yReal < y + h;
+
+ DBG_OBJ_LEAVE_VAL_O (getOOFFloatsMgr (), "%s", b ? "true" : "false");
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ return ((Float*)o1)->yReal - ((Float*)o2)->yReal;
+}
+
+int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
+ Object *o2)
+{
+ return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
+}
+
+int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
+{
+ Float *f1 = (Float*)o1, *f2 = (Float*)o2;
+ int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex::compare",
+ "#%d -> %p/%d, #%d -> %p/#%d",
+ f1->index, f1->generator, f1->externalIndex,
+ f2->index, f2->generator, f2->externalIndex);
+
+ if (f1->generator == f2->generator) {
+ r = f1->externalIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(a) generating blocks equal => %d - %d = %d",
+ f1->externalIndex, f2->externalIndex, r);
+ } else {
+ TBInfo *t1 = oofm->getOOFAwareWidget (f1->generator),
+ *t2 = oofm->getOOFAwareWidget (f2->generator);
+ bool rdef = false;
+
+ for (TBInfo *t = t1; t != NULL; t = t->parent)
+ if (t->parent == t2) {
+ rdef = true;
+ r = t->parentExtIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(b) %p is an achestor of %p; direct child is "
+ "%p (%d) => %d - %d = %d\n",
+ t2->getOOFAwareWidget (), t1->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ t->parentExtIndex, f2->externalIndex, r);
+ }
+
+ for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
+ if (t->parent == t1) {
+ r = f1->externalIndex - t->parentExtIndex;
+ rdef = true;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(c) %p is an achestor of %p; direct child is %p "
+ "(%d) => %d - %d = %d\n",
+ t1->getOOFAwareWidget (), t2->getOOFAwareWidget (),
+ t->getOOFAwareWidget (), t->parentExtIndex,
+ f1->externalIndex, t->parentExtIndex, r);
+ }
+
+ if (!rdef) {
+ r = t1->index - t2->index;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
+ t1->index, t2->index, r);
+ }
+ }
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
+ lastGB, lastExtIndex);
+
+ Float key (oofm, NULL, lastGB, lastExtIndex);
+ key.index = -1; // for debugging
+ Float::CompareGBAndExtIndex comparator (oofm);
+ int i = bsearch (&key, false, &comparator);
+
+ // At position i is the next larger element, so element i should
+ // not included, but i - 1 returned; except if the exact element is
+ // found: then include it and so return i.
+ int r;
+ if (i == size())
+ r = i - 1;
+ else {
+ Float *f = get (i);
+ if (comparator.compare (f, &key) == 0)
+ r = i;
+ else
+ r = i - 1;
+ }
+
+ //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); "
+ // "in %s list %p on the %s side\n",
+ // oofm->container, lastGB, lastExtIndex, i, r, size (),
+ // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right");
+
+ //for (int i = 0; i < size (); i++) {
+ // Float *f = get(i);
+ // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock);
+ // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock,
+ // t->index, t->parent ? t->parent->textblock : NULL,
+ // get(i)->externalIndex);
+ //}
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+/**
+ * `y` is given relative to the container.
+ */
+int OOFFloatsMgr::SortedFloatsVector::find (int y, int start, int end)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%d, %d, %d", y, start, end);
+
+ Float key (oofm, NULL, NULL, 0);
+ key.yReal = y;
+ Float::ComparePosition comparator;
+ int result = bsearch (&key, false, start, end, &comparator);
+
+ DBG_OBJ_LEAVE_VAL_O (oofm, "%d", result);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findFirst (int y, int h,
+ OOFAwareWidget *lastGB,
+ int lastExtIndex,
+ int *lastReturn)
+{
+ DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%d, %d, %p, %d",
+ y, h, lastGB, lastExtIndex);
+
+ int last = findFloatIndex (lastGB, lastExtIndex);
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last);
+ assert (last < size());
+
+ // If the caller wants to reuse this value:
+ if (lastReturn)
+ *lastReturn = last;
+
+ int i = find (y, 0, last), result;
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i);
+
+ // Note: The smallest value of "i" is 0, which means that "y" is before or
+ // equal to the first float. The largest value is "last + 1", which means
+ // that "y" is after the last float. In both cases, the first or last,
+ // respectively, float is a candidate. Generally, both floats, before and
+ // at the search position, are candidates.
+
+ if (i > 0 && get(i - 1)->covers (y, h))
+ result = i - 1;
+ else if (i <= last && get(i)->covers (y, h))
+ result = i;
+ else
+ result = -1;
+
+ DBG_OBJ_LEAVE_VAL_O (oofm, "%d", result);
+ return result;
+}
+
+int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex
+ (int sideSpanningIndex)
+{
+ OOFFloatsMgr::Float::CompareSideSpanningIndex comparator;
+ Float key (NULL, NULL, NULL, 0);
+ key.sideSpanningIndex = sideSpanningIndex;
+ return bsearch (&key, false, &comparator) - 1;
+}
+
+void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat)
+{
+ lout::container::typed::Vector<Float>::put (vloat);
+ vloat->index = size() - 1;
+}
+
+OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock,
+ TBInfo *parent, int parentExtIndex) :
+ WidgetInfo (oofm, textblock)
+{
+ this->parent = parent;
+ this->parentExtIndex = parentExtIndex;
+
+ leftFloats = new Vector<Float> (1, false);
+ rightFloats = new Vector<Float> (1, false);
+}
+
+OOFFloatsMgr::TBInfo::~TBInfo ()
+{
+ delete leftFloats;
+ delete rightFloats;
+}
+
+OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container, int oofmIndex)
+{
+ DBG_OBJ_CREATE ("dw::oof::OOFFloatsMgr");
+
+ this->container = container;
+ this->oofmIndex = oofmIndex;
+
+ leftFloats = new SortedFloatsVector (this, LEFT);
+ rightFloats = new SortedFloatsVector (this, RIGHT);
+
+ DBG_OBJ_SET_NUM ("leftFloats.size", leftFloats->size());
+ DBG_OBJ_SET_NUM ("rightFloats.size", rightFloats->size());
+
+ floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false);
+
+ tbInfos = new Vector<TBInfo> (1, false);
+ tbInfosByOOFAwareWidget =
+ new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true);
+
+ leftFloatsMark = rightFloatsMark = 0;
+ lastLeftTBIndex = lastRightTBIndex = 0;
+
+ containerAllocation = *(container->getAllocation());
+
+ addWidgetInFlow (this->container, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ // Order is important: tbInfosByOOFAwareWidget is owner of the instances
+ // of TBInfo.tbInfosByOOFAwareWidget. Also, leftFloats and rightFloats are
+ // owners of the floats.
+ delete tbInfos;
+ delete tbInfosByOOFAwareWidget;
+
+ delete leftFloats;
+ delete rightFloats;
+
+ delete floatsByWidget;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller,
+ Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
+ "%p, (%d, %d, %d * (%d + %d))",
+ caller, allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ if (caller == container)
+ containerAllocation = *allocation;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == container) {
+ sizeAllocateFloats (LEFT);
+ sizeAllocateFloats (RIGHT);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ for (int i = 0; i < leftFloats->size (); i++)
+ leftFloats->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloats->size (); i++)
+ rightFloats->get(i)->getWidget()->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::sizeAllocateFloats (Side side)
+{
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ for (int i = 0; i < list->size (); i++) {
+ Float *vloat = list->get(i);
+ ensureFloatSize (vloat);
+
+ Allocation childAllocation;
+ childAllocation.x = containerAllocation.x + calcFloatX (vloat);
+ childAllocation.y = containerAllocation.y + vloat->yReal;
+ childAllocation.width = vloat->size.width;
+ childAllocation.ascent = vloat->size.ascent;
+ childAllocation.descent = vloat->size.descent;
+
+ vloat->getWidget()->sizeAllocate (&childAllocation);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Return position of a float relative to the container.
+ */
+int OOFFloatsMgr::calcFloatX (Float *vloat)
+{
+ DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p", vloat->getWidget ());
+ int x, effGeneratorWidth;
+ OOFAwareWidget *generator = vloat->generator;
+
+ ensureFloatSize (vloat);
+
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ // Left floats are always aligned on the left side of the generator
+ // (content, not allocation) ...
+ x = generator->getGeneratorX (oofmIndex)
+ + generator->getStyle()->boxOffsetX();
+
+ // ... but when the float exceeds the line break width of the container,
+ // it is corrected (but not left of the container). This way, we save
+ // space and, especially within tables, avoid some problems.
+ if (x + vloat->size.width > container->getMaxGeneratorWidth ())
+ x = max (0, container->getMaxGeneratorWidth () - vloat->size.width);
+ break;
+
+ case FLOAT_RIGHT:
+ // Similar for right floats, but in this case, floats are shifted to the
+ // right when they are too big (instead of shifting the generator to the
+ // right).
+
+ // (The following code for calculating effGeneratorWidth, is quite
+ // specific for textblocks; this also applies for the comments. Both may
+ // be generalized, but actually, only textblocks play a role here.)
+
+ if (vloat->generator->usesMaxGeneratorWidth ())
+ // For most textblocks, the line break width is used for calculating
+ // the x position. (This changed for GROWS, where the width of a
+ // textblock is often smaller that the line break.)
+ effGeneratorWidth = vloat->generator->getMaxGeneratorWidth ();
+ else
+ // For some textblocks, like inline blocks, the line break width would
+ // be too large for right floats in some cases.
+ //
+ // (i) Consider a small inline block with only a few words in one
+ // line, narrower that line break width minus float width. In this
+ // case, the sum should be used.
+ //
+ // (ii) If there is more than one line, the line break will already be
+ // exceeded, and so be smaller that GB width + float width.
+ effGeneratorWidth =
+ min (vloat->generator->getGeneratorWidth () + vloat->size.width,
+ vloat->generator->getMaxGeneratorWidth ());
+
+ x = max (generator->getGeneratorX (oofmIndex) + effGeneratorWidth
+ - vloat->size.width - generator->getStyle()->boxRestWidth(),
+ // Do not exceed container allocation:
+ 0);
+ break;
+
+ default:
+ assertNotReached ();
+ x = 0;
+ break;
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", x);
+ return x;
+}
+
+void OOFFloatsMgr::draw (View *view, Rectangle *area, DrawingContext *context)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawFloats (leftFloats, view, area, context);
+ drawFloats (rightFloats, view, area, context);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view,
+ Rectangle *area, DrawingContext *context)
+{
+ // This could be improved, since the list is sorted: search the
+ // first float fitting into the area, and iterate until one is
+ // found below the area.
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ Widget *childWidget = vloat->getWidget ();
+
+ Rectangle childArea;
+ if (!context->hasWidgetBeenProcessedAsInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->intersects (container, area, &childArea))
+ childWidget->draw (view, &childArea, context);
+ }
+}
+
+void OOFFloatsMgr::addWidgetInFlow (OOFAwareWidget *textblock,
+ OOFAwareWidget *parentBlock,
+ int externalIndex)
+{
+ //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
+ // container, textblock, parentBlock, externalIndex);
+
+ TBInfo *tbInfo =
+ new TBInfo (this, textblock,
+ parentBlock ? getOOFAwareWidget (parentBlock) : NULL,
+ externalIndex);
+ tbInfo->index = tbInfos->size();
+
+ tbInfos->put (tbInfo);
+ tbInfosByOOFAwareWidget->put (new TypedPointer<OOFAwareWidget> (textblock),
+ tbInfo);
+}
+
+int OOFFloatsMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generatingBlock,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generatingBlock, externalIndex);
+
+ int subRef;
+
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
+
+ // Note: Putting the float first in the GB list, and then, possibly
+ // into the CB list (in that order) will trigger setting
+ // Float::inCBList to the right value.
+
+ switch (widget->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ leftFloats->put (vloat);
+ DBG_OBJ_SET_NUM ("leftFloats.size", leftFloats->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloats", leftFloats->size() - 1,
+ "widget", vloat->getWidget ());
+ tbInfo->leftFloats->put (vloat);
+
+ subRef = createSubRefLeftFloat (leftFloats->size() - 1);
+
+ break;
+
+ case FLOAT_RIGHT:
+ rightFloats->put (vloat);
+ DBG_OBJ_SET_NUM ("rightFloats.size", rightFloats->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloats", rightFloats->size() - 1,
+ "widget", vloat->getWidget ());
+ tbInfo->rightFloats->put (vloat);
+
+ subRef = createSubRefRightFloat (rightFloats->size() - 1);
+ break;
+
+ default:
+ assertNotReached();
+ }
+
+ // "sideSpanningIndex" is only compared, so this simple assignment
+ // is sufficient; differenciation between GB and CB lists is not
+ // neccessary.
+ vloat->sideSpanningIndex =
+ leftFloats->size() + rightFloats->size() - 1;
+
+ floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
+
+ DBG_OBJ_LEAVE_VAL ("%d", subRef);
+ return subRef;
+}
+
+void OOFFloatsMgr::calcWidgetRefSize (Widget *widget, Requisition *size)
+{
+ size->width = size->ascent = size->descent = 0;
+}
+
+void OOFFloatsMgr::moveExternalIndices (OOFAwareWidget *generatingBlock,
+ int oldStartIndex, int diff)
+{
+ TBInfo *tbInfo = getOOFAwareWidget (generatingBlock);
+ moveExternalIndices (tbInfo->leftFloats, oldStartIndex, diff);
+ moveExternalIndices (tbInfo->rightFloats, oldStartIndex, diff);
+}
+
+void OOFFloatsMgr::moveExternalIndices (Vector<Float> *list, int oldStartIndex,
+ int diff)
+{
+ // Could be faster with binary search, but the number of floats per generator
+ // should be rather small.
+ for (int i = 0; i < list->size (); i++) {
+ Float *vloat = list->get (i);
+ if (vloat->externalIndex >= oldStartIndex) {
+ vloat->externalIndex += diff;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
+ vloat->externalIndex);
+ }
+ }
+}
+
+OOFFloatsMgr::Float *OOFFloatsMgr::findFloatByWidget (Widget *widget)
+{
+ TypedPointer <Widget> key (widget);
+ Float *vloat = floatsByWidget->get (&key);
+ assert (vloat != NULL);
+ return vloat;
+}
+
+void OOFFloatsMgr::markSizeChange (int ref)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
+
+ Float *vloat;
+
+ if (isSubRefLeftFloat (ref))
+ vloat = leftFloats->get (getFloatIndexFromSubRef (ref));
+ else if (isSubRefRightFloat (ref))
+ vloat = rightFloats->get (getFloatIndexFromSubRef (ref));
+ else {
+ assertNotReached();
+ vloat = NULL; // compiler happiness
+ }
+
+ vloat->dirty = true;
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+
+ for (int i = 0; i < tbInfos->size (); i++)
+ tbInfos->get(i)->getOOFAwareWidget()->borderChanged (oofmIndex,
+ vloat->yReal,
+ vloat->getWidget ());
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFFloatsMgr::markExtremesChange (int ref)
+{
+ // Nothing to do here.
+}
+
+Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y,
+ GettingWidgetAtPointContext *context)
+{
+ Widget *widgetAtPoint = NULL;
+
+ widgetAtPoint = getFloatWidgetAtPoint (rightFloats, x, y, context);
+ if (widgetAtPoint == NULL)
+ widgetAtPoint = getFloatWidgetAtPoint (leftFloats, x, y, context);
+
+ return widgetAtPoint;
+}
+
+Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x,
+ int y,
+ GettingWidgetAtPointContext
+ *context)
+{
+ // Could use binary search to be faster (similar to drawing).
+ Widget *widgetAtPoint = NULL;
+
+ for (int i = list->size() - 1; widgetAtPoint == NULL && i >= 0; i--) {
+ Widget *childWidget = list->get(i)->getWidget ();
+ if (!context->hasWidgetBeenProcessedAsInterruption (childWidget) &&
+ !StackingContextMgr::handledByStackingContextMgr (childWidget))
+ widgetAtPoint = childWidget->getWidgetAtPoint (x, y, context);
+ }
+
+ return widgetAtPoint;
+}
+
+void OOFFloatsMgr::tellPosition1 (Widget *widget, int x, int y)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition1", "%p, %d, %d",
+ widget, x, y);
+
+ assert (y >= 0);
+
+ Float *vloat = findFloatByWidget(widget);
+
+ SortedFloatsVector *listSame, *listOpp;
+ Side side;
+ getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
+ ensureFloatSize (vloat);
+
+ // "yReal" may change due to collisions (see below).
+ vloat->yReq = vloat->yReal = y;
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+
+ // Test collisions (on this side). Although there are (rare) cases
+ // where it could make sense, the horizontal dimensions are not
+ // tested; especially since searching and border calculation would
+ // be confused. For this reaspn, only the previous float is
+ // relevant. (Cf. below, collisions on the other side.)
+ int yRealNew;
+ if (vloat->index >= 1 &&
+ collidesV (vloat, listSame->get (vloat->index - 1), &yRealNew)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ }
+
+ // Test collisions (on the opposite side). There are cases when
+ // more than one float has to be tested. Consider the following
+ // HTML snippet ("id" attribute only used for simple reference
+ // below, as #f1, #f2, and #f3):
+ //
+ // <div style="float:left" id="f1">
+ // Left left left left left left left left left left.
+ // </div>
+ // <div style="float:left" id="f2">Also left.</div>
+ // <div style="float:right" id="f3">Right.</div>
+ //
+ // When displayed with a suitable window width (only slightly wider
+ // than the text within #f1), this should look like this:
+ //
+ // ---------------------------------------------------------
+ // | Left left left left left left left left left left. |
+ // | Also left. Right. |
+ // ---------------------------------------------------------
+ //
+ // Consider float #f3: a collision test with #f2, considering
+ // vertical dimensions, is positive, but not the test with
+ // horizontal dimensions (because #f2 and #f3 are too
+ // narrow). However, a collision has to be tested with #f1;
+ // otherwise #f3 and #f1 would overlap.
+
+ int oppFloatIndex =
+ listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
+ // Generally, the rules are simple: loop as long as the vertical
+ // dimensions test is positive (and, of course, there are floats),
+ // ...
+ for (bool foundColl = false;
+ !foundColl && oppFloatIndex >= 0 &&
+ collidesV (vloat, listOpp->get (oppFloatIndex), &yRealNew);
+ oppFloatIndex--) {
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, listOpp->get (oppFloatIndex))) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ foundColl = true;
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
+ vloat->yReq, vloat->yReal);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::tellPosition2 (Widget *widget, int x, int y)
+{
+ // Nothing to do.
+}
+
+void OOFFloatsMgr::tellIncompletePosition1 (Widget *generator, Widget *widget,
+ int x, int y)
+{
+ notImplemented ("OOFFloatsMgr::tellIncompletePosition1");
+}
+
+void OOFFloatsMgr::tellIncompletePosition2 (Widget *generator, Widget *widget,
+ int x, int y)
+{
+ notImplemented ("OOFFloatsMgr::tellIncompletePosition2");
+}
+
+bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, int *yReal)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
+ vloat->index, vloat->getWidget (), other->index,
+ other->getWidget ());
+
+ bool result;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
+
+ ensureFloatSize (other);
+ int otherBottomGB = other->yReal + other->size.ascent + other->size.descent;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "otherBottomGB = %d + (%d + %d) = %d",
+ other->yReal, other->size.ascent, other->size.descent,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+
+ if (result)
+ DBG_OBJ_LEAVE_VAL ("%s, %d", "true", *yReal);
+ else
+ DBG_OBJ_LEAVE_VAL ("%s", "false");
+
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generator == other->generator)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generator->boxDiffWidth()
+ > vloat->generator->getGeneratorWidth ();
+ else {
+ // Again, if the other float is not allocated, there is no
+ // collision. Compare to collidesV. (But vloat->size is used
+ // here.)
+ if (!other->getWidget()->wasAllocated ())
+ collidesH = false;
+ else {
+ int vloatX = calcFloatX (vloat);
+
+ // Generally: right border of the left float > left border of
+ // the right float (all in canvas coordinates).
+ if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
+ // "vloat" is left, "other" is right
+ collidesH = vloatX + vloat->size.width
+ > other->getWidget()->getAllocation()->x;
+ else
+ // "other" is left, "vloat" is right
+ collidesH = other->getWidget()->getAllocation()->x
+ + other->getWidget()->getAllocation()->width
+ > vloatX;
+ }
+ }
+
+ return collidesH;
+}
+
+void OOFFloatsMgr::getFloatsListsAndSide (Float *vloat,
+ SortedFloatsVector **listSame,
+ SortedFloatsVector **listOpp,
+ Side *side)
+{
+ switch (vloat->getWidget()->getStyle()->vloat) {
+ case FLOAT_LEFT:
+ if (listSame) *listSame = leftFloats;
+ if (listOpp) *listOpp = rightFloats;
+ if (side) *side = LEFT;
+ break;
+
+ case FLOAT_RIGHT:
+ if (listSame) *listSame = rightFloats;
+ if (listOpp) *listOpp = leftFloats;
+ if (side) *side = RIGHT;
+ break;
+
+ default:
+ assertNotReached();
+ }
+}
+
+void OOFFloatsMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight)
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
+
+ int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
+ getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
+ getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
+
+ // Floats must be within the *content* area of the containing
+ // block, not its *margin* area (which is equivalent to the
+ // requisition / allocation). For this reason, boxRestWidth() and
+ // boxRestHeight() are added here.
+
+ *oofWidth =
+ max (oofWidthtLeft, oofWidthRight) + container->boxRestWidth ();
+ *oofHeight =
+ max (oofHeightLeft, oofHeightRight) + container->boxRestHeight ();
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)",
+ oofWidthtLeft, oofWidthRight, *oofWidth, oofHeightLeft,
+ oofHeightRight, *oofHeight);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
+ int *height)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
+ cbReq->width, cbReq->ascent, cbReq->descent,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+
+ *width = *height = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p has generator %p (container is %p)",
+ vloat->getWidget (), vloat->generator, container);
+
+ ensureFloatSize (vloat);
+
+ *width = max (*width, calcFloatX (vloat) + vloat->size.width);
+ *height = max (*height,
+ vloat->yReal + vloat->size.ascent + vloat->size.descent);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::containerMustAdjustExtraSpace ()
+{
+ return false;
+}
+
+void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ cbExtr->minWidth, cbExtr->maxWidth);
+
+ int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
+ getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
+ getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
+
+ *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight);
+ *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)",
+ oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth,
+ oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
+ int *minWidth, int *maxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
+ cbExtr->minWidth, cbExtr->maxWidth,
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ *minWidth = *maxWidth = 0;
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "float %p has generator %p (container is %p)",
+ vloat->getWidget (), vloat->generator,
+ container);
+
+ Extremes extr;
+ vloat->getWidget()->getExtremes (&extr);
+
+ // The calculation of extremes must be kept consistent with
+ // getFloatsSize(). Especially this means for the *minimal* width:
+ //
+ // - The right border (difference between float and container) does not
+ // have to be considered (see getFloatsSize()).
+ //
+ // - This is also the case for the left border, as seen in calcFloatX()
+ // ("... but when the float exceeds the line break width" ...).
+
+ *minWidth = max (*minWidth, extr.minWidth);
+
+ // For the maximal width, borders must be considered.
+ *maxWidth = max (*maxWidth,
+ extr.maxWidth
+ + vloat->generator->getStyle()->boxDiffWidth(),
+ + max (container->getGeneratorWidth ()
+ - vloat->generator->getGeneratorWidth (),
+ 0));
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d / %d => %d / %d",
+ extr.minWidth, extr.maxWidth, *minWidth, *maxWidth);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidgetWhenRegistered
+ (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidgetWhenRegistered", "%p",
+ widget);
+ TypedPointer<OOFAwareWidget> key (widget);
+ TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (&key);
+ DBG_OBJ_MSGF ("oofm.common", 1, "found? %s", tbInfo ? "yes" : "no");
+ DBG_OBJ_LEAVE ();
+ return tbInfo;
+}
+
+OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidget (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidget", "%p", widget);
+ TBInfo *tbInfo = getOOFAwareWidgetWhenRegistered (widget);
+ assert (tbInfo);
+ DBG_OBJ_LEAVE ();
+ return tbInfo;
+}
+
+int OOFFloatsMgr::getLeftBorder (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ int b = getBorder (LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "left border (%d, %d, %p, %d) => %d",
+ y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getRightBorder (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ int b = getBorder (RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "right border (%d, %d, %p, %d) => %d",
+ y, h, lastGB, lastExtIndex, b);
+ return b;
+}
+
+int OOFFloatsMgr::getBorder (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getBorder", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int last;
+ int first = list->findFirst (y, h, lastGB, lastExtIndex, &last);
+ int border = 0;
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+
+ if (first != -1) {
+ // It is not sufficient to find the first float, since a line
+ // (with height h) may cover the region of multiple float, of
+ // which the widest has to be choosen.
+ bool covers = true;
+
+ // We are not searching until the end of the list, but until the
+ // float defined by lastGB and lastExtIndex.
+ for (int i = first; covers && i <= last; i++) {
+ Float *vloat = list->get(i);
+ covers = vloat->covers (y, h);
+ DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
+ i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
+
+ if (covers) {
+ int d;
+ switch (side) {
+ case LEFT:
+ d = vloat->generator->getGeneratorX (oofmIndex)
+ + vloat->generator->getStyle()->boxOffsetX ();
+ break;
+
+ case RIGHT:
+ // There is no simple possibility to get the difference between
+ // container and generator at the right border (as it is at the
+ // left border, see above). We have to calculate the difference
+ // between the maximal widths.
+ d = container->getMaxGeneratorWidth ()
+ - (vloat->generator->getGeneratorX (oofmIndex)
+ + vloat->generator->getMaxGeneratorWidth ())
+ + vloat->generator->getStyle()->boxRestWidth ();
+ break;
+
+ default:
+ assertNotReached ();
+ d = 0;
+ break;
+ }
+
+ int thisBorder = vloat->size.width + d;
+ DBG_OBJ_MSGF ("border", 1, "thisBorder = %d + %d = %d",
+ vloat->size.width, d, thisBorder);
+
+ border = max (border, thisBorder);
+ }
+ }
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", border);
+ return border;
+}
+
+bool OOFFloatsMgr::hasFloatLeft (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ bool b = hasFloat (LEFT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float left (%d, %d, %p, %d) => %s",
+ y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloatRight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ bool b = hasFloat (RIGHT, y, h, lastGB, lastExtIndex);
+ DBG_OBJ_MSGF ("border", 0, "has float right (%d, %d, %p, %d) => %s",
+ y, h, lastGB, lastExtIndex, b ? "true" : "false");
+ return b;
+}
+
+bool OOFFloatsMgr::hasFloat (Side side, int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "hasFloat", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int first = list->findFirst (y, h, lastGB, lastExtIndex, NULL);
+
+ DBG_OBJ_MSGF ("border", 1, "first = %d", first);
+ DBG_OBJ_LEAVE ();
+ return first != -1;
+}
+
+int OOFFloatsMgr::getLeftFloatHeight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ return getFloatHeight (LEFT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getRightFloatHeight (int y, int h, OOFAwareWidget *lastGB,
+ int lastExtIndex)
+{
+ return getFloatHeight (RIGHT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::getFloatHeight (Side side, int y, int h,
+ OOFAwareWidget *lastGB, int lastExtIndex)
+{
+ DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%s, %d, %d, %p, %d",
+ side == LEFT ? "LEFT" : "RIGHT", y, h, lastGB, lastExtIndex);
+
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+ int first = list->findFirst (y, h, lastGB, lastExtIndex, NULL);
+ assert (first != -1); /* This method must not be called when there is no
+ float on the respective side. */
+
+ Float *vloat = list->get (first);
+ int yRelToFloat = y - vloat->yReal;
+ DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
+ y, vloat->yReal, yRelToFloat);
+
+ ensureFloatSize (vloat);
+ int height = vloat->size.ascent + vloat->size.descent - yRelToFloat;
+
+ DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d",
+ vloat->size.ascent, vloat->size.descent, yRelToFloat, height);
+ DBG_OBJ_LEAVE ();
+ return height;
+}
+
+int OOFFloatsMgr::getClearPosition (OOFAwareWidget *widget)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", widget);
+
+ int pos;
+
+ if (widget->getStyle()) {
+ bool left = false, right = false;
+ switch (widget->getStyle()->clear) {
+ case CLEAR_NONE: break;
+ case CLEAR_LEFT: left = true; break;
+ case CLEAR_RIGHT: right = true; break;
+ case CLEAR_BOTH: left = right = true; break;
+ default: assertNotReached ();
+ }
+
+ pos = max (left ? getClearPosition (widget, LEFT) : 0,
+ right ? getClearPosition (widget, RIGHT) : 0);
+ } else
+ pos = 0;
+
+ DBG_OBJ_LEAVE_VAL ("%d", pos);
+ return pos;
+}
+
+bool OOFFloatsMgr::affectsLeftBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_LEFT;
+}
+
+bool OOFFloatsMgr::affectsRightBorder (core::Widget *widget)
+{
+ return widget->getStyle()->vloat == core::style::FLOAT_RIGHT;
+};
+
+bool OOFFloatsMgr::mayAffectBordersAtAll ()
+{
+ return true;
+}
+
+int OOFFloatsMgr::getClearPosition (OOFAwareWidget *widget, Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s",
+ widget, side == LEFT ? "LEFT" : "RIGHT");
+
+ int pos;
+ SortedFloatsVector *list = side == LEFT ? leftFloats : rightFloats;
+
+ // Search the last float before (therfore -1) this widget.
+ int i = list->findFloatIndex (widget, -1);
+ if (i < 0)
+ pos = 0;
+ else {
+ Float *vloat = list->get(i);
+ assert (vloat->generator != widget);
+ ensureFloatSize (vloat);
+ int yRel = widget->getGeneratorY (oofmIndex);
+ pos = max (vloat->yReal + vloat->size.ascent + vloat->size.descent - yRel,
+ 0);
+ DBG_OBJ_MSGF ("resize.oofm", 1, "pos = max (%d + %d + %d - %d, 0)",
+ vloat->yReal, vloat->size.ascent, vloat->size.descent,
+ yRel);
+ }
+
+ DBG_OBJ_LEAVE_VAL ("%d", pos);
+
+ return pos;
+}
+
+void OOFFloatsMgr::ensureFloatSize (Float *vloat)
+{
+ // Historical note: relative sizes (e. g. percentages) are already
+ // handled by (at this time) Layout::containerSizeChanged, so
+ // Float::dirty will be set.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p",
+ vloat->getWidget ());
+
+ if (vloat->dirty) {
+ DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation");
+
+ vloat->getWidget()->sizeRequest (&vloat->size);
+ vloat->dirty = false;
+ DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)",
+ vloat->size.width, vloat->size.ascent, vloat->size.descent);
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width",
+ vloat->size.width);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent",
+ vloat->size.ascent);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent",
+ vloat->size.descent);
+
+ // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd()
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::dealingWithSizeOfChild (core::Widget *child)
+{
+ return false;
+}
+
+int OOFFloatsMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ notImplemented ("OOFFloatsMgr::getAvailWidthOfChild");
+ return 0;
+}
+
+int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ notImplemented ("OOFFloatsMgr::getAvailHeightOfChild");
+ return 0;
+}
+
+int OOFFloatsMgr::getNumWidgets ()
+{
+ return leftFloats->size() + rightFloats->size();
+}
+
+Widget *OOFFloatsMgr::getWidget (int i)
+{
+ if (i < leftFloats->size())
+ return leftFloats->get(i)->getWidget ();
+ else
+ return rightFloats->get(i - leftFloats->size())->getWidget ();
+}
+
+} // namespace oof
+
+} // namespace dw