aboutsummaryrefslogtreecommitdiff
path: root/dw
diff options
context:
space:
mode:
Diffstat (limited to 'dw')
-rw-r--r--dw/Makefile.am8
-rw-r--r--dw/alignedtablecell.cc2
-rw-r--r--dw/ooffloatsmgr.cc2248
-rw-r--r--dw/ooffloatsmgr.hh377
-rw-r--r--dw/oofposabsmgr.cc29
-rw-r--r--dw/oofposabsmgr.hh16
-rw-r--r--dw/oofposfixedmgr.cc29
-rw-r--r--dw/oofposfixedmgr.hh16
-rw-r--r--dw/oofpositionedmgr.cc428
-rw-r--r--dw/oofpositionedmgr.hh87
-rw-r--r--dw/outofflowmgr.cc2436
-rw-r--r--dw/outofflowmgr.hh501
-rw-r--r--dw/textblock.cc356
-rw-r--r--dw/textblock.hh62
-rw-r--r--dw/textblock_iterator.cc158
-rw-r--r--dw/textblock_linebreaking.cc203
16 files changed, 3754 insertions, 3202 deletions
diff --git a/dw/Makefile.am b/dw/Makefile.am
index 0b4b7bb4..a90fa20f 100644
--- a/dw/Makefile.am
+++ b/dw/Makefile.am
@@ -69,6 +69,14 @@ libDw_widgets_a_SOURCES = \
image.hh \
listitem.cc \
listitem.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..08750faa 100644
--- a/dw/alignedtablecell.cc
+++ b/dw/alignedtablecell.cc
@@ -191,7 +191,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/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc
new file mode 100644
index 00000000..0b110167
--- /dev/null
+++ b/dw/ooffloatsmgr.cc
@@ -0,0 +1,2248 @@
+/*
+ * 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 "textblock.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 {
+
+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,
+ 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 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 (Textblock *textblock, int y, int h)
+{
+ DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers",
+ "%p, %d, %d [vloat: %p]",
+ textblock, y, h, getWidget ());
+
+ bool b;
+
+ if (textblock == generatingBlock) {
+ int reqyGB = y;
+ int flyGB = yReal;
+ getOOFFloatsMgr()->ensureFloatSize (this);
+ int flh = size.ascent + size.descent;
+ b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "for generator: reqyGB = %d, flyGB = %d, "
+ "flh = %d + %d = %d => %s",
+ reqyGB, flyGB, size.ascent, size.descent, flh,
+ b ? "true" : "false");
+ } else {
+ assert (getOOFFloatsMgr()->wasAllocated (generatingBlock));
+ assert (getOOFFloatsMgr()->wasAllocated (textblock));
+
+ if (!getWidget()->wasAllocated ()) {
+ DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (not allocated) => false");
+ b = false;
+ } else {
+ Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock),
+ //*gba = getOOFFloatsMgr()->getAllocation(generatingBlock),
+ *fla = getWidget()->getAllocation ();
+ int reqyCanv = tba->y + y;
+ int flyCanv = fla->y;
+ int flh = fla->ascent + fla->descent;
+ b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
+
+ DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (),
+ "not generator (allocated): reqyCanv = %d + %d = %d, "
+ "flyCanv = %d, flh = %d + %d = %d => %s",
+ tba->y, y, reqyCanv, flyCanv,
+ fla->ascent, fla->descent, flh, b ? "true" : "false");
+ }
+ }
+
+ DBG_OBJ_LEAVE_O (getOOFFloatsMgr ());
+
+ return b;
+}
+
+int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
+{
+ Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
+ int r;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm,
+ "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
+ fl1->getIndex (type), fl2->getIndex (type), refTB);
+
+ if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
+ r = fl1->yReal - fl2->yReal;
+ } else {
+ DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
+ DBG_OBJ_MSG_START_O (oofm);
+
+ assert (oofm->wasAllocated (fl1->generatingBlock));
+ assert (oofm->wasAllocated (fl2->generatingBlock));
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
+ fl1->generatingBlock, fl2->generatingBlock);
+
+ // (i) Floats may not yet been allocated (although the
+ // generators are). Non-allocated floats do not have an effect
+ // yet, they are considered "at the end" of the list.
+
+ // (ii) Float::widget for the key used for binary search. In
+ // this case, Float::yReal is used instead (which is set in
+ // SortedFloatsVector::find).
+
+ bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
+ bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
+ fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
+ a2 ? "yes" : "no");
+
+ if (a1 && a2) {
+ int fly1, fly2;
+
+ if (fl1->getWidget()) {
+ fly1 = fl1->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
+ } else {
+ fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
+ oofm->getAllocation(fl1->generatingBlock)->y,
+ fl1->yReal, fly1);
+ }
+
+ if (fl2->getWidget()) {
+ fly2 = fl2->getWidget()->getAllocation()->y;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
+ } else {
+ fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
+ oofm->getAllocation(fl2->generatingBlock)->y,
+ fl2->yReal, fly2);
+ }
+
+ r = fly1 - fly2;
+
+ DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
+ } else if (a1 && !a2)
+ r = -1;
+ else if (!a1 && a2)
+ r = +1;
+ else // if (!a1 && !a2)
+ return 0;
+
+ DBG_OBJ_MSG_END_O (oofm);
+ }
+
+ DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
+ DBG_OBJ_LEAVE_O (oofm);
+ return r;
+}
+
+int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
+ Object *o2)
+{
+ return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
+}
+
+int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
+{
+ Float *f1 = (Float*)o1, *f2 = (Float*)o2;
+ int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
+
+ DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
+ "#%d -> %p/%d, #%d -> %p/#%d",
+ f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
+ f2->getIndex (type), f2->generatingBlock,
+ f2->externalIndex);
+
+ if (f1->generatingBlock == f2->generatingBlock) {
+ r = f1->externalIndex - f2->externalIndex;
+ DBG_OBJ_MSGF_O ("border", 2, oofm,
+ "(a) generating blocks equal => %d - %d = %d",
+ f1->externalIndex, f2->externalIndex, r);
+ } else {
+ TBInfo *t1 = oofm->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 OOFFloatsMgr::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 OOFFloatsMgr::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 OOFFloatsMgr::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 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, 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 ());
+}
+
+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 (Textblock *containingBlock)
+{
+ DBG_OBJ_CREATE ("dw::OOFFloatsMgr");
+
+ this->containingBlock = (Textblock*)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 (this->containingBlock, NULL, 0);
+}
+
+OOFFloatsMgr::~OOFFloatsMgr ()
+{
+ //printf ("OOFFloatsMgr::~OOFFloatsMgr\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 OOFFloatsMgr::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 OOFFloatsMgr::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));
+ }
+
+ 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 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->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 OOFFloatsMgr::hasRelationChanged (bool oldTBAlloc,
+ int oldTBx, int oldTBy, int oldTBw,
+ int oldTBh, int newTBx, int newTBy,
+ int newTBw, int newTBh,
+ bool oldFlAlloc,
+ int oldFlx, int oldFly, int oldFlw,
+ int oldFlh, int newFlx, int newFly,
+ int newFlw, int newFlh,
+ Side side, int *floatPos)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
+ "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT");
+
+ if (oldTBAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d",
+ oldTBx, oldTBy, oldTBw, oldTBh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d",
+ newTBx, newTBy, newTBw, newTBh);
+
+ if (oldFlAlloc)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d",
+ oldFlx, oldFly, oldFlw, oldFlh);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined");
+ DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d",
+ newFlx, newFly, newFlw, newFlh);
+
+ bool result;
+ if (oldTBAlloc && oldFlAlloc) {
+ bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh;
+ bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.",
+ oldCov ? "yes" : "no", newCov ? "yes" : "no");
+ DBG_OBJ_MSG_START ();
+
+ if (oldCov && newCov) {
+ int yOld = oldFly - oldTBy, yNew = newFly - newTBy;
+ if (yOld == yNew) {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d) and new (%d - %d) position equal: %d",
+ oldFly, oldTBy, newFly, newTBy, yOld);
+
+ // Float position has not changed, but perhaps the amout
+ // how far the float reaches into the TB. (TODO:
+ // Generally, not only here, it could be tested whether
+ // the float reaches into the TB at all.)
+ int wOld, wNew;
+ if (side == LEFT) {
+ wOld = oldFlx + oldFlw - oldTBx;
+ wNew = newFlx + newFlw - newTBx;
+ } else {
+ wOld = oldTBx + oldTBw - oldFlx;
+ wNew = newTBx + newTBw - newFlx;
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n",
+ wOld, wNew);
+
+ if (wOld == wNew) {
+ if (oldFlh == newFlh)
+ result = false;
+ else {
+ // Only heights of floats changed. Relevant only
+ // from bottoms of float.
+ *floatPos = min (yOld + oldFlh, yNew + newFlh);
+ result = true;
+ }
+ } else {
+ *floatPos = yOld;
+ result = true;
+ }
+ } else {
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "old (%d - %d = %d) and new (%d - %d = %d) position "
+ "different",
+ oldFly, oldTBy, yOld, newFly, newTBy, yNew);
+ *floatPos = min (yOld, yNew);
+ result = true;
+ }
+ } else if (oldCov) {
+ *floatPos = oldFly - oldTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning old position: %d - %d = %d", oldFly, oldTBy,
+ *floatPos);
+ } else if (newCov) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "returning new position: %d - %d = %d", newFly, newTBy,
+ *floatPos);
+ } else
+ result = false;
+
+ DBG_OBJ_MSG_END ();
+ } else {
+ // Not allocated before: ignore all old values, only check whether
+ // TB is covered by Float.
+ if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) {
+ *floatPos = newFly - newTBy;
+ result = true;
+ } else
+ result = false;
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d",
+ *floatPos);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
+
+ DBG_OBJ_LEAVE ();
+
+ return result;
+}
+
+void OOFFloatsMgr::checkAllocatedFloatCollisions (Side side)
+{
+ // In some cases, the collision detection in tellPosition() is
+ // based on the wrong allocations. Here (just after all Floats have
+ // been allocated), we correct this.
+
+ // TODO In some cases this approach is rather slow, causing a too
+ // long queueResize() cascade.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB;
+
+ // While iterating through the list of floats to be checked, we
+ // iterate equally through the list of the opposite floats, using
+ // this index:
+ int oppIndex = 0;
+
+ for (int index = 0; index < list->size (); index++) {
+ Float *vloat = list->get(index);
+ bool needsChange = false;
+ int yRealNew = INT_MAX;
+
+ // Same side.
+ if (index >= 1) {
+ Float *other = list->get(index - 1);
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same side: checking %p (#%d, GB: %p) against "
+ "%p (#%d, GB: %p)",
+ vloat->getWidget (), index, vloat->generatingBlock,
+ other->getWidget (), index - 1, other->generatingBlock);
+
+ if (vloat->generatingBlock != other->generatingBlock) {
+ int yRealNewSame;
+ if (collidesV (vloat, other, CB, &yRealNewSame)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides, new yReal = %d (old: %d)",
+ yRealNewSame, vloat->yReal);
+ if (vloat->yReal != yRealNewSame) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewSame);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
+ }
+ }
+
+ if (oppList->size () > 0) {
+ // Other side. Iterate to next float on the other side,
+ // before this float.
+ while (oppIndex + 1 < oppList->size () &&
+ oppList->get(oppIndex + 1)->sideSpanningIndex
+ < vloat->sideSpanningIndex)
+ oppIndex++;
+
+ if (oppList->get(oppIndex)->sideSpanningIndex
+ < vloat->sideSpanningIndex) {
+ int oppIndexTmp = oppIndex, yRealNewOpp;
+
+ // Aproach is similar to tellPosition(); see comments
+ // there. Again, loop as long as the vertical dimensions test
+ // is positive (and, of course, there are floats), ...
+ for (bool foundColl = false;
+ !foundColl && oppIndexTmp >= 0 &&
+ collidesV (vloat, oppList->get (oppIndexTmp), CB,
+ &yRealNewOpp);
+ oppIndexTmp--) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "opposite side (after collision (v) test): "
+ "checking %p (#%d/%d, GB: %p) against "
+ "%p (#%d/%d, GB: %p)",
+ vloat->getWidget (), index,
+ vloat->sideSpanningIndex,
+ vloat->generatingBlock,
+ oppList->get(oppIndexTmp)->getWidget (),
+ oppList->get(oppIndexTmp)->getIndex (CB),
+ oppList->get(oppIndexTmp)->sideSpanningIndex,
+ oppList->get(oppIndexTmp)->generatingBlock);
+
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "=> collides (h), new yReal = %d (old: %d)",
+ yRealNewOpp, vloat->yReal);
+ foundColl = true;
+ if (vloat->yReal != yRealNewOpp) {
+ needsChange = true;
+ yRealNew = min (yRealNew, yRealNewOpp);
+ }
+ } else
+ DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
+ }
+ }
+ }
+
+ if (needsChange)
+ vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
+ vloat->getWidget ());
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::doFloatsExceedCB (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This method is called to determine whether the *requisition* of
+ // the CB must be recalculated. So, we check the float allocations
+ // against the *requisition* of the CB, which may (e. g. within
+ // tables) differ from the new allocation. (Generally, a widget may
+ // allocated at a different size.)
+ core::Requisition cbReq;
+ 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 OOFFloatsMgr::haveExtremesChanged (Side side)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
+ side == LEFT ? "LEFT" : "RIGHT");
+
+ // This is quite different from doFloatsExceedCB, since there is no
+ // counterpart to getExtremes, as sizeAllocate is a counterpart to
+ // sizeRequest. So we have to determine whether the allocation has
+ // changed the extremes, which is done by examining the part of the
+ // allocation which is part of the extremes calculation (see
+ // getFloatsExtremes). Changes of the extremes are handled by the
+ // normal queueResize mechanism.
+
+ SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
+ bool changed = false;
+
+ for (int i = 0; i < list->size () && !changed; i++) {
+ Float *vloat = list->get (i);
+ // When the GB is the CB, an allocation change does not play a
+ // role here.
+ if (vloat->generatingBlock != 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 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 = &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 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->getStyle()->boxOffsetX();
+ DBG_OBJ_MSGF ("resize.oofm", 1, "left: x = %d + %d = %d",
+ gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x);
+ // ... but when the float exceeds the line break width of the
+ // container, it is corrected (but not left of the container).
+ // This way, we save space and, especially within tables, avoid
+ // some problems.
+ if (wasAllocated (containingBlock) &&
+ x + vloat->size.width > containingBlock->getLineBreakWidth ()) {
+ x = max (0, containingBlock->getLineBreakWidth () - vloat->size.width);
+ DBG_OBJ_MSGF ("resize.common", 1,
+ "corrected to: max (0, %d - %d) = %d",
+ containingBlock->getLineBreakWidth (), vloat->size.width,
+ x);
+ }
+ break;
+
+ case RIGHT:
+ // Similar for right floats, but in this case, floats are
+ // shifted to the right when they are too big (instead of
+ // shifting the generator to the right).
+
+ // Notice that not the actual width, but the line break width is
+ // used. (This changed for GROWS, where the width of a textblock
+ // is often smaller that the line break.)
+
+ x = max (gbX + gbLineBreakWidth - vloat->size.width
+ - vloat->generatingBlock->getStyle()->boxRestWidth(),
+ // Do not exceed CB allocation:
+ 0);
+ DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d",
+ gbX, gbLineBreakWidth, vloat->size.width,
+ vloat->generatingBlock->getStyle()->boxRestWidth(), x);
+ break;
+
+ default:
+ assertNotReached ();
+ x = 0;
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return x;
+}
+
+
+void OOFFloatsMgr::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawFloats (leftFloatsCB, view, area);
+ drawFloats (rightFloatsCB, view, area);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view,
+ Rectangle *area)
+{
+ // This could be improved, since the list is sorted: search the
+ // first float fitting into the area, and iterate until one is
+ // found below the area.
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+ Rectangle childArea;
+ if (vloat->getWidget()->intersects (area, &childArea))
+ vloat->getWidget()->draw (view, &childArea);
+ }
+}
+
+void OOFFloatsMgr::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);
+}
+
+int OOFFloatsMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generatingBlock, externalIndex);
+
+ int subRef;
+
+ 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 ());
+
+ 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 (Textblock *generatingBlock,
+ int oldStartIndex, int diff)
+{
+ TBInfo *tbInfo = getTextblock (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, int level)
+{
+ Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level);
+ if (childAtPoint == NULL)
+ childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level);
+ return childAtPoint;
+}
+
+Widget *OOFFloatsMgr::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 OOFFloatsMgr::tellPosition (Widget *widget, int yReq)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d",
+ widget, yReq);
+
+ assert (yReq >= 0);
+
+ Float *vloat = findFloatByWidget(widget);
+
+ SortedFloatsVector *listSame, *listOpp;
+ Side side;
+ getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
+ ensureFloatSize (vloat);
+
+ // "yReal" may change due to collisions (see below).
+ vloat->yReq = vloat->yReal = yReq;
+
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+
+ // Test collisions (on this side). Although there are (rare) cases
+ // where it could make sense, the horizontal dimensions are not
+ // tested; especially since searching and border calculation would
+ // be confused. For this reaspn, only the previous float is
+ // relevant. (Cf. below, collisions on the other side.)
+ int index = vloat->getIndex (listSame->type), yRealNew;
+ if (index >= 1 &&
+ collidesV (vloat, listSame->get (index - 1), listSame->type,
+ &yRealNew)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ }
+
+ // Test collisions (on the opposite side). There are cases when
+ // more than one float has to be tested. Consider the following
+ // HTML snippet ("id" attribute only used for simple reference
+ // below, as #f1, #f2, and #f3):
+ //
+ // <div style="float:left" id="f1">
+ // Left left left left left left left left left left.
+ // </div>
+ // <div style="float:left" id="f2">Also left.</div>
+ // <div style="float:right" id="f3">Right.</div>
+ //
+ // When displayed with a suitable window width (only slightly wider
+ // than the text within #f1), this should look like this:
+ //
+ // ---------------------------------------------------------
+ // | Left left left left left left left left left left. |
+ // | Also left. Right. |
+ // ---------------------------------------------------------
+ //
+ // Consider float #f3: a collision test with #f2, considering
+ // vertical dimensions, is positive, but not the test with
+ // horizontal dimensions (because #f2 and #f3 are too
+ // narrow). However, a collision has to be tested with #f1;
+ // otherwise #f3 and #f1 would overlap.
+
+ int oppFloatIndex =
+ listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
+ // Generally, the rules are simple: loop as long as the vertical
+ // dimensions test is positive (and, of course, there are floats),
+ // ...
+ for (bool foundColl = false;
+ !foundColl && oppFloatIndex >= 0 &&
+ collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
+ &yRealNew);
+ oppFloatIndex--) {
+ // ... but stop the loop as soon as the horizontal dimensions
+ // test is positive.
+ if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
+ vloat->yReal = yRealNew;
+ DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
+ foundColl = true;
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
+ vloat->yReq, vloat->yReal);
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, SFVType type,
+ int *yReal)
+{
+ // Only checks vertical (possible) collisions, and only refers to
+ // vloat->yReal; never to vloat->allocation->y, even when the GBs are
+ // different. Used only in tellPosition.
+
+ DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
+ vloat->getIndex (type), vloat->getWidget (),
+ other->getIndex (type), other->getWidget ());
+
+ bool result;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
+
+ if (vloat->generatingBlock == other->generatingBlock) {
+ ensureFloatSize (other);
+ int otherBottomGB =
+ other->yReal + other->size.ascent + other->size.descent;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "same generators: otherBottomGB = %d + (%d + %d) = %d",
+ other->yReal, other->size.ascent, other->size.descent,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ } else {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (wasAllocated (other->generatingBlock));
+
+ // If the other float is not allocated, there is no collision. The
+ // allocation of this float (vloat) is not used at all.
+ if (!other->getWidget()->wasAllocated ())
+ result = false;
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock),
+ *flaOther = other->getWidget()->getAllocation ();
+ int otherBottomGB =
+ flaOther->y + flaOther->ascent + flaOther->descent - gba->y;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "different generators: "
+ "otherBottomGB = %d + (%d + %d) - %d = %d",
+ flaOther->y, flaOther->ascent, flaOther->descent, gba->y,
+ otherBottomGB);
+
+ if (vloat->yReal < otherBottomGB) {
+ *yReal = otherBottomGB;
+ result = true;
+ } else
+ result = false;
+ }
+ }
+
+ if (result)
+ DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
+ else
+ DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
+
+ DBG_OBJ_LEAVE ();
+ return result;
+}
+
+
+bool OOFFloatsMgr::collidesH (Float *vloat, Float *other, SFVType type)
+{
+ // Only checks horizontal collision. For a complete test, use
+ // collidesV (...) && collidesH (...).
+ bool collidesH;
+
+ if (vloat->generatingBlock == other->generatingBlock)
+ collidesH = vloat->size.width + other->size.width
+ + vloat->generatingBlock->getStyle()->boxDiffWidth()
+ > vloat->generatingBlock->getLineBreakWidth();
+ else {
+ assert (wasAllocated (vloat->generatingBlock));
+ assert (wasAllocated (other->generatingBlock));
+
+ // Again, if the other float is not allocated, there is no
+ // collision. Compare to collidesV. (But vloat->size is used
+ // here.)
+ if (!other->getWidget()->wasAllocated ())
+ collidesH = false;
+ else {
+ Allocation *gba = getAllocation (vloat->generatingBlock);
+ int vloatX =
+ calcFloatX (vloat,
+ vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
+ LEFT : RIGHT,
+ gba->x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+
+ // Generally: right border of the left float > left border of
+ // the right float (all in canvas coordinates).
+ if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
+ // "vloat" is left, "other" is right
+ collidesH = vloatX + vloat->size.width
+ > other->getWidget()->getAllocation()->x;
+ else
+ // "other" is left, "vloat" is right
+ collidesH = other->getWidget()->getAllocation()->x
+ + other->getWidget()->getAllocation()->width
+ > vloatX;
+ }
+ }
+
+ return collidesH;
+}
+
+void OOFFloatsMgr::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 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);
+
+ *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 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 = getFloatsListForTextblock (containingBlock, side);
+
+ *width = *height = 0;
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
+
+ for (int i = 0; i < list->size(); i++) {
+ Float *vloat = list->get(i);
+
+ if (vloat->generatingBlock == containingBlock ||
+ wasAllocated (vloat->generatingBlock)) {
+ ensureFloatSize (vloat);
+ int x, y;
+
+ if (vloat->generatingBlock == containingBlock) {
+ x = calcFloatX (vloat, side, 0, cbReq->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+ y = vloat->yReal;
+ } else {
+ Allocation *gba = getAllocation(vloat->generatingBlock);
+ x = calcFloatX (vloat, side,
+ gba->x - containingBlockAllocation.x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
+ y = gba->y - containingBlockAllocation.y + vloat->yReal;
+ }
+
+ *width = max (*width, x + vloat->size.width);
+ *height = max (*height, y + vloat->size.ascent + vloat->size.descent);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: (%d + %d) * "
+ "(%d + (%d + %d)) => %d * %d",
+ vloat->getWidget (), vloat->generatingBlock,
+ x, vloat->size.width,
+ y, vloat->size.ascent, vloat->size.descent,
+ *width, *height);
+ } else
+ DBG_OBJ_MSGF ("resize.oofm", 1,
+ "considering float %p generated by %p: not allocated",
+ vloat->getWidget (), vloat->generatingBlock);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void 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 = 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 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 == 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;
+}
+
+OOFFloatsMgr::TBInfo *OOFFloatsMgr::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 OOFFloatsMgr::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 OOFFloatsMgr::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 OOFFloatsMgr::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;
+ }
+}
+
+
+OOFFloatsMgr::SortedFloatsVector *OOFFloatsMgr::getFloatsListForTextblock
+ (Textblock *textblock, Side side)
+{
+ DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForTextblock", "%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 = getTextblock (textblock);
+ list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
+ }
+
+ DBG_OBJ_LEAVE ();
+ return list;
+}
+
+
+bool OOFFloatsMgr::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 OOFFloatsMgr::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 OOFFloatsMgr::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 OOFFloatsMgr::getLeftFloatHeight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex);
+}
+
+int OOFFloatsMgr::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 OOFFloatsMgr::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 = y + fla->y - tba->y;
+
+ DBG_OBJ_MSGF ("border", 1,
+ "caller is not CB: yRelToFloat = %d + %d - %d = %d",
+ y, fla->y, tba->y, yRelToFloat);
+ }
+
+ ensureFloatSize (vloat);
+ int height = vloat->size.ascent + vloat->size.descent + yRelToFloat;
+
+ DBG_OBJ_MSGF ("border", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+ return height;
+}
+
+/**
+ * Returns position relative to the textblock "tb".
+ */
+int OOFFloatsMgr::getClearPosition (Textblock *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 ? getClearPosition (textblock, LEFT) : 0,
+ right ? getClearPosition (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;
+};
+
+int OOFFloatsMgr::getClearPosition (Textblock *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);
+ ensureFloatSize (vloat);
+ pos = vloat->yReal + vloat->size.ascent + vloat->size.descent -
+ getAllocation(textblock)->y;
+ DBG_OBJ_MSGF ("resize.oofm", 1, "float %p => %d + (%d + %d) - %d",
+ vloat->getWidget (), 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 = 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 ();
+}
+
+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 dw
diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh
new file mode 100644
index 00000000..e40f1b30
--- /dev/null
+++ b/dw/ooffloatsmgr.hh
@@ -0,0 +1,377 @@
+#ifndef __DW_OOFFLOATSMGR_HH__
+#define __DW_OOFFLOATSMGR_HH__
+
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+class OOFFloatsMgr: public 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;
+
+ 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;
+ Textblock *refTB;
+ SFVType type; // actually only used for debugging
+
+ public:
+ ComparePosition (OOFFloatsMgr *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:
+ 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);
+ };
+
+ 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 (OOFFloatsMgr *oofm, core::Widget *widget,
+ Textblock *generatingBlock, int externalIndex);
+
+ inline bool isNowAllocated () { return getWidget()->wasAllocated (); }
+ inline int getNewXCB () { return getWidget()->getAllocation()->x -
+ getOOFFloatsMgr()->containingBlockAllocation.x; }
+ inline int getNewYCB () { return getWidget()->getAllocation()->y -
+ getOOFFloatsMgr()->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:
+ 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 (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;
+
+ // These two lists store all floats generated by this textblock,
+ // as long as this textblock is not allocates.
+ SortedFloatsVector *leftFloatsGB, *rightFloatsGB;
+
+ TBInfo (OOFFloatsMgr *oofm, Textblock *textblock,
+ TBInfo *parent, int parentExtIndex);
+ ~TBInfo ();
+
+ inline bool isNowAllocated () {
+ return getOOFFloatsMgr()->wasAllocated (getTextblock ()); }
+ inline int getNewXCB () {
+ return getOOFFloatsMgr()->getAllocation (getTextblock ())->x -
+ getOOFFloatsMgr()->containingBlockAllocation.x; }
+ inline int getNewYCB () {
+ return getOOFFloatsMgr()->getAllocation (getTextblock ())->y -
+ getOOFFloatsMgr()->containingBlockAllocation.y; }
+ inline int getNewWidth () {
+ return getOOFFloatsMgr()->getAllocation (getTextblock ())->width; }
+ inline int getNewHeight () {
+ core::Allocation *allocation =
+ getOOFFloatsMgr()->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 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 getClearPosition (Textblock *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 (Textblock *containingBlock);
+ ~OOFFloatsMgr ();
+
+ void sizeAllocateStart (Textblock *caller, core::Allocation *allocation);
+ void sizeAllocateEnd (Textblock *caller);
+ void containerSizeChangedForChildren ();
+ void draw (core::View *view, core::Rectangle *area);
+
+ void markSizeChange (int ref);
+ void markExtremesChange (int ref);
+ core::Widget *getWidgetAtPoint (int x, int y, int level);
+
+ static bool _isWidgetOutOfFlow (core::Widget *widget);
+ static bool _isWidgetHandledByOOFM (core::Widget *widget);
+ void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
+ int externalIndex);
+ int 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);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+
+ int getClearPosition (Textblock *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 dw
+
+#endif // __DW_OOFFLOATSMGR_HH__
diff --git a/dw/oofposabsmgr.cc b/dw/oofposabsmgr.cc
new file mode 100644
index 00000000..afabdf0a
--- /dev/null
+++ b/dw/oofposabsmgr.cc
@@ -0,0 +1,29 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "oofposabsmgr.hh"
+
+namespace dw {
+
+OOFPosAbsMgr::OOFPosAbsMgr (Textblock *containingBlock) :
+ OOFPositionedMgr (containingBlock)
+{
+}
+
+} // namespace dw
diff --git a/dw/oofposabsmgr.hh b/dw/oofposabsmgr.hh
new file mode 100644
index 00000000..769f528f
--- /dev/null
+++ b/dw/oofposabsmgr.hh
@@ -0,0 +1,16 @@
+#ifndef __DW_OOFPOSABSMGR_HH__
+#define __DW_OOFPOSABSMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+class OOFPosAbsMgr: public OOFPositionedMgr
+{
+public:
+ OOFPosAbsMgr (Textblock *containingBlock);
+};
+
+} // namespace dw
+
+#endif // __DW_OOFPOSABSMGR_HH__
diff --git a/dw/oofposfixedmgr.cc b/dw/oofposfixedmgr.cc
new file mode 100644
index 00000000..2017298f
--- /dev/null
+++ b/dw/oofposfixedmgr.cc
@@ -0,0 +1,29 @@
+/*
+ * 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 {
+
+OOFPosFixedMgr::OOFPosFixedMgr (Textblock *containingBlock) :
+ OOFPositionedMgr (containingBlock)
+{
+}
+
+} // namespace dw
diff --git a/dw/oofposfixedmgr.hh b/dw/oofposfixedmgr.hh
new file mode 100644
index 00000000..d21b232c
--- /dev/null
+++ b/dw/oofposfixedmgr.hh
@@ -0,0 +1,16 @@
+#ifndef __DW_OOFPOSFIXEDMGR_HH__
+#define __DW_OOFPOSFIXEDMGR_HH__
+
+#include "oofpositionedmgr.hh"
+
+namespace dw {
+
+class OOFPosFixedMgr: public OOFPositionedMgr
+{
+public:
+ OOFPosFixedMgr (Textblock *containingBlock);
+};
+
+} // namespace dw
+
+#endif // __DW_OOFPOSFIXEDMGR_HH__
diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc
new file mode 100644
index 00000000..590b8545
--- /dev/null
+++ b/dw/oofpositionedmgr.cc
@@ -0,0 +1,428 @@
+/*
+ * 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 "textblock.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 {
+
+OOFPositionedMgr::OOFPositionedMgr (Textblock *containingBlock)
+{
+ DBG_OBJ_CREATE ("dw::OOFPositionedMgr");
+
+ this->containingBlock = (Textblock*)containingBlock;
+ children = new Vector<Widget> (1, false);
+ DBG_OBJ_SET_NUM ("children.size", children->size());
+}
+
+OOFPositionedMgr::~OOFPositionedMgr ()
+{
+ delete children;
+
+ DBG_OBJ_DELETE ();
+}
+
+void OOFPositionedMgr::sizeAllocateStart (Textblock *caller,
+ Allocation *allocation)
+{
+ containingBlockAllocation = *allocation;
+}
+
+void OOFPositionedMgr::sizeAllocateEnd (Textblock *caller)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
+
+ if (caller == containingBlock) {
+ sizeAllocateChildren ();
+
+ bool sizeChanged = doChildrenExceedCB ();
+ bool extremesChanged = haveExtremesChanged ();
+ if (sizeChanged || extremesChanged)
+ containingBlock->oofSizeChanged (extremesChanged);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFPositionedMgr::sizeAllocateChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "sizeAllocateAbsolutelyPositioned");
+
+ //int refWidth = containingBlock->getAvailWidth (true);
+ //int refHeight = containingBlock->getAvailHeight (true);
+ int refWidth = containingBlockAllocation.width;
+ int refHeight =
+ containingBlockAllocation.ascent + containingBlockAllocation.descent;
+
+ for (int i = 0; i < children->size(); i++) {
+ Widget *child = children->get (i);
+
+ Requisition childRequisition;
+ child->sizeRequest (&childRequisition);
+
+ Allocation childAllocation;
+
+ childAllocation.x =
+ containingBlockAllocation.x + getAbsPosLeft (child, refWidth);
+ childAllocation.y =
+ containingBlockAllocation.y + getAbsPosTop (child, refHeight);
+ // TODO (i) Consider {min|max}-{width|heigt}. (ii) Clarify where
+ // sizes refer to. (iii) Height is always apportioned to descent
+ // (ascent is preserved), which makes sense when the children
+ // are textblocks. (iv) Consider minimal length?
+
+ if (style::isAbsLength (child->getStyle()->width))
+ childAllocation.width = style::absLengthVal (child->getStyle()->width);
+ else if (style::isPerLength (child->getStyle()->width))
+ childAllocation.width =
+ style::multiplyWithPerLength (refWidth, child->getStyle()->width);
+ else
+ childAllocation.width = childRequisition.width;
+
+ childAllocation.ascent = childRequisition.ascent;
+ childAllocation.descent = childRequisition.descent;
+ if (style::isAbsLength (child->getStyle()->height)) {
+ int height = style::absLengthVal (child->getStyle()->height);
+ splitHeightPreserveAscent (height, &childAllocation.ascent,
+ &childAllocation.descent);
+ } else if (style::isPerLength (child->getStyle()->height)) {
+ int height = style::multiplyWithPerLength (refHeight,
+ child->getStyle()->height);
+ splitHeightPreserveAscent (height, &childAllocation.ascent,
+ &childAllocation.descent);
+ }
+
+ child->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)->containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool OOFPositionedMgr::doChildrenExceedCB ()
+{
+#if 0
+ 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.)
+ Requisition cbReq;
+ containingBlock->sizeRequest (&cbReq);
+
+ for (int i = 0; i < children->size () && !exceeds; i++) {
+ Widget *child = children->get (i);
+ Allocation *childAlloc = child->getAllocation ();
+ DBG_OBJ_MSGF ("resize.oofm", 2,
+ "Does childAlloc = (%d, %d, %d * %d) exceed CBA = "
+ "(%d, %d, %d * %d)?",
+ childAlloc->x, childAlloc->y, childAlloc->width,
+ childAlloc->ascent + childAlloc->descent,
+ containingBlockAllocation.x, containingBlockAllocation.y,
+ cbReq.width, cbReq.ascent + cbReq.descent);
+ if (childAlloc->x + childAlloc->width
+ > containingBlockAllocation.x + cbReq.width ||
+ childAlloc->y + childAlloc->ascent + childAlloc->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_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+
+ return exceeds;
+#endif
+
+ return false;
+}
+
+bool OOFPositionedMgr::haveExtremesChanged ()
+{
+ // TODO Something to do?
+ return false;
+}
+
+
+void OOFPositionedMgr::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ for (int i = 0; i < children->size(); i++) {
+ Widget *child = children->get(i);
+ Rectangle childArea;
+ if (child->intersects (area, &childArea))
+ child->draw (view, &childArea);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+void OOFPositionedMgr::addWidgetInFlow (Textblock *textblock,
+ Textblock *parentBlock, int externalIndex)
+{
+}
+
+int OOFPositionedMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
+ int externalIndex)
+{
+ DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
+ widget, generatingBlock, externalIndex);
+
+ children->put (widget);
+ int subRef = children->size() - 1;
+ DBG_OBJ_SET_NUM ("children.size", children->size());
+ DBG_OBJ_ARRSET_PTR ("children", children->size() - 1, widget);
+
+ DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef);
+ DBG_OBJ_LEAVE ();
+ return subRef;
+}
+
+void OOFPositionedMgr::moveExternalIndices (Textblock *generatingBlock,
+ int oldStartIndex, int diff)
+{
+}
+
+void OOFPositionedMgr::markSizeChange (int ref)
+{
+}
+
+
+void OOFPositionedMgr::markExtremesChange (int ref)
+{
+}
+
+Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y, int level)
+{
+ for (int i = 0; i < children->size(); i++) {
+ Widget *child = children->get(i);
+ if (child->wasAllocated ()) {
+ Widget *childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
+ if (childAtPoint)
+ return childAtPoint;
+ }
+ }
+
+ return NULL;
+}
+
+void OOFPositionedMgr::tellPosition (Widget *widget, int yReq)
+{
+}
+
+void OOFPositionedMgr::getSize (Requisition *cbReq, int *oofWidth,
+ int *oofHeight)
+{
+ DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
+
+ // TODO
+ *oofWidth = *oofHeight = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFPositionedMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth)
+{
+ DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
+ cbExtr->minWidth, cbExtr->maxWidth);
+
+ // TODO Something to do?
+ *oofMinWidth = *oofMaxWidth = 0;
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+int OOFPositionedMgr::getLeftBorder (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightBorder (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::hasFloatLeft (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::hasFloatRight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return false;
+}
+
+
+int OOFPositionedMgr::getLeftFloatHeight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getRightFloatHeight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex)
+{
+ return 0;
+}
+
+int OOFPositionedMgr::getClearPosition (Textblock *textblock)
+{
+ return 0;
+}
+
+bool OOFPositionedMgr::affectsLeftBorder (Widget *widget)
+{
+ return false;
+}
+
+bool OOFPositionedMgr::affectsRightBorder (Widget *widget)
+{
+ 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 = containingBlock->getAvailWidth (true);
+ width = max (availWidth - containingBlock->boxDiffWidth ()
+ - getAbsPosLeft (child, availWidth)
+ - getAbsPosRight (child, availWidth),
+ 0);
+ } else
+ width = -1;
+ } else
+ // TODO Percentage widths must refer to padding area.
+ child->calcFinalWidth (child->getStyle(), -1, containingBlock, 0,
+ forceValue, &width);
+
+ 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)
+{
+ // TODO FF shows a bit different priority for heights than for
+ // widths, in case of over-determined values.
+
+ 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 = containingBlock->getAvailHeight (true);
+ height = max (availHeight - containingBlock->boxDiffHeight ()
+ - getAbsPosTop (child, availHeight)
+ - getAbsPosBottom (child, availHeight),
+ 0);
+ } else
+ height = -1;
+ } else
+ // TODO Percentage heights must refer to padding area.
+ height = child->calcHeight (child->getStyle()->height, true, -1,
+ containingBlock, forceValue);
+
+ DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+int OOFPositionedMgr::getAbsPosBorder (style::Length cssValue, int refLength)
+{
+ if (style::isAbsLength (cssValue))
+ return style::absLengthVal (cssValue);
+ else if (style::isPerLength (cssValue))
+ return style::multiplyWithPerLength (refLength, cssValue);
+ else
+ // standard value for 'left', 'right', 'top', 'bottom':
+ return 0;
+}
+
+int OOFPositionedMgr::getNumWidgets ()
+{
+ return children->size();
+}
+
+Widget *OOFPositionedMgr::getWidget (int i)
+{
+ return children->get (i);
+}
+
+} // namespace dw
diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh
new file mode 100644
index 00000000..07660547
--- /dev/null
+++ b/dw/oofpositionedmgr.hh
@@ -0,0 +1,87 @@
+#ifndef __DW_OOFPOSITIONEDMGR_HH__
+#define __DW_OOFPOSITIONEDMGR_HH__
+
+#include "outofflowmgr.hh"
+
+namespace dw {
+
+class OOFPositionedMgr: public OutOfFlowMgr
+{
+private:
+ Textblock *containingBlock;
+ core::Allocation containingBlockAllocation;
+
+ lout::container::typed::Vector<core::Widget> *children;
+
+ bool doChildrenExceedCB ();
+ bool haveExtremesChanged ();
+ void sizeAllocateChildren ();
+
+ inline int getAbsPosLeft (core::Widget *child, int availWidth)
+ { return getAbsPosBorder (child->getStyle()->left, availWidth); }
+ inline int getAbsPosRight (core::Widget *child, int availWidth)
+ { return getAbsPosBorder (child->getStyle()->right, availWidth); }
+ inline int getAbsPosTop (core::Widget *child, int availHeight)
+ { return getAbsPosBorder (child->getStyle()->top, availHeight); }
+ inline int getAbsPosBottom (core::Widget *child, int availHeight)
+ { return getAbsPosBorder (child->getStyle()->bottom, availHeight); }
+
+ int getAbsPosBorder (core::style::Length cssValue, int refLength);
+
+public:
+ OOFPositionedMgr (Textblock *containingBlock);
+ ~OOFPositionedMgr ();
+
+ 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);
+
+ void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
+ int externalIndex);
+ int 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 *textblock);
+
+ bool affectsLeftBorder (core::Widget *widget);
+ bool affectsRightBorder (core::Widget *widget);
+
+ 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 dw
+
+#endif // __DW_OOFPOSITIONEDMGR_HH__
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc
index 3dd09ebd..29d45f89 100644
--- a/dw/outofflowmgr.cc
+++ b/dw/outofflowmgr.cc
@@ -22,2449 +22,15 @@
#include "textblock.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)
+OutOfFlowMgr::OutOfFlowMgr ()
{
- this->oofm = oofm;
- this->widget = widget;
- wasAllocated = false;
- xCB = yCB = width = height = -1;
-}
-
-void OutOfFlowMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB,
- int width, int height)
-{
- DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d",
- wasAllocated ? "true" : "false", xCB, yCB, width, height);
-
- this->wasAllocated = wasAllocated;
- this->xCB = xCB;
- this->yCB = yCB;
- this->width = width;
- this->height = height;
-
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width);
- DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height);
-
- DBG_OBJ_LEAVE_O (widget);
-}
-
-// ----------------------------------------------------------------------
-
-OutOfFlowMgr::Float::Float (OutOfFlowMgr *oofm, Widget *widget,
- Textblock *generatingBlock, int externalIndex) :
- WidgetInfo (oofm, widget)
-{
- this->generatingBlock = generatingBlock;
- this->externalIndex = externalIndex;
-
- yReq = yReal = size.width = size.ascent = size.descent = 0;
- dirty = sizeChangedSinceLastAllocation = true;
- indexGBList = indexCBList = -1;
-
- // Sometimes a float with widget = NULL is created as a key; this
- // is not interesting for RTFL.
- if (widget) {
- DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent);
- DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty);
- DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation",
- sizeChangedSinceLastAllocation);
- }
-}
-
-void OutOfFlowMgr::Float::updateAllocation ()
-{
- DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation");
-
- update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (),
- getNewHeight ());
-
- DBG_OBJ_LEAVE_O (getWidget ());
-}
-
-void OutOfFlowMgr::Float::intoStringBuffer(StringBuffer *sb)
-{
- sb->append ("{ widget = ");
- sb->appendPointer (getWidget ());
-
- if (getWidget ()) {
- sb->append (" (");
- sb->append (getWidget()->getClassName ());
- sb->append (")");
- }
-
- sb->append (", indexGBList = ");
- sb->appendInt (indexGBList);
- sb->append (", indexCBList = ");
- sb->appendInt (indexCBList);
- sb->append (", sideSpanningIndex = ");
- sb->appendInt (sideSpanningIndex);
- sb->append (", generatingBlock = ");
- sb->appendPointer (generatingBlock);
- sb->append (", yReq = ");
- sb->appendInt (yReq);
- sb->append (", yReal = ");
- sb->appendInt (yReal);
- sb->append (", size = { ");
- sb->appendInt (size.width);
- sb->append (" * ");
- sb->appendInt (size.ascent);
- sb->append (" + ");
- sb->appendInt (size.descent);
- sb->append (" }, dirty = ");
- sb->appendBool (dirty);
- sb->append (", sizeChangedSinceLastAllocation = ");
- sb->appendBool (sizeChangedSinceLastAllocation);
- sb->append (" }");
-}
-
-bool OutOfFlowMgr::Float::covers (Textblock *textblock, int y, int h)
-{
- DBG_OBJ_ENTER_O ("border", 0, getOutOfFlowMgr (), "covers",
- "%p, %d, %d [vloat: %p]",
- textblock, y, h, getWidget ());
-
- bool b;
-
- if (textblock == generatingBlock) {
- int reqyGB = y;
- int flyGB = yReal;
- getOutOfFlowMgr()->ensureFloatSize (this);
- int flh = size.ascent + size.descent;
- b = flyGB + flh > reqyGB && flyGB < reqyGB + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "for generator: reqyGB = %d, flyGB = %d, "
- "flh = %d + %d = %d => %s",
- reqyGB, flyGB, size.ascent, size.descent, flh,
- b ? "true" : "false");
- } else {
- assert (getOutOfFlowMgr()->wasAllocated (generatingBlock));
- assert (getOutOfFlowMgr()->wasAllocated (textblock));
-
- if (!getWidget()->wasAllocated ()) {
- DBG_OBJ_MSG_O ("border", 1, getOutOfFlowMgr (),
- "not generator (not allocated) => false");
- b = false;
- } else {
- Allocation *tba = getOutOfFlowMgr()->getAllocation(textblock),
- //*gba = getOutOfFlowMgr()->getAllocation(generatingBlock),
- *fla = getWidget()->getAllocation ();
- int reqyCanv = tba->y + y;
- int flyCanv = fla->y;
- int flh = fla->ascent + fla->descent;
- b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h;
-
- DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (),
- "not generator (allocated): reqyCanv = %d + %d = %d, "
- "flyCanv = %d, flh = %d + %d = %d => %s",
- tba->y, y, reqyCanv, flyCanv,
- fla->ascent, fla->descent, flh, b ? "true" : "false");
- }
- }
-
- DBG_OBJ_LEAVE_O (getOutOfFlowMgr ());
-
- return b;
-}
-
-int OutOfFlowMgr::Float::ComparePosition::compare (Object *o1, Object *o2)
-{
- Float *fl1 = (Float*)o1, *fl2 = (Float*)o2;
- int r;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm,
- "ComparePosition/compare", "(#%d, #%d) [refTB = %p]",
- fl1->getIndex (type), fl2->getIndex (type), refTB);
-
- if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats");
- r = fl1->yReal - fl2->yReal;
- } else {
- DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats");
- DBG_OBJ_MSG_START_O (oofm);
-
- assert (oofm->wasAllocated (fl1->generatingBlock));
- assert (oofm->wasAllocated (fl2->generatingBlock));
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p",
- fl1->generatingBlock, fl2->generatingBlock);
-
- // (i) Floats may not yet been allocated (although the
- // generators are). Non-allocated floats do not have an effect
- // yet, they are considered "at the end" of the list.
-
- // (ii) Float::widget for the key used for binary search. In
- // this case, Float::yReal is used instead (which is set in
- // SortedFloatsVector::find).
-
- bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true;
- bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s",
- fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (),
- a2 ? "yes" : "no");
-
- if (a1 && a2) {
- int fly1, fly2;
-
- if (fl1->getWidget()) {
- fly1 = fl1->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1);
- } else {
- fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d",
- oofm->getAllocation(fl1->generatingBlock)->y,
- fl1->yReal, fly1);
- }
-
- if (fl2->getWidget()) {
- fly2 = fl2->getWidget()->getAllocation()->y;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2);
- } else {
- fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d",
- oofm->getAllocation(fl2->generatingBlock)->y,
- fl2->yReal, fly2);
- }
-
- r = fly1 - fly2;
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r);
- } else if (a1 && !a2)
- r = -1;
- else if (!a1 && a2)
- r = +1;
- else // if (!a1 && !a2)
- return 0;
-
- DBG_OBJ_MSG_END_O (oofm);
- }
-
- DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::Float::CompareSideSpanningIndex::compare (Object *o1,
- Object *o2)
-{
- return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex;
-}
-
-int OutOfFlowMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2)
-{
- Float *f1 = (Float*)o1, *f2 = (Float*)o2;
- int r = -123; // Compiler happiness: GCC 4.7 does not handle this?;
-
- DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare",
- "#%d -> %p/%d, #%d -> %p/#%d",
- f1->getIndex (type), f1->generatingBlock, f1->externalIndex,
- f2->getIndex (type), f2->generatingBlock,
- f2->externalIndex);
-
- if (f1->generatingBlock == f2->generatingBlock) {
- r = f1->externalIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(a) generating blocks equal => %d - %d = %d",
- f1->externalIndex, f2->externalIndex, r);
- } else {
- TBInfo *t1 = oofm->getTextblock (f1->generatingBlock),
- *t2 = oofm->getTextblock (f2->generatingBlock);
- bool rdef = false;
-
- for (TBInfo *t = t1; t != NULL; t = t->parent)
- if (t->parent == t2) {
- rdef = true;
- r = t->parentExtIndex - f2->externalIndex;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(b) %p is an achestor of %p; direct child is "
- "%p (%d) => %d - %d = %d\n",
- t2->getTextblock (), t1->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- t->parentExtIndex, f2->externalIndex, r);
- }
-
- for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent)
- if (t->parent == t1) {
- r = f1->externalIndex - t->parentExtIndex;
- rdef = true;
- DBG_OBJ_MSGF_O ("border", 2, oofm,
- "(c) %p is an achestor of %p; direct child is %p "
- "(%d) => %d - %d = %d\n",
- t1->getTextblock (), t2->getTextblock (),
- t->getTextblock (), t->parentExtIndex,
- f1->externalIndex, t->parentExtIndex, r);
- }
-
- if (!rdef) {
- r = t1->index - t2->index;
- DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d",
- t1->index, t2->index, r);
- }
- }
-
- DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r);
- DBG_OBJ_LEAVE_O (oofm);
- return r;
-}
-
-int OutOfFlowMgr::SortedFloatsVector::findFloatIndex (Textblock *lastGB,
- int lastExtIndex)
-{
- DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d",
- lastGB, lastExtIndex);
-
- Float key (oofm, NULL, lastGB, lastExtIndex);
- key.setIndex (type, -1); // for debugging
- Float::CompareGBAndExtIndex comparator (oofm, type);
- int i = bsearch (&key, false, &comparator);
-
- // At position i is the next larger element, so element i should
- // not included, but i - 1 returned; except if the exact element is
- // found: then include it and so return i.
- int r;
- if (i == size())
- r = i - 1;
- else {
- Float *f = get (i);
- if (comparator.compare (f, &key) == 0)
- r = i;
- else
- r = i - 1;
- }
-
- //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 ());
-}
-
-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;
-
- absolutelyPositioned = new Vector<Widget> (1, false);
-
- DBG_OBJ_SET_NUM ("absolutelyPositioned.size", absolutelyPositioned->size());
-
- containingBlockWasAllocated = containingBlock->wasAllocated ();
- containingBlockAllocation = *(containingBlock->getAllocation());
-
- addWidgetInFlow (containingBlock, NULL, 0);
}
OutOfFlowMgr::~OutOfFlowMgr ()
{
- //printf ("OutOfFlowMgr::~OutOfFlowMgr\n");
-
- delete leftFloatsCB;
- delete rightFloatsCB;
-
- // Order is important: tbInfosByTextblock is owner of the instances
- // of TBInfo.tbInfosByTextblock
- delete tbInfos;
- delete tbInfosByTextblock;
-
- delete floatsByWidget;
-
- // Order is important, since the instances of Float are owned by
- // leftFloatsAll and rightFloatsAll, so these should be deleted
- // last.
- delete leftFloatsAll;
- delete rightFloatsAll;
-
- delete absolutelyPositioned;
-
- DBG_OBJ_DELETE ();
-}
-
-void OutOfFlowMgr::sizeAllocateStart (Textblock *caller, Allocation *allocation)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart",
- "%p, (%d, %d, %d * (%d + %d))",
- caller, allocation->x, allocation->y, allocation->width,
- allocation->ascent, allocation->descent);
-
- getTextblock(caller)->allocation = *allocation;
- getTextblock(caller)->wasAllocated = true;
-
- if (caller == containingBlock) {
- // In the size allocation process, the *first* OOFM method
- // called is sizeAllocateStart, with the containing block as an
- // argument. So this is the correct point to initialize size
- // allocation.
-
- containingBlockAllocation = *allocation;
- containingBlockWasAllocated = true;
-
- // Move floats from GB lists to the one CB list.
- moveFromGBToCB (LEFT);
- moveFromGBToCB (RIGHT);
-
- // These attributes are used to keep track which floats have
- // been allocated (referring to leftFloatsCB and rightFloatsCB).
- lastAllocatedLeftFloat = lastAllocatedRightFloat = -1;
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller);
-
- // (Later, absolutely positioned blocks have to be allocated.)
-
- if (caller != containingBlock) {
- // Allocate all floats "before" this textblock.
- sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1));
- sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1));
- }
-
- 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);
-
- sizeAllocateAbsolutelyPositioned ();
-
- // Check changes of both textblocks and floats allocation. (All
- // is checked by hasRelationChanged (...).)
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- int minFloatPos;
- Widget *minFloat;
- if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat))
- tb->borderChanged (minFloatPos, minFloat);
- }
-
- checkAllocatedFloatCollisions (LEFT);
- checkAllocatedFloatCollisions (RIGHT);
-
- // Store some information for later use.
- for (lout::container::typed::Iterator<TypedPointer <Textblock> > it =
- tbInfosByTextblock->iterator ();
- it.hasNext (); ) {
- TypedPointer <Textblock> *key = it.getNext ();
- TBInfo *tbInfo = tbInfosByTextblock->get (key);
- Textblock *tb = key->getTypedValue();
-
- tbInfo->updateAllocation ();
- tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
- }
-
- // There are cases where some allocated floats (TODO: later also
- // absolutely positioned elements?) exceed the CB allocation.
- bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT);
-
- // Similar for extremes. (TODO: here also absolutely positioned
- // elements?)
- bool extremesChanged =
- haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT);
-
- for (int i = 0; i < leftFloatsCB->size(); i++)
- leftFloatsCB->get(i)->updateAllocation ();
-
- for (int i = 0; i < rightFloatsCB->size(); i++)
- rightFloatsCB->get(i)->updateAllocation ();
-
- if (sizeChanged || extremesChanged)
- containingBlock->oofSizeChanged (extremesChanged);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::containerSizeChangedForChildren ()
-{
- DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
-
- DBG_OBJ_MSGF ("resize", 0,
- "%d left floats, %d right floats %d abspos",
- leftFloatsAll->size (), rightFloatsAll->size (),
- absolutelyPositioned->size());
-
- for (int i = 0; i < leftFloatsAll->size (); i++)
- leftFloatsAll->get(i)->getWidget()->containerSizeChanged ();
- for (int i = 0; i < rightFloatsAll->size (); i++)
- rightFloatsAll->get(i)->getWidget()->containerSizeChanged ();
- for (int i = 0; i < absolutelyPositioned->size(); i++)
- absolutelyPositioned->get(i)->containerSizeChanged ();
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
- Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, ...", tbInfo->getWidget ());
-
- int leftMinPos, rightMinPos;
- Widget *leftMinFloat, *rightMinFloat;
- bool c1 =
- hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat);
- bool c2 =
- hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat);
- if (c1 || c2) {
- if (!c1) {
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- } else if (!c2) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else {
- if (leftMinPos < rightMinPos) {
- *minFloatPos = leftMinPos;
- *minFloat = leftMinFloat;
- } else{
- *minFloatPos = rightMinPos;
- *minFloat = rightMinFloat;
- }
- }
- }
-
- if (c1 || c2)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "has changed: minFloatPos = %d, minFloat = %p",
- *minFloatPos, *minFloat);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
- return c1 || c2;
-}
-
-bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
- int *minFloatPos, Widget **minFloat)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>widget:</i> %p, %s, ...",
- tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size(); i++) {
- // TODO binary search?
- Float *vloat = list->get(i);
- int floatPos;
-
- if (tbInfo->getTextblock () == vloat->generatingBlock)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "not checking (generating!) textblock %p against float "
- "%p", tbInfo->getWidget (), vloat->getWidget ());
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock);
-
- int newFlx =
- calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
- int newFly = vloat->generatingBlock->getAllocation()->y
- - containingBlockAllocation.y + vloat->yReal;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "checking textblock %p against float %p",
- tbInfo->getWidget (), vloat->getWidget ());
- DBG_OBJ_MSG_START ();
-
- if (hasRelationChanged (tbInfo->wasThenAllocated (),
- tbInfo->getOldXCB (), tbInfo->getOldYCB (),
- tbInfo->getNewWidth (),
- tbInfo->getNewHeight (),
- tbInfo->getNewXCB (), tbInfo->getNewYCB (),
- tbInfo->getNewWidth (),
- tbInfo->getNewHeight (),
- vloat->wasThenAllocated (),
- // When not allocated before, these values
- // are undefined, but this does not matter,
- // since they are neither used.
- vloat->getOldXCB (), vloat->getOldYCB (),
- vloat->getOldWidth (), vloat->getOldHeight (),
- newFlx, newFly, vloat->size.width,
- vloat->size.ascent + vloat->size.descent,
- side, &floatPos)) {
- if (!changed || floatPos < *minFloatPos) {
- *minFloatPos = floatPos;
- *minFloat = vloat->getWidget ();
- }
- changed = true;
- } else
- DBG_OBJ_MSG ("resize.oofm", 0, "No.");
-
- DBG_OBJ_MSG_END ();
- }
-
- // All floarts are searched, to find the minimum. TODO: Are
- // floats sorted, so this can be shortened? (The first is the
- // minimum?)
- }
-
- if (changed)
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "has changed: minFloatPos = %d, minFloat = %p",
- *minFloatPos, *minFloat);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
- return changed;
-}
-
-/**
- * \brief ...
- *
- * All coordinates are given relative to the CB. *floatPos is relative
- * to the TB, and may be negative.
- */
-bool OutOfFlowMgr::hasRelationChanged (bool oldTBAlloc,
- int oldTBx, int oldTBy, int oldTBw,
- int oldTBh, int newTBx, int newTBy,
- int newTBw, int newTBh,
- bool oldFlAlloc,
- int oldFlx, int oldFly, int oldFlw,
- int oldFlh, int newFlx, int newFly,
- int newFlw, int newFlh,
- Side side, int *floatPos)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged",
- "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT");
-
- if (oldTBAlloc)
- DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d",
- oldTBx, oldTBy, oldTBw, oldTBh);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined");
- DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d",
- newTBx, newTBy, newTBw, newTBh);
-
- if (oldFlAlloc)
- DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d",
- oldFlx, oldFly, oldFlw, oldFlh);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined");
- DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d",
- newFlx, newFly, newFlw, newFlh);
-
- bool result;
- if (oldTBAlloc && oldFlAlloc) {
- bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh;
- bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.",
- oldCov ? "yes" : "no", newCov ? "yes" : "no");
- DBG_OBJ_MSG_START ();
-
- if (oldCov && newCov) {
- int yOld = oldFly - oldTBy, yNew = newFly - newTBy;
- if (yOld == yNew) {
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "old (%d - %d) and new (%d - %d) position equal: %d",
- oldFly, oldTBy, newFly, newTBy, yOld);
-
- // Float position has not changed, but perhaps the amout
- // how far the float reaches into the TB. (TODO:
- // Generally, not only here, it could be tested whether
- // the float reaches into the TB at all.)
- int wOld, wNew;
- if (side == LEFT) {
- wOld = oldFlx + oldFlw - oldTBx;
- wNew = newFlx + newFlw - newTBx;
- } else {
- wOld = oldTBx + oldTBw - oldFlx;
- wNew = newTBx + newTBw - newFlx;
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n",
- wOld, wNew);
-
- if (wOld == wNew) {
- if (oldFlh == newFlh)
- result = false;
- else {
- // Only heights of floats changed. Relevant only
- // from bottoms of float.
- *floatPos = min (yOld + oldFlh, yNew + newFlh);
- result = true;
- }
- } else {
- *floatPos = yOld;
- result = true;
- }
- } else {
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "old (%d - %d = %d) and new (%d - %d = %d) position "
- "different",
- oldFly, oldTBy, yOld, newFly, newTBy, yNew);
- *floatPos = min (yOld, yNew);
- result = true;
- }
- } else if (oldCov) {
- *floatPos = oldFly - oldTBy;
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "returning old position: %d - %d = %d", oldFly, oldTBy,
- *floatPos);
- } else if (newCov) {
- *floatPos = newFly - newTBy;
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "returning new position: %d - %d = %d", newFly, newTBy,
- *floatPos);
- } else
- result = false;
-
- DBG_OBJ_MSG_END ();
- } else {
- // Not allocated before: ignore all old values, only check whether
- // TB is covered by Float.
- if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) {
- *floatPos = newFly - newTBy;
- result = true;
- } else
- result = false;
- }
-
- if (result)
- DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d",
- *floatPos);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "has not changed");
-
- DBG_OBJ_LEAVE ();
-
- return result;
-}
-
-void OutOfFlowMgr::checkAllocatedFloatCollisions (Side side)
-{
- // In some cases, the collision detection in tellPosition() is
- // based on the wrong allocations. Here (just after all Floats have
- // been allocated), we correct this.
-
- // TODO In some cases this approach is rather slow, causing a too
- // long queueResize() cascade.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB;
-
- // While iterating through the list of floats to be checked, we
- // iterate equally through the list of the opposite floats, using
- // this index:
- int oppIndex = 0;
-
- for (int index = 0; index < list->size (); index++) {
- Float *vloat = list->get(index);
- bool needsChange = false;
- int yRealNew = INT_MAX;
-
- // Same side.
- if (index >= 1) {
- Float *other = list->get(index - 1);
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "same side: checking %p (#%d, GB: %p) against "
- "%p (#%d, GB: %p)",
- vloat->getWidget (), index, vloat->generatingBlock,
- other->getWidget (), index - 1, other->generatingBlock);
-
- if (vloat->generatingBlock != other->generatingBlock) {
- int yRealNewSame;
- if (collidesV (vloat, other, CB, &yRealNewSame)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides, new yReal = %d (old: %d)",
- yRealNewSame, vloat->yReal);
- if (vloat->yReal != yRealNewSame) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewSame);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision");
- }
- }
-
- if (oppList->size () > 0) {
- // Other side. Iterate to next float on the other side,
- // before this float.
- while (oppIndex + 1 < oppList->size () &&
- oppList->get(oppIndex + 1)->sideSpanningIndex
- < vloat->sideSpanningIndex)
- oppIndex++;
-
- if (oppList->get(oppIndex)->sideSpanningIndex
- < vloat->sideSpanningIndex) {
- int oppIndexTmp = oppIndex, yRealNewOpp;
-
- // Aproach is similar to tellPosition(); see comments
- // there. Again, loop as long as the vertical dimensions test
- // is positive (and, of course, there are floats), ...
- for (bool foundColl = false;
- !foundColl && oppIndexTmp >= 0 &&
- collidesV (vloat, oppList->get (oppIndexTmp), CB,
- &yRealNewOpp);
- oppIndexTmp--) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "opposite side (after collision (v) test): "
- "checking %p (#%d/%d, GB: %p) against "
- "%p (#%d/%d, GB: %p)",
- vloat->getWidget (), index,
- vloat->sideSpanningIndex,
- vloat->generatingBlock,
- oppList->get(oppIndexTmp)->getWidget (),
- oppList->get(oppIndexTmp)->getIndex (CB),
- oppList->get(oppIndexTmp)->sideSpanningIndex,
- oppList->get(oppIndexTmp)->generatingBlock);
-
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) {
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> collides (h), new yReal = %d (old: %d)",
- yRealNewOpp, vloat->yReal);
- foundColl = true;
- if (vloat->yReal != yRealNewOpp) {
- needsChange = true;
- yRealNew = min (yRealNew, yRealNewOpp);
- }
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)");
- }
- }
- }
-
- if (needsChange)
- vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew),
- vloat->getWidget ());
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::doFloatsExceedCB (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This method is called to determine whether the *requisition* of
- // the CB must be recalculated. So, we check the float allocations
- // against the *requisition* of the CB, which may (e. g. within
- // tables) differ from the new allocation. (Generally, a widget may
- // allocated at a different size.)
- core::Requisition cbReq;
- containingBlock->sizeRequest (&cbReq);
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool exceeds = false;
-
- DBG_OBJ_MSG_START ();
-
- for (int i = 0; i < list->size () && !exceeds; i++) {
- Float *vloat = list->get (i);
- if (vloat->getWidget()->wasAllocated ()) {
- Allocation *fla = vloat->getWidget()->getAllocation ();
- DBG_OBJ_MSGF ("resize.oofm", 2,
- "Does FlA = (%d, %d, %d * %d) exceed CBA = "
- "(%d, %d, %d * %d)?",
- fla->x, fla->y, fla->width, fla->ascent + fla->descent,
- containingBlockAllocation.x, containingBlockAllocation.y,
- cbReq.width, cbReq.ascent + cbReq.descent);
- if (fla->x + fla->width > containingBlockAllocation.x + cbReq.width ||
- fla->y + fla->ascent + fla->descent
- > containingBlockAllocation.y + cbReq.ascent + cbReq.descent) {
- exceeds = true;
- DBG_OBJ_MSG ("resize.oofm", 2, "Yes.");
- } else
- DBG_OBJ_MSG ("resize.oofm", 2, "No.");
- }
- }
-
- DBG_OBJ_MSG_END ();
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return exceeds;
-}
-
-bool OutOfFlowMgr::haveExtremesChanged (Side side)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- // This is quite different from doFloatsExceedCB, since there is no
- // counterpart to getExtremes, as sizeAllocate is a counterpart to
- // sizeRequest. So we have to determine whether the allocation has
- // changed the extremes, which is done by examining the part of the
- // allocation which is part of the extremes calculation (see
- // getFloatsExtremes). Changes of the extremes are handled by the
- // normal queueResize mechanism.
-
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- bool changed = false;
-
- for (int i = 0; i < list->size () && !changed; i++) {
- Float *vloat = list->get (i);
- // When the GB is the CB, an allocation change does not play a
- // role here.
- if (vloat->generatingBlock != containingBlock) {
- if (!vloat->wasThenAllocated () && vloat->isNowAllocated ())
- changed = true;
- else {
- // This method is called within sizeAllocateEnd, where
- // containinBlock->getAllocation() (old value) and
- // containinBlockAllocation (new value) are different.
-
- Allocation *oldCBA = containingBlock->getAllocation ();
- Allocation *newCBA = &containingBlockAllocation;
-
- // Compare also to getFloatsExtremes. The box difference
- // of the GB (from style) has not changed in this context,
- // so it is ignored.
-
- int oldDiffLeft = vloat->getOldXCB ();
- int newDiffLeft = vloat->getNewXCB ();
- int oldDiffRight =
- oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ());
- int newDiffRight =
- newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ());
-
- if (// regarding minimum
- (side == LEFT && oldDiffLeft != newDiffLeft) ||
- (side == RIGHT && oldDiffRight != newDiffRight) ||
- // regarding maximum
- oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight)
- changed = true;
- }
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false");
- DBG_OBJ_LEAVE ();
-
- return changed;
-}
-
-void OutOfFlowMgr::moveFromGBToCB (Side side)
-{
- DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s",
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark;
-
- for (int mark = 0; mark <= *floatsMark; mark++)
- for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator ();
- it.hasNext (); ) {
- TBInfo *tbInfo = it.getNext ();
- SortedFloatsVector *src =
- side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
- for (int i = 0; i < src->size (); i++) {
- Float *vloat = src->get (i);
- // "vloat->indexCBList == -1": prevent copying the vloat twice.
- if (vloat->indexCBList == -1 && vloat->mark == mark) {
- dest->put (vloat);
- DBG_OBJ_MSGF ("oofm.resize", 1,
- "moving float %p (mark %d) to CB list\n",
- vloat->getWidget (), vloat->mark);
- DBG_OBJ_SET_NUM (side == LEFT ?
- "leftFloatsCB.size" : "rightFloatsCB.size",
- dest->size());
- DBG_OBJ_ARRATTRSET_PTR (side == LEFT ?
- "leftFloatsCB" : "rightFloatsCB",
- dest->size() - 1, "widget",
- vloat->getWidget ());
-
- }
- }
- }
-
- *floatsMark = 0;
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
-{
- SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- int *lastAllocatedFloat =
- side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat;
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats",
- "%s, [%d ->] %d [size = %d]",
- side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat,
- newLastAllocatedFloat, list->size ());
-
- Allocation *cba = &containingBlockAllocation;
-
- for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) {
- Float *vloat = list->get(i);
- ensureFloatSize (vloat);
-
- Allocation *gba = getAllocation (vloat->generatingBlock);
- int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth();
-
- Allocation childAllocation;
- childAllocation.x = cba->x +
- calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth);
- childAllocation.y = gba->y + vloat->yReal;
- childAllocation.width = vloat->size.width;
- childAllocation.ascent = vloat->size.ascent;
- childAllocation.descent = vloat->size.descent;
-
- vloat->getWidget()->sizeAllocate (&childAllocation);
- }
-
- *lastAllocatedFloat = newLastAllocatedFloat;
-
- DBG_OBJ_LEAVE ();
-}
-
-
-/**
- * \brief ...
- *
- * gbX is given relative to the CB, as is the return value.
- */
-int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbLineBreakWidth)
-{
- DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d, %d",
- vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
- gbWidth, gbLineBreakWidth);
- int x;
-
- switch (side) {
- case LEFT:
- // Left floats are always aligned on the left side of the
- // generator (content, not allocation) ...
- x = gbX + vloat->generatingBlock->getStyle()->boxOffsetX();
- DBG_OBJ_MSGF ("resize.oofm", 1, "left: x = %d + %d = %d",
- gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x);
- // ... but when the float exceeds the line break width of the
- // container, it is corrected (but not left of the container).
- // This way, we save space and, especially within tables, avoid
- // some problems.
- if (wasAllocated (containingBlock) &&
- x + vloat->size.width > containingBlock->getLineBreakWidth ()) {
- x = max (0, containingBlock->getLineBreakWidth () - vloat->size.width);
- DBG_OBJ_MSGF ("resize.common", 1,
- "corrected to: max (0, %d - %d) = %d",
- containingBlock->getLineBreakWidth (), vloat->size.width,
- x);
- }
- break;
-
- case RIGHT:
- // Similar for right floats, but in this case, floats are
- // shifted to the right when they are too big (instead of
- // shifting the generator to the right).
-
- // Notice that not the actual width, but the line break width is
- // used. (This changed for GROWS, where the width of a textblock
- // is often smaller that the line break.)
-
- x = max (gbX + gbLineBreakWidth - vloat->size.width
- - vloat->generatingBlock->getStyle()->boxRestWidth(),
- // Do not exceed CB allocation:
- 0);
- DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d",
- gbX, gbLineBreakWidth, vloat->size.width,
- vloat->generatingBlock->getStyle()->boxRestWidth(), x);
- break;
-
- default:
- assertNotReached ();
- x = 0;
- break;
- }
-
- DBG_OBJ_LEAVE ();
- return x;
-}
-
-
-void OutOfFlowMgr::draw (View *view, Rectangle *area)
-{
- DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
- area->x, area->y, area->width, area->height);
-
- drawFloats (leftFloatsCB, view, area);
- drawFloats (rightFloatsCB, view, area);
- drawAbsolutelyPositioned (view, area);
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::drawFloats (SortedFloatsVector *list, View *view,
- Rectangle *area)
-{
- // This could be improved, since the list is sorted: search the
- // first float fitting into the area, and iterate until one is
- // found below the area.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- Rectangle childArea;
- if (vloat->getWidget()->intersects (area, &childArea))
- vloat->getWidget()->draw (view, &childArea);
- }
-}
-
-void OutOfFlowMgr::drawAbsolutelyPositioned (View *view, Rectangle *area)
-{
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- Widget *child = absolutelyPositioned->get(i);
- Rectangle childArea;
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
- }
-}
-
-/**
- * This method consideres also the attributes not yet considered by
- * dillo, so that the containing block is determined correctly, which
- * leads sometimes to a cleaner rendering.
- */
-bool OutOfFlowMgr::isWidgetOutOfFlow (Widget *widget)
-{
- // This is only half-baked, will perhaps be reactivated:
- //
- //return
- // widget->getStyle()->vloat != FLOAT_NONE ||
- // widget->getStyle()->position == POSITION_ABSOLUTE ||
- // widget->getStyle()->position == POSITION_FIXED;
-
- return isWidgetHandledByOOFM (widget);
-}
-
-bool OutOfFlowMgr::isWidgetHandledByOOFM (Widget *widget)
-{
- // May be extended for fixed (and relative?) positions.
- return isWidgetFloat (widget) || isWidgetAbsolutelyPositioned (widget);
-}
-
-void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock,
- Textblock *parentBlock, int externalIndex)
-{
- //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n",
- // containingBlock, textblock, parentBlock, externalIndex);
-
- TBInfo *tbInfo =
- new TBInfo (this, textblock,
- parentBlock ? getTextblock (parentBlock) : NULL,
- externalIndex);
- tbInfo->index = tbInfos->size();
-
- tbInfos->put (tbInfo);
- tbInfosByTextblock->put (new TypedPointer<Textblock> (textblock), tbInfo);
-}
-
-void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
- int externalIndex)
-{
- DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d",
- widget, generatingBlock, externalIndex);
-
- if (isWidgetFloat (widget)) {
- TBInfo *tbInfo = getTextblock (generatingBlock);
-
- Float *vloat = new Float (this, widget, generatingBlock, externalIndex);
-
- // Note: Putting the float first in the GB list, and then,
- // possibly into the CB list (in that order) will trigger
- // setting Float::inCBList to the right value.
-
- switch (widget->getStyle()->vloat) {
- case FLOAT_LEFT:
- leftFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefLeftFloat (leftFloatsAll->size() - 1);
- tbInfo->leftFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- leftFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastLeftTBIndex)
- leftFloatsMark++;
-
- vloat->mark = leftFloatsMark;
- //printf ("[%p] adding left float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastLeftTBIndex);
-
- lastLeftTBIndex = tbInfo->index;
- }
- break;
-
- case FLOAT_RIGHT:
- rightFloatsAll->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
- "widget", vloat->getWidget ());
-
- widget->parentRef = createRefRightFloat (rightFloatsAll->size() - 1);
- tbInfo->rightFloatsGB->put (vloat);
-
- if (wasAllocated (generatingBlock)) {
- rightFloatsCB->put (vloat);
- DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size());
- DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1,
- "widget", vloat->getWidget ());
- } else {
- if (tbInfo->index < lastRightTBIndex)
- rightFloatsMark++;
-
- vloat->mark = rightFloatsMark;
- //printf ("[%p] adding right float %p (%s %p, mark %d) to GB list "
- // "(index %d, last = %d)\n",
- // containingBlock, vloat, widget->getClassName(), widget,
- // vloat->mark, tbInfo->index, lastRightTBIndex);
-
- lastRightTBIndex = tbInfo->index;
- }
-
- break;
-
- default:
- assertNotReached();
- }
-
- // "sideSpanningIndex" is only compared, so this simple
- // assignment is sufficient; differenciation between GB and CB
- // lists is not neccessary. TODO: Can this also be applied to
- // "index", to simplify the current code? Check: where is
- // "index" used.
- vloat->sideSpanningIndex =
- leftFloatsAll->size() + rightFloatsAll->size() - 1;
-
- floatsByWidget->put (new TypedPointer<Widget> (widget), vloat);
- } else if (isWidgetAbsolutelyPositioned (widget)) {
- absolutelyPositioned->put (widget);
- widget->parentRef =
- createRefAbsolutelyPositioned (absolutelyPositioned->size() - 1);
- DBG_OBJ_SET_NUM ("absolutelyPositioned.size",
- absolutelyPositioned->size());
- DBG_OBJ_ARRSET_NUM ("absolutelyPositioned",
- absolutelyPositioned->size() - 1, widget);
- } else
- // May be extended.
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::moveExternalIndices (Textblock *generatingBlock,
- int oldStartIndex, int diff)
-{
- TBInfo *tbInfo = getTextblock (generatingBlock);
- moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff);
- moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff);
-}
-
-void OutOfFlowMgr::moveExternalIndices (SortedFloatsVector *list,
- int oldStartIndex, int diff)
-{
- // Could be faster with binary search, but the GB (not CB!) lists
- // should be rather small.
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- if (vloat->externalIndex >= oldStartIndex) {
- vloat->externalIndex += diff;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex",
- vloat->externalIndex);
- }
- }
-}
-
-OutOfFlowMgr::Float *OutOfFlowMgr::findFloatByWidget (Widget *widget)
-{
- TypedPointer <Widget> key (widget);
- Float *vloat = floatsByWidget->get (&key);
- assert (vloat != NULL);
- return vloat;
-}
-
-void OutOfFlowMgr::markSizeChange (int ref)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref);
-
- if (isRefFloat (ref)) {
- Float *vloat;
-
- if (isRefLeftFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = leftFloatsAll->get (i);
- //printf (" => left float %d\n", i);
- } else if (isRefRightFloat (ref)) {
- int i = getFloatIndexFromRef (ref);
- vloat = rightFloatsAll->get (i);
- //printf (" => right float %d\n", i);
- } else {
- assertNotReached();
- vloat = NULL; // compiler happiness
- }
-
- vloat->dirty = vloat->sizeChangedSinceLastAllocation = true;
-
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty);
- DBG_OBJ_SET_BOOL_O (vloat->getWidget (),
- "<Float>.sizeChangedSinceLastAllocation",
- vloat->sizeChangedSinceLastAllocation);
-
- // The generating block is told directly about this. (Others later, in
- // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which
- // differentiates many special cases), but the size is not known yet,
- vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ());
- } else if (isRefAbsolutelyPositioned (ref)) {
- // Nothing to do.
- } else
- assertNotReached();
-
- DBG_OBJ_LEAVE ();
-}
-
-
-void OutOfFlowMgr::markExtremesChange (int ref)
-{
- // Nothing to do here.
-}
-
-Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level)
-{
- Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level);
- if (childAtPoint == NULL)
- childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level);
- if (childAtPoint == NULL)
- childAtPoint = getAbsolutelyPositionedWidgetAtPoint (x, y, level);
- return childAtPoint;
-}
-
-Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list,
- int x, int y, int level)
-{
- for (int i = 0; i < list->size(); i++) {
- // Could use binary search to be faster.
- Float *vloat = list->get(i);
- if (vloat->getWidget()->wasAllocated ()) {
- Widget *childAtPoint =
- vloat->getWidget()->getWidgetAtPoint (x, y, level + 1);
- if (childAtPoint)
- return childAtPoint;
- }
- }
-
- return NULL;
-}
-
-Widget *OutOfFlowMgr::getAbsolutelyPositionedWidgetAtPoint (int x, int y,
- int level)
-{
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- Widget *child = absolutelyPositioned->get(i);
- if (child->wasAllocated ()) {
- Widget *childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
- if (childAtPoint)
- return childAtPoint;
- }
- }
-
- return NULL;
-}
-
-void OutOfFlowMgr::tellPosition (Widget *widget, int yReq)
-{
- if (isWidgetFloat (widget))
- tellFloatPosition (widget, yReq);
-
- // Nothing to do for absolutely positioned blocks.
-}
-
-
-void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "tellFloatPosition", "%p, %d",
- widget, yReq);
-
- assert (yReq >= 0);
-
- Float *vloat = findFloatByWidget(widget);
-
- SortedFloatsVector *listSame, *listOpp;
- Side side;
- getFloatsListsAndSide (vloat, &listSame, &listOpp, &side);
- ensureFloatSize (vloat);
-
- // "yReal" may change due to collisions (see below).
- vloat->yReq = vloat->yReal = yReq;
-
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq);
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
-
- // Test collisions (on this side). Although there are (rare) cases
- // where it could make sense, the horizontal dimensions are not
- // tested; especially since searching and border calculation would
- // be confused. For this reaspn, only the previous float is
- // relevant. (Cf. below, collisions on the other side.)
- int index = vloat->getIndex (listSame->type), yRealNew;
- if (index >= 1 &&
- collidesV (vloat, listSame->get (index - 1), listSame->type,
- &yRealNew)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- }
-
- // Test collisions (on the opposite side). There are cases when
- // more than one float has to be tested. Consider the following
- // HTML snippet ("id" attribute only used for simple reference
- // below, as #f1, #f2, and #f3):
- //
- // <div style="float:left" id="f1">
- // Left left left left left left left left left left.
- // </div>
- // <div style="float:left" id="f2">Also left.</div>
- // <div style="float:right" id="f3">Right.</div>
- //
- // When displayed with a suitable window width (only slightly wider
- // than the text within #f1), this should look like this:
- //
- // ---------------------------------------------------------
- // | Left left left left left left left left left left. |
- // | Also left. Right. |
- // ---------------------------------------------------------
- //
- // Consider float #f3: a collision test with #f2, considering
- // vertical dimensions, is positive, but not the test with
- // horizontal dimensions (because #f2 and #f3 are too
- // narrow). However, a collision has to be tested with #f1;
- // otherwise #f3 and #f1 would overlap.
-
- int oppFloatIndex =
- listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex);
- // Generally, the rules are simple: loop as long as the vertical
- // dimensions test is positive (and, of course, there are floats),
- // ...
- for (bool foundColl = false;
- !foundColl && oppFloatIndex >= 0 &&
- collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type,
- &yRealNew);
- oppFloatIndex--) {
- // ... but stop the loop as soon as the horizontal dimensions
- // test is positive.
- if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) {
- vloat->yReal = yRealNew;
- DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal);
- foundColl = true;
- }
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d",
- vloat->yReq, vloat->yReal);
-
- DBG_OBJ_LEAVE ();
-}
-
-bool OutOfFlowMgr::collidesV (Float *vloat, Float *other, SFVType type,
- int *yReal)
-{
- // Only checks vertical (possible) collisions, and only refers to
- // vloat->yReal; never to vloat->allocation->y, even when the GBs are
- // different. Used only in tellPosition.
-
- DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...",
- vloat->getIndex (type), vloat->getWidget (),
- other->getIndex (type), other->getWidget ());
-
- bool result;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal);
-
- if (vloat->generatingBlock == other->generatingBlock) {
- ensureFloatSize (other);
- int otherBottomGB =
- other->yReal + other->size.ascent + other->size.descent;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "same generators: otherBottomGB = %d + (%d + %d) = %d",
- other->yReal, other->size.ascent, other->size.descent,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- } else {
- assert (wasAllocated (vloat->generatingBlock));
- assert (wasAllocated (other->generatingBlock));
-
- // If the other float is not allocated, there is no collision. The
- // allocation of this float (vloat) is not used at all.
- if (!other->getWidget()->wasAllocated ())
- result = false;
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock),
- *flaOther = other->getWidget()->getAllocation ();
- int otherBottomGB =
- flaOther->y + flaOther->ascent + flaOther->descent - gba->y;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "different generators: "
- "otherBottomGB = %d + (%d + %d) - %d = %d",
- flaOther->y, flaOther->ascent, flaOther->descent, gba->y,
- otherBottomGB);
-
- if (vloat->yReal < otherBottomGB) {
- *yReal = otherBottomGB;
- result = true;
- } else
- result = false;
- }
- }
-
- if (result)
- DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal);
- else
- DBG_OBJ_MSG ("resize.oofm", 1, "does not collide");
-
- DBG_OBJ_LEAVE ();
- return result;
-}
-
-
-bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type)
-{
- // Only checks horizontal collision. For a complete test, use
- // collidesV (...) && collidesH (...).
- bool collidesH;
-
- if (vloat->generatingBlock == other->generatingBlock)
- collidesH = vloat->size.width + other->size.width
- + vloat->generatingBlock->getStyle()->boxDiffWidth()
- > vloat->generatingBlock->getLineBreakWidth();
- else {
- assert (wasAllocated (vloat->generatingBlock));
- assert (wasAllocated (other->generatingBlock));
-
- // Again, if the other float is not allocated, there is no
- // collision. Compare to collidesV. (But vloat->size is used
- // here.)
- if (!other->getWidget()->wasAllocated ())
- collidesH = false;
- else {
- Allocation *gba = getAllocation (vloat->generatingBlock);
- int vloatX =
- calcFloatX (vloat,
- vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
- LEFT : RIGHT,
- gba->x, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
-
- // Generally: right border of the left float > left border of
- // the right float (all in canvas coordinates).
- if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT)
- // "vloat" is left, "other" is right
- collidesH = vloatX + vloat->size.width
- > other->getWidget()->getAllocation()->x;
- else
- // "other" is left, "vloat" is right
- collidesH = other->getWidget()->getAllocation()->x
- + other->getWidget()->getAllocation()->width
- > vloatX;
- }
- }
-
- return collidesH;
-}
-
-void OutOfFlowMgr::getFloatsListsAndSide (Float *vloat,
- SortedFloatsVector **listSame,
- SortedFloatsVector **listOpp,
- Side *side)
-{
- TBInfo *tbInfo = getTextblock (vloat->generatingBlock);
-
- switch (vloat->getWidget()->getStyle()->vloat) {
- case FLOAT_LEFT:
- if (wasAllocated (vloat->generatingBlock)) {
- if (listSame) *listSame = leftFloatsCB;
- if (listOpp) *listOpp = rightFloatsCB;
- } else {
- if (listSame) *listSame = tbInfo->leftFloatsGB;
- if (listOpp) *listOpp = tbInfo->rightFloatsGB;
- }
- if (side) *side = LEFT;
- break;
-
- case FLOAT_RIGHT:
- if (wasAllocated (vloat->generatingBlock)) {
- if (listSame) *listSame = rightFloatsCB;
- if (listOpp) *listOpp = leftFloatsCB;
- } else {
- if (listSame) *listSame = tbInfo->rightFloatsGB;
- if (listOpp) *listOpp = tbInfo->leftFloatsGB;
- }
- if (side) *side = RIGHT;
- break;
-
- default:
- assertNotReached();
- }
-}
-
-void OutOfFlowMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight)
-{
- DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize");
-
- int oofWidthAbsPos, oofHeightAbsPos;
- getAbsolutelyPositionedSize (cbReq, &oofWidthAbsPos, &oofHeightAbsPos);
-
- int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight;
- getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft);
- getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight);
-
- *oofWidth = max (oofWidthtLeft, oofWidthRight, oofWidthAbsPos);
- *oofHeight = max (oofHeightLeft, oofHeightRight, oofHeightAbsPos);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (a: %d, l: %d, r: %d => %d) * (a: %d, l: %d, r: %d => %d)",
- oofWidthAbsPos, oofWidthtLeft, oofWidthRight, *oofWidth,
- oofHeightAbsPos, oofHeightLeft, oofHeightRight, *oofHeight);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
- int *height)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...",
- cbReq->width, cbReq->ascent, cbReq->descent,
- side == LEFT ? "LEFT" : "RIGHT");
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
-
- *width = *height = 0;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
-
- if (vloat->generatingBlock == containingBlock ||
- wasAllocated (vloat->generatingBlock)) {
- ensureFloatSize (vloat);
- int x, y;
-
- if (vloat->generatingBlock == containingBlock) {
- x = calcFloatX (vloat, side, 0, cbReq->width,
- vloat->generatingBlock->getLineBreakWidth ());
- y = vloat->yReal;
- } else {
- Allocation *gba = getAllocation(vloat->generatingBlock);
- x = calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x, gba->width,
- vloat->generatingBlock->getLineBreakWidth ());
- y = gba->y - containingBlockAllocation.y + vloat->yReal;
- }
-
- *width = max (*width, x + vloat->size.width);
- *height = max (*height, y + vloat->size.ascent + vloat->size.descent);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: (%d + %d) * "
- "(%d + (%d + %d)) => %d * %d",
- vloat->getWidget (), vloat->generatingBlock,
- x, vloat->size.width,
- y, vloat->size.ascent, vloat->size.descent,
- *width, *height);
- } else
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: not allocated",
- vloat->getWidget (), vloat->generatingBlock);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth,
- int *oofMaxWidth)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...",
- cbExtr->minWidth, cbExtr->maxWidth);
-
- int oofMinWidthAbsPos, oofMaxWidthAbsPos;
- getAbsolutelyPositionedExtremes (cbExtr, &oofMinWidthAbsPos,
- &oofMaxWidthAbsPos);
-
- int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight;
- getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft);
- getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight);
-
- *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight, oofMinWidthAbsPos);
- *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight, oofMaxWidthAbsPos);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "=> (a: %d, l: %d, r: %d => %d) / (a: %d, l: %d, r: %d => %d)",
- oofMinWidthAbsPos, oofMinWidthtLeft, oofMinWidthRight,
- *oofMinWidth, oofMaxWidthAbsPos, oofMaxWidthLeft,
- oofMaxWidthRight, *oofMaxWidth);
- DBG_OBJ_LEAVE ();
-}
-
-void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
- int *minWidth, int *maxWidth)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...",
- cbExtr->minWidth, cbExtr->maxWidth,
- side == LEFT ? "LEFT" : "RIGHT");
-
- *minWidth = *maxWidth = 0;
-
- SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side);
- DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size());
-
- for (int i = 0; i < list->size(); i++) {
- Float *vloat = list->get(i);
- int leftDiff, rightDiff;
-
- if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) {
- Extremes extr;
- vloat->getWidget()->getExtremes (&extr);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: %d / %d",
- vloat->getWidget (), vloat->generatingBlock,
- extr.minWidth, extr.maxWidth);
-
- // TODO: Or zero (instead of rightDiff) for right floats?
- *minWidth =
- max (*minWidth,
- extr.minWidth + (side == LEFT ? leftDiff : rightDiff));
- *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff);
-
- DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth);
- } else
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "considering float %p generated by %p: not allocated",
- vloat->getWidget (), vloat->generatingBlock);
- }
-
- DBG_OBJ_LEAVE ();
-}
-
-// Returns "false" when borders cannot yet determined; *leftDiff and
-// *rightDiff are undefined in this case.
-bool OutOfFlowMgr::getFloatDiffToCB (Float *vloat, int *leftDiff,
- int *rightDiff)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB",
- "float %p [generated by %p], ...",
- vloat->getWidget (), vloat->generatingBlock);
-
- bool result;
-
- if (vloat->generatingBlock == containingBlock) {
- *leftDiff = vloat->generatingBlock->getStyle()->boxOffsetX();
- *rightDiff = vloat->generatingBlock->getStyle()->boxRestWidth();
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "GB == CB => leftDiff = %d, rightDiff = %d",
- *leftDiff, *rightDiff);
- } else if (wasAllocated (vloat->generatingBlock)) {
- Allocation *gba = getAllocation(vloat->generatingBlock);
- *leftDiff = gba->x - containingBlockAllocation.x
- + vloat->generatingBlock->getStyle()->boxOffsetX();
- *rightDiff =
- (containingBlockAllocation.x + containingBlockAllocation.width)
- - (gba->x + gba->width)
- + vloat->generatingBlock->getStyle()->boxRestWidth();
- result = true;
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "GB != CB => leftDiff = %d - %d + %d = %d, "
- "rightDiff = (%d + %d) - (%d + %d) + %d = %d",
- gba->x, containingBlockAllocation.x,
- vloat->generatingBlock->getStyle()->boxOffsetX(),
- *leftDiff, containingBlockAllocation.x,
- containingBlockAllocation.width, gba->x, gba->width,
- vloat->generatingBlock->getStyle()->boxRestWidth(),
- *rightDiff);
- } else {
- DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated");
- result = false;
- }
-
- DBG_OBJ_LEAVE ();
- return result;
-}
-
-OutOfFlowMgr::TBInfo *OutOfFlowMgr::getTextblock (Textblock *textblock)
-{
- TypedPointer<Textblock> key (textblock);
- TBInfo *tbInfo = tbInfosByTextblock->get (&key);
- assert (tbInfo);
- return tbInfo;
-}
-
-/**
- * Get the left border for the vertical position of *y*, for a height
- * of *h", based on floats; relative to the allocation of the calling
- * textblock.
- *
- * The border includes marging/border/padding of the calling textblock
- * but is 0 if there is no float, so a caller should also consider
- * other borders.
- */
-int OutOfFlowMgr::getLeftBorder (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d",
- textblock, y, h, lastGB, lastExtIndex, b);
- return b;
-}
-
-/**
- * Get the right border for the vertical position of *y*, for a height
- * of *h*, based on floats.
- *
- * See also getLeftBorder(int, int);
- */
-int OutOfFlowMgr::getRightBorder (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d",
- textblock, y, h, lastGB, lastExtIndex, b);
- return b;
-}
-
-int OutOfFlowMgr::getBorder (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int last;
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last);
-
- DBG_OBJ_MSGF ("border", 1, "first = %d", first);
-
- if (first == -1) {
- // No float.
- DBG_OBJ_LEAVE ();
- return 0;
- } else {
- // It is not sufficient to find the first float, since a line
- // (with height h) may cover the region of multiple float, of
- // which the widest has to be choosen.
- int border = 0;
- bool covers = true;
-
- // We are not searching until the end of the list, but until the
- // float defined by lastGB and lastExtIndex.
- for (int i = first; covers && i <= last; i++) {
- Float *vloat = list->get(i);
- covers = vloat->covers (textblock, y, h);
- DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.",
- i, vloat->getWidget(), covers ? "<b>yes</b>" : "no");
-
- if (covers) {
- int thisBorder;
- if (vloat->generatingBlock == textblock) {
- int borderIn = side == LEFT ?
- vloat->generatingBlock->getStyle()->boxOffsetX() :
- vloat->generatingBlock->getStyle()->boxRestWidth();
- thisBorder = vloat->size.width + borderIn;
- DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d",
- vloat->size.width, borderIn, thisBorder);
- } else {
- assert (wasAllocated (vloat->generatingBlock));
- assert (vloat->getWidget()->wasAllocated ());
-
- Allocation *tba = getAllocation(textblock),
- *fla = vloat->getWidget()->getAllocation ();
- if (side == LEFT) {
- thisBorder = fla->x + fla->width - tba->x;
- DBG_OBJ_MSGF ("border", 1,
- "not GB: thisBorder = %d + %d - %d = %d",
- fla->x, fla->width, tba->x, thisBorder);
- } else {
- // See also calcFloatX.
- thisBorder =
- tba->x + textblock->getLineBreakWidth () - fla->x;
- DBG_OBJ_MSGF ("border", 1,
- "not GB: thisBorder = %d + %d - %d "
- "= %d",
- tba->x, textblock->getLineBreakWidth (), fla->x,
- thisBorder);
- }
- }
-
- border = max (border, thisBorder);
- DBG_OBJ_MSGF ("border", 1, "=> border = %d", border);
- }
- }
-
- DBG_OBJ_LEAVE ();
- return border;
- }
-}
-
-
-OutOfFlowMgr::SortedFloatsVector *OutOfFlowMgr::getFloatsListForTextblock
- (Textblock *textblock, Side side)
-{
- DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForTextblock", "%p, %s",
- textblock, side == LEFT ? "LEFT" : "RIGHT");
-
- OutOfFlowMgr::SortedFloatsVector *list;
-
- if (wasAllocated (textblock)) {
- DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list");
- list = side == LEFT ? leftFloatsCB : rightFloatsCB;
- } else {
- DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list");
- TBInfo *tbInfo = getTextblock (textblock);
- list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB;
- }
-
- DBG_OBJ_LEAVE ();
- return list;
-}
-
-
-bool OutOfFlowMgr::hasFloatLeft (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s",
- textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
- return b;
-}
-
-bool OutOfFlowMgr::hasFloatRight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex);
- DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s",
- textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false");
- return b;
-}
-
-bool OutOfFlowMgr::hasFloat (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
-
- DBG_OBJ_MSGF ("border", 1, "first = %d", first);
- DBG_OBJ_LEAVE ();
- return first != -1;
-}
-
-int OutOfFlowMgr::getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex);
-}
-
-int OutOfFlowMgr::getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex);
-}
-
-// Calculate height from the position *y*.
-int OutOfFlowMgr::getFloatHeight (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex)
-{
- DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d",
- textblock, side == LEFT ? "LEFT" : "RIGHT", y, h,
- lastGB, lastExtIndex);
-
- SortedFloatsVector *list = getFloatsListForTextblock (textblock, side);
- int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL);
- assert (first != -1); /* This method must not be called when there is no
- float on the respective side. */
-
- Float *vloat = list->get(first);
- int yRelToFloat;
-
- if (vloat->generatingBlock == textblock) {
- yRelToFloat = y - vloat->yReal;
- DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d",
- y, vloat->yReal, yRelToFloat);
- } else {
- // The respective widgets are allocated; otherwise, hasFloat() would have
- // returned false.
- assert (wasAllocated (textblock));
- assert (vloat->getWidget()->wasAllocated ());
-
- Allocation *tba = getAllocation(textblock),
- *fla = vloat->getWidget()->getAllocation ();
- yRelToFloat = y + fla->y - tba->y;
-
- DBG_OBJ_MSGF ("border", 1,
- "caller is not CB: yRelToFloat = %d + %d - %d = %d",
- y, fla->y, tba->y, yRelToFloat);
- }
-
- ensureFloatSize (vloat);
- int height = vloat->size.ascent + vloat->size.descent + yRelToFloat;
-
- DBG_OBJ_MSGF ("border", 1, "=> %d", height);
- DBG_OBJ_LEAVE ();
- return height;
-}
-
-/**
- * Returns position relative to the textblock "tb".
- */
-int OutOfFlowMgr::getClearPosition (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 ? getClearPosition (tb, LEFT) : 0,
- right ? getClearPosition (tb, RIGHT) : 0);
- } else
- pos = 0;
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos);
- DBG_OBJ_LEAVE ();
-
- return pos;
-}
-
-int OutOfFlowMgr::getClearPosition (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);
- ensureFloatSize (vloat);
- pos = vloat->yReal + vloat->size.ascent + vloat->size.descent -
- getAllocation(tb)->y;
- DBG_OBJ_MSGF ("resize.oofm", 1, "float %p => %d + (%d + %d) - %d",
- vloat->getWidget (), 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 ();
-}
-
-int OutOfFlowMgr::getAvailWidthOfChild (Widget *child, bool forceValue)
-{
- DBG_OBJ_ENTER ("resize.oofm", 0,
- "OutOfFlowMgr/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 = containingBlock->getAvailWidth (true);
- width = max (availWidth - containingBlock->boxDiffWidth ()
- - getAbsPosLeft (child, availWidth)
- - getAbsPosRight (child, availWidth),
- 0);
- } else
- width = -1;
- } else
- // TODO Percentage widths must refer to padding area.
- child->calcFinalWidth (child->getStyle(), -1, containingBlock, 0,
- forceValue, &width);
-
- if (width != -1)
- width = max (width, child->getMinWidth (NULL, forceValue));
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", width);
- DBG_OBJ_LEAVE ();
-
- return width;
-}
-
-int OutOfFlowMgr::getAvailHeightOfChild (Widget *child, bool forceValue)
-{
- // TODO FF shows a bit different priority for heights than for
- // widths, in case of over-determined values.
-
- DBG_OBJ_ENTER ("resize.oofm", 0,
- "OutOfFlowMgr/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 = containingBlock->getAvailHeight (true);
- height = max (availHeight - containingBlock->boxDiffHeight ()
- - getAbsPosTop (child, availHeight)
- - getAbsPosBottom (child, availHeight),
- 0);
- } else
- height = -1;
- } else
- // TODO Percentage heights must refer to padding area.
- height = child->calcHeight (child->getStyle()->height, true, -1,
- containingBlock, forceValue);
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", height);
- DBG_OBJ_LEAVE ();
-
- return height;
-}
-
-void OutOfFlowMgr::getAbsolutelyPositionedSize (Requisition *cbReq, int *width,
- int *height)
-{
- // TODO
- *width = *height = 0;
-}
-
-int OutOfFlowMgr::getAbsPosBorder (style::Length cssValue, int refLength)
-{
- if (style::isAbsLength (cssValue))
- return style::absLengthVal (cssValue);
- else if (style::isPerLength (cssValue))
- return style::multiplyWithPerLength (refLength, cssValue);
- else
- // standard value for 'left', 'right', 'top', 'bottom':
- return 0;
-}
-
-void OutOfFlowMgr::getAbsolutelyPositionedExtremes (Extremes *cbExtr,
- int *minWidth,
- int *maxWidth)
-{
- // TODO
- *minWidth = *maxWidth = 0;
-}
-
-void OutOfFlowMgr::sizeAllocateAbsolutelyPositioned ()
-{
- DBG_OBJ_ENTER0 ("resize.oofm", 0, "sizeAllocateAbsolutelyPositioned");
-
- Allocation *cbAllocation = getAllocation (containingBlock);
- //int refWidth = containingBlock->getAvailWidth (true);
- //int refHeight = containingBlock->getAvailHeight (true);
- int refWidth = cbAllocation->width;
- int refHeight = cbAllocation->ascent + cbAllocation->descent;
-
- for (int i = 0; i < absolutelyPositioned->size(); i++) {
- Widget *child = absolutelyPositioned->get (i);
-
- Requisition childRequisition;
- child->sizeRequest (&childRequisition);
-
- Allocation childAllocation;
-
- childAllocation.x = cbAllocation->x + getAbsPosLeft (child, refWidth);
- childAllocation.y = cbAllocation->y + getAbsPosTop (child, refHeight);
- // TODO (i) Consider {min|max}-{width|heigt}. (ii) Clarify where
- // sizes refer to. (iii) Height is always apportioned to descent
- // (ascent is preserved), which makes sense when the children
- // are textblocks. (iv) Consider minimal length?
-
- if (style::isAbsLength (child->getStyle()->width))
- childAllocation.width = style::absLengthVal (child->getStyle()->width);
- else if (style::isPerLength (child->getStyle()->width))
- childAllocation.width =
- style::multiplyWithPerLength (refWidth, child->getStyle()->width);
- else
- childAllocation.width = childRequisition.width;
-
- childAllocation.ascent = childRequisition.ascent;
- childAllocation.descent = childRequisition.descent;
- if (style::isAbsLength (child->getStyle()->height)) {
- int height = style::absLengthVal (child->getStyle()->height);
- splitHeightPreserveAscent (height, &childAllocation.ascent,
- &childAllocation.descent);
- } else if (style::isPerLength (child->getStyle()->height)) {
- int height = style::multiplyWithPerLength (refHeight,
- child->getStyle()->height);
- splitHeightPreserveAscent (height, &childAllocation.ascent,
- &childAllocation.descent);
- }
-
- child->sizeAllocate (&childAllocation);
- }
-
- DBG_OBJ_LEAVE ();
}
} // namespace dw
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index c5579368..1ac5b7ec 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -12,457 +12,62 @@ class Textblock;
*/
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;
-
- // 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;
-
- lout::container::typed::Vector<core::Widget> *absolutelyPositioned;
-
- int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
-
- /**
- * Variant of Widget::wasAllocated(), which can also be used within
- * OOFM::sizeAllocateEnd().
- */
- inline bool wasAllocated (Textblock *textblock) {
- return getTextblock(textblock)->wasAllocated;
- }
-
- /**
- * Variant of Widget::getAllocation(), which can also be used
- * within OOFM::sizeAllocateEnd().
- */
- inline core::Allocation *getAllocation (Textblock *textblock) {
- return &(getTextblock(textblock)->allocation);
- }
-
- void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
- int diff);
- Float *findFloatByWidget (core::Widget *widget);
-
- void moveFromGBToCB (Side side);
- void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
- int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbLineBreakWidth);
-
- bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos,
- core::Widget **minFloat);
- bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos,
- core::Widget **minFloat);
- bool hasRelationChanged (bool oldTBAlloc,
- int oldTBx, int oldTBy, int oldTBw, int oldTBh,
- int newTBx, int newTBy, int newTBw, int newTBh,
- bool oldFlAlloc,
- int oldFlx, int oldFly, int oldFlw, int oldFlh,
- int newFlx, int newFly, int newFlw, int newFlh,
- Side side, int *floatPos);
-
- void checkAllocatedFloatCollisions (Side side);
-
- bool doFloatsExceedCB (Side side);
- bool haveExtremesChanged (Side side);
-
- void drawFloats (SortedFloatsVector *list, core::View *view,
- core::Rectangle *area);
- void drawAbsolutelyPositioned (core::View *view, core::Rectangle *area);
- core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
- int level);
- core::Widget *getAbsolutelyPositionedWidgetAtPoint (int x, int y, int level);
-
- bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal);
- bool collidesH (Float *vloat, Float *other, SFVType type);
-
- void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
- SortedFloatsVector **listOpp, Side *side);
-
- void getFloatsSize (core::Requisition *cbReq, Side side, int *width,
- int *height);
- void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth,
- int *maxWidth);
- bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff);
-
- TBInfo *getTextblock (Textblock *textblock);
- int getBorder (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- SortedFloatsVector *getFloatsListForTextblock (Textblock *textblock,
- Side side);
- bool hasFloat (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getFloatHeight (Textblock *textblock, Side side, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getClearPosition (Textblock *tb, Side side);
-
- void ensureFloatSize (Float *vloat);
-
- void tellFloatPosition (core::Widget *widget, int yReq);
-
- void getAbsolutelyPositionedSize (core::Requisition *cbReq, int *width,
- int *height);
- void getAbsolutelyPositionedExtremes (core::Extremes *cbExtr, int *minWidth,
- int *maxWidth);
- void sizeAllocateAbsolutelyPositioned ();
-
- inline int getAbsPosLeft (core::Widget *child, int availWidth)
- { return getAbsPosBorder (child->getStyle()->left, availWidth); }
- inline int getAbsPosRight (core::Widget *child, int availWidth)
- { return getAbsPosBorder (child->getStyle()->right, availWidth); }
- inline int getAbsPosTop (core::Widget *child, int availHeight)
- { return getAbsPosBorder (child->getStyle()->top, availHeight); }
- inline int getAbsPosBottom (core::Widget *child, int availHeight)
- { return getAbsPosBorder (child->getStyle()->bottom, availHeight); }
-
- int getAbsPosBorder (core::style::Length cssValue, int refLength);
-
- static inline bool isWidgetFloat (core::Widget *widget)
- { return widget->getStyle()->vloat != core::style::FLOAT_NONE; }
- static inline bool isWidgetAbsolutelyPositioned (core::Widget *widget)
- { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; }
-
- /*
- * Format for parent ref (see also below for isRefOutOfFlow,
- * createRefNormalFlow, and getLineNoFromRef.
- *
- * Widget in flow:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | line number | 0 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * So, anything with the least signifant bit set to 1 is out of flow.
- *
- * Floats:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | left float index | 0 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | right float index | 1 | 0 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- *
- * Absolutely positioned blocks:
- *
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- * | index | 1 | 1 |
- * +---+ - - - +---+---+- - - - - -+---+---+---+---+
- */
-
- inline static bool isRefFloat (int ref)
- { return ref != -1 && (ref & 3) == 1; }
- inline static bool isRefLeftFloat (int ref)
- { return ref != -1 && (ref & 7) == 1; }
- inline static bool isRefRightFloat (int ref)
- { return ref != -1 && (ref & 7) == 5; }
- inline static bool isRefAbsolutelyPositioned (int ref)
- { return ref != -1 && (ref & 3) == 3; }
-
- inline static int createRefLeftFloat (int index)
- { return (index << 3) | 1; }
- inline static int createRefRightFloat (int index)
- { return (index << 3) | 5; }
- inline static int createRefAbsolutelyPositioned (int index)
- { return (index << 2) | 3; }
-
- inline static int getFloatIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 3); }
- inline static int getAbsolutelyPositionedIndexFromRef (int ref)
- { return ref == -1 ? ref : (ref >> 2); }
-
public:
- OutOfFlowMgr (Textblock *containingBlock);
- ~OutOfFlowMgr ();
-
- void sizeAllocateStart (Textblock *caller, core::Allocation *allocation);
- void sizeAllocateEnd (Textblock *caller);
- void containerSizeChangedForChildren ();
- void draw (core::View *view, core::Rectangle *area);
-
- void markSizeChange (int ref);
- void markExtremesChange (int ref);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
-
- static bool isWidgetOutOfFlow (core::Widget *widget);
- static bool isWidgetHandledByOOFM (core::Widget *widget);
- void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
- int externalIndex);
- void addWidgetOOF (core::Widget *widget, Textblock *generatingBlock,
- int externalIndex);
- void moveExternalIndices (Textblock *generatingBlock, int oldStartIndex,
- int diff);
-
- void tellPosition (core::Widget *widget, int yReq);
-
- void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight);
- void getExtremes (core::Extremes *cbExtr,
- int *oofMinWidth, int *oofMaxWidth);
-
- int getLeftBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- int getRightBorder (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- bool hasFloatLeft (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
- bool hasFloatRight (Textblock *textblock, int y, int h, Textblock *lastGB,
- int lastExtIndex);
-
- int getLeftFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
- int getRightFloatHeight (Textblock *textblock, int y, int h,
- Textblock *lastGB, int lastExtIndex);
-
- int getClearPosition (Textblock *tb);
-
- inline bool dealingWithSizeOfChild (core::Widget *child)
- { return isWidgetAbsolutelyPositioned (child); }
-
- int getAvailWidthOfChild (core::Widget *child, bool forceValue);
- int getAvailHeightOfChild (core::Widget *child, bool forceValue);
-
- 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 (Textblock *caller,
+ core::Allocation *allocation) = 0;
+ virtual void sizeAllocateEnd (Textblock *caller) = 0;
+ virtual void containerSizeChangedForChildren () = 0;
+ virtual void draw (core::View *view, core::Rectangle *area) = 0;
+
+ virtual void markSizeChange (int ref) = 0;
+ virtual void markExtremesChange (int ref) = 0;
+ virtual core::Widget *getWidgetAtPoint (int x, int y, int level) = 0;
+
+ virtual void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock,
+ int externalIndex) = 0;
+ virtual int addWidgetOOF (core::Widget *widget, Textblock *generatingBlock,
+ int externalIndex) = 0;
+ virtual void moveExternalIndices (Textblock *generatingBlock,
+ int oldStartIndex, int diff) = 0;
+
+ virtual void tellPosition (core::Widget *widget, int yReq) = 0;
+
+ virtual void getSize (core::Requisition *cbReq, int *oofWidth,
+ int *oofHeight) = 0;
+ virtual void getExtremes (core::Extremes *cbExtr, int *oofMinWidth,
+ int *oofMaxWidth) = 0;
+
+
+ virtual int getLeftBorder (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+ virtual int getRightBorder (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+
+ virtual bool hasFloatLeft (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+ virtual bool hasFloatRight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+
+ virtual int getLeftFloatHeight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+ virtual int getRightFloatHeight (Textblock *textblock, int y, int h,
+ Textblock *lastGB, int lastExtIndex) = 0;
+
+ virtual bool affectsLeftBorder (core::Widget *widget) = 0;
+ virtual bool affectsRightBorder (core::Widget *widget) = 0;
+
+ virtual int getClearPosition (Textblock *textblock) = 0;
+
+ virtual bool dealingWithSizeOfChild (core::Widget *child) = 0;
+ virtual int getAvailWidthOfChild (core::Widget *child, bool forceValue) = 0;
+ virtual int getAvailHeightOfChild (core::Widget *child, bool forceValue) = 0;
// for iterators
- inline int getNumWidgets () {
- return leftFloatsAll->size() + rightFloatsAll->size() +
- absolutelyPositioned->size(); }
-
- inline core::Widget *getWidget (int i) {
- if (i < leftFloatsAll->size())
- return leftFloatsAll->get(i)->getWidget ();
- else if (i < leftFloatsAll->size() + rightFloatsAll->size())
- return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
- else
- return absolutelyPositioned->get(i - (leftFloatsAll->size() +
- rightFloatsAll->size()));
- }
-
- 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 dw
diff --git a/dw/textblock.cc b/dw/textblock.cc
index bfa59502..caf4b558 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -19,6 +19,9 @@
#include "textblock.hh"
+#include "ooffloatsmgr.hh"
+#include "oofposabsmgr.hh"
+#include "oofposfixedmgr.hh"
#include "../lout/msg.h"
#include "../lout/misc.hh"
#include "../lout/unicode.hh"
@@ -227,7 +230,11 @@ Textblock::Textblock (bool limitTextWidth)
registerName ("dw::Textblock", &CLASS_ID);
setButtonSensitive(true);
- containingBlock = NULL;
+ for (int i = 0; i < NUM_OOFM; i++) {
+ containingBlock[i] = NULL;
+ outOfFlowMgr[i] = NULL;
+ }
+
hasListitemValue = false;
leftInnerPadding = 0;
line1Offset = 0;
@@ -252,7 +259,6 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
- outOfFlowMgr = NULL;
wrapRefLines = wrapRefParagraphs = -1;
@@ -304,14 +310,16 @@ 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;
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if(outOfFlowMgr[i]) {
+ // I feel more comfortable by letting the textblock 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];
+ }
}
/* Make sure we don't own widgets anymore. Necessary before call of
@@ -406,24 +414,28 @@ 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;
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ int oofWidth, oofHeight;
+ DBG_OBJ_MSGF ("resize", 1,
+ "before considering widgets by OOFM #%d: %d * (%d + %d)",
+ i, requisition->width, requisition->ascent,
+ requisition->descent);
+
+ outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight);
+
+ // Widgets OOF 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;
+ }
}
DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)",
@@ -505,19 +517,21 @@ 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);
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "OOFM (#%d) correction: %d / %d",
+ i, oofMinWidth, oofMaxWidth);
+
+ extremes->minWidth = 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);
+ }
}
DBG_OBJ_MSGF ("resize", 0,
@@ -578,8 +592,10 @@ 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);
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (containingBlock[i]->outOfFlowMgr[i])
+ containingBlock[i]->outOfFlowMgr[i]->sizeAllocateStart (this,
+ allocation);
int lineIndex, wordIndex;
Line *line;
@@ -707,9 +723,10 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
DBG_OBJ_MSG_END ();
- if (containingBlock->outOfFlowMgr)
- containingBlock->outOfFlowMgr->sizeAllocateEnd (this);
-
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (containingBlock[i]->outOfFlowMgr[i])
+ containingBlock[i]->outOfFlowMgr[i]->sizeAllocateEnd (this);
+
for (int i = 0; i < anchors->size(); i++) {
Anchor *anchor = anchors->getRef(i);
int y;
@@ -736,8 +753,10 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
int width = Widget::getAvailWidthOfChild (child, forceValue);
- if (outOfFlowMgr && outOfFlowMgr->dealingWithSizeOfChild (child))
- width = outOfFlowMgr->getAvailWidthOfChild (child, forceValue);
+ if (isWidgetOOF(child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ width =
+ getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child, forceValue);
else {
if (forceValue && this == child->getContainer () &&
!mustBeWidenedToAvailWidth ()) {
@@ -755,8 +774,10 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
int Textblock::getAvailHeightOfChild (core::Widget *child, bool forceValue)
{
- if (outOfFlowMgr && outOfFlowMgr->dealingWithSizeOfChild (child))
- return outOfFlowMgr->getAvailHeightOfChild (child, forceValue);
+ if (isWidgetOOF(child) && getWidgetOutOfFlowMgr(child) &&
+ getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
+ return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child,
+ forceValue);
else
return Widget::getAvailHeightOfChild (child, forceValue);
}
@@ -771,9 +792,10 @@ void Textblock::containerSizeChangedForChildren ()
word->content.widget->containerSizeChanged ();
}
- if (outOfFlowMgr)
- outOfFlowMgr->containerSizeChangedForChildren ();
-
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (outOfFlowMgr[i])
+ outOfFlowMgr[i]->containerSizeChangedForChildren ();
+
DBG_OBJ_LEAVE ();
}
@@ -825,13 +847,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
@@ -839,10 +858,9 @@ void Textblock::markSizeChange (int ref)
now, but addLine(...) will do everything necessary. */
if (ref != -1) {
if (wrapRefLines == -1)
- wrapRefLines = OutOfFlowMgr::getLineNoFromRef (ref);
+ wrapRefLines = getParentRefLineNo (ref);
else
- wrapRefLines = misc::min (wrapRefLines,
- OutOfFlowMgr::getLineNoFromRef (ref));
+ wrapRefLines = misc::min (wrapRefLines, getParentRefLineNo (ref));
}
DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
@@ -862,13 +880,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
@@ -876,11 +891,10 @@ void Textblock::markExtremesChange (int ref)
now, but addLine(...) will do everything necessary. */
if (ref != -1) {
if (wrapRefParagraphs == -1)
- wrapRefParagraphs = OutOfFlowMgr::getLineNoFromRef (ref);
+ wrapRefParagraphs = getParentRefLineNo (ref);
else
wrapRefParagraphs =
- misc::min (wrapRefParagraphs,
- OutOfFlowMgr::getLineNoFromRef (ref));
+ misc::min (wrapRefParagraphs, getParentRefLineNo (ref));
}
DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
@@ -891,52 +905,79 @@ void Textblock::markExtremesChange (int ref)
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 ||
- // Finally, "out of flow" in a narrower sense: floats and
- // absolute positions.
- OutOfFlowMgr::isWidgetOutOfFlow (widget));
+ containingBlock[OOFM_FLOATS] = containingBlock[OOFM_ABSOLUTE]
+ = containingBlock[OOFM_FIXED] = this;
+}
+
+bool Textblock::isContainingBlock (Widget *widget, int oofmIndex)
+{
+ switch (oofmIndex) {
+ case OOFM_FLOATS:
+ return
+ // For floats, 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 ||
+ // Finally, "out of flow" in a narrower sense: floats; absolutely
+ // and fixedly positioned elements.
+ testWidgetOutOfFlow (widget));
+
+ case OOFM_ABSOLUTE:
+ // Only the toplevel widget (as for all) as well as absolutely
+ // and fixedly positioned elements constitute the containing
+ // block for absolutely positioned elements, but neither floats
+ // nor other elements like table cells.
+ //
+ // We also test whether this widget is a textblock: is this
+ // necessary? (What about other absolutely widgets containing
+ // children, like tables? TODO: Check CSS spec.)
+
+ return widget->instanceOf (Textblock::CLASS_ID) &&
+ (widget->getParent() == NULL ||
+ testWidgetAbsolutelyPositioned (widget) ||
+ testWidgetFixedPositioned (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 Textblock::notifySetParent ()
{
- PRINTF ("%p becomes a child of %p\n", this, getParent());
+ // Search for containing blocks.
+ for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
+ containingBlock[oofmIndex] = NULL;
- // 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);
+ for (Widget *widget = this;
+ widget != NULL && containingBlock[oofmIndex] == NULL;
+ widget = widget->getParent ())
+ if (isContainingBlock (widget, oofmIndex)) {
+ assert (widget->instanceOf (Textblock::CLASS_ID));
+ containingBlock[oofmIndex] = (Textblock*)widget;
}
- }
+
+ DBG_OBJ_ARRSET_PTR ("containingBlock", oofmIndex,
+ containingBlock[oofmIndex]);
+ }
assert (containingBlock != NULL);
}
@@ -1763,8 +1804,9 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
drawLine (line, view, area);
}
- if(outOfFlowMgr)
- outOfFlowMgr->draw(view, area);
+ for (int i = 0; i < NUM_OOFM; i++)
+ if(outOfFlowMgr[i])
+ outOfFlowMgr[i]->draw(view, area);
DBG_OBJ_LEAVE ();
}
@@ -2310,6 +2352,31 @@ void Textblock::addText0 (const char *text, size_t len, short flags,
DBG_OBJ_LEAVE ();
}
+void Textblock::initOutOfFlowMgrs ()
+{
+ if (containingBlock[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] == NULL) {
+ containingBlock[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] =
+ new OOFFloatsMgr (containingBlock[OOFM_FLOATS]);
+ DBG_OBJ_ASSOC (containingBlock[OOFM_FLOATS],
+ containingBlock[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS]);
+ }
+
+ if (containingBlock[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] == NULL) {
+ containingBlock[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] =
+ new OOFPosAbsMgr (containingBlock[OOFM_ABSOLUTE]);
+ DBG_OBJ_ASSOC (containingBlock[OOFM_ABSOLUTE],
+ containingBlock[OOFM_ABSOLUTE]
+ ->outOfFlowMgr[OOFM_ABSOLUTE]);
+ }
+
+ if (containingBlock[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] == NULL) {
+ containingBlock[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] =
+ new OOFPosFixedMgr (containingBlock[OOFM_FIXED]);
+ DBG_OBJ_ASSOC (containingBlock[OOFM_FIXED],
+ containingBlock[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED]);
+ }
+}
+
/**
* Add a widget (word type) to the page.
*/
@@ -2325,21 +2392,26 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
widget->setStyle (style);
- PRINTF ("adding the %s %p to %p (word %d) ...\n",
- widget->getClassName(), widget, this, words->size());
-
- if (containingBlock->outOfFlowMgr == NULL) {
- containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock);
- DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr);
- }
+ initOutOfFlowMgrs ();
- if (OutOfFlowMgr::isWidgetHandledByOOFM (widget)) {
- PRINTF (" -> out of flow.\n");
+ if (testWidgetOutOfFlow (widget)) {
+ int oofmIndex = -1;
+ if (testWidgetFloat (widget))
+ oofmIndex = OOFM_FLOATS;
+ else if (testWidgetAbsolutelyPositioned (widget))
+ oofmIndex = OOFM_ABSOLUTE;
+ else if (testWidgetFixedPositioned (widget))
+ oofmIndex = OOFM_FIXED;
+ else
+ lout::misc::assertNotReached ();
- widget->setParent (containingBlock);
+ widget->setParent (containingBlock[oofmIndex]);
widget->setGenerator (this);
- containingBlock->outOfFlowMgr->addWidgetOOF (widget, this,
- words->size ());
+ int oofmSubRef =
+ containingBlock[oofmIndex]->outOfFlowMgr[oofmIndex]
+ ->addWidgetOOF (widget, this, words->size ());
+ widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef);
+
Word *word = addWord (0, 0, 0, 0, style);
word->content.type = core::Content::WIDGET_OOF_REF;
word->content.widget = widget;
@@ -2348,14 +2420,14 @@ 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");
-
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++)
+ containingBlock[i]->outOfFlowMgr[i]
+ ->addWidgetInFlow ((Textblock*)widget, this, words->size ());
+ }
core::Requisition size;
calcWidgetSize (widget, &size);
@@ -2593,7 +2665,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;
@@ -2604,7 +2676,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 = getWidgetLineNo (widget);
if (lineno > 0 &&
(word2 =
@@ -2613,8 +2685,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;
}
}
@@ -2738,10 +2809,13 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
// 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;
+ for (int i = 0; i < NUM_OOFM; i++) {
+ Widget *oofWidget =
+ outOfFlowMgr[i] ?
+ outOfFlowMgr[i]->getWidgetAtPoint (x, y, level) : NULL;
+ if (oofWidget)
+ return oofWidget;
+ }
lineIndex = findLineIndexWhenAllocated (y - allocation.y);
@@ -3037,7 +3111,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)
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 3abe1f41..bee7dad8 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -124,7 +124,7 @@ namespace dw {
*
* dw::Textblock makes use of incremental resizing as described in \ref
* dw-widget-sizes. The parentRef is, for children of a dw::Textblock, simply
- * the number of the line.
+ * the number of the line. [<b>Update:</b> Incorrect; see \ref dw-out-of-flow.]
*
* Generally, there are three cases which may change the size of the
* widget:
@@ -246,10 +246,57 @@ private:
static const char *hyphenDrawChar;
- Textblock *containingBlock;
- OutOfFlowMgr *outOfFlowMgr;
-
protected:
+ enum { OOFM_FLOATS, OOFM_ABSOLUTE, OOFM_FIXED, NUM_OOFM };
+ enum { PARENT_REF_OOFM_BITS = 2,
+ PARENT_REF_OOFM_MASK = (1 << PARENT_REF_OOFM_BITS) - 1 };
+
+ Textblock *containingBlock[NUM_OOFM];
+ OutOfFlowMgr *outOfFlowMgr[NUM_OOFM];
+
+ inline bool isParentRefOOF (int parentRef)
+ { return parentRef != -1 && (parentRef & PARENT_REF_OOFM_MASK); }
+
+ inline int makeParentRefInFlow (int lineNo)
+ { return (lineNo << PARENT_REF_OOFM_BITS); }
+ inline int getParentRefLineNo (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 OutOfFlowMgr *getParentRefOutOfFlowMgr (int parentRef)
+ { return outOfFlowMgr[getParentRefOOFIndex (parentRef)]; }
+
+ inline bool isWidgetOOF (Widget *widget)
+ { return isParentRefOOF (widget->parentRef); }
+
+ inline int getWidgetLineNo (Widget *widget)
+ { return getParentRefLineNo (widget->parentRef); }
+
+ inline int getWidgetOOFSubRef (Widget *widget)
+ { return getParentRefOOFSubRef (widget->parentRef); }
+ inline int getWidgetOOFIndex (Widget *widget)
+ { return getParentRefOOFIndex (widget->parentRef); }
+ inline OutOfFlowMgr *getWidgetOutOfFlowMgr (Widget *widget)
+ { return getParentRefOutOfFlowMgr (widget->parentRef); }
+
+ static inline bool testWidgetFloat (Widget *widget)
+ { return widget->getStyle()->vloat != core::style::FLOAT_NONE; }
+ static inline bool testWidgetAbsolutelyPositioned (Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; }
+ static inline bool testWidgetFixedPositioned (Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_FIXED; }
+ static inline bool testWidgetOutOfFlow (Widget *widget)
+ { return testWidgetFloat (widget) || testWidgetAbsolutelyPositioned (widget)
+ || testWidgetFixedPositioned (widget); }
+
/**
* \brief Implementation used for words.
*/
@@ -453,14 +500,14 @@ protected:
class TextblockIterator: public core::Iterator
{
private:
- bool oofm;
+ int oofmIndex; // -1 means in flow
int index;
public:
TextblockIterator (Textblock *textblock, core::Content::Type mask,
bool atEnd);
TextblockIterator (Textblock *textblock, core::Content::Type mask,
- bool oofm, int index);
+ int oofmIndex, int index);
lout::object::Object *clone();
int compareTo(lout::object::Comparable *other);
@@ -782,11 +829,12 @@ protected:
void addText0 (const char *text, size_t len, short flags,
core::style::Style *style, core::Requisition *size);
+ void initOutOfFlowMgrs ();
void calcTextSizes (const char *text, size_t textLen,
core::style::Style *style,
int numBreaks, int *breakPos,
core::Requisition *wordSize);
- static bool isContainingBlock (Widget *widget);
+ static bool isContainingBlock (Widget *widget, int oofmIndex);
inline bool mustBeWidenedToAvailWidth () {
DBG_OBJ_ENTER0 ("resize", 0, "mustBeWidenedToAvailWidth");
diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc
index c09d9a75..74cb3f98 100644
--- a/dw/textblock_iterator.cc
+++ b/dw/textblock_iterator.cc
@@ -36,15 +36,16 @@ Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
core::Iterator (textblock, mask, atEnd)
{
if (atEnd) {
- if (textblock->outOfFlowMgr) {
- oofm = true;
- index = textblock->outOfFlowMgr->getNumWidgets();
+ // Note: either all or no OOFM is defined.
+ if (textblock->outOfFlowMgr[0]) {
+ oofmIndex = NUM_OOFM - 1;
+ index = textblock->outOfFlowMgr[NUM_OOFM - 1]->getNumWidgets();
} else {
- oofm = false;
+ oofmIndex = -1;
index = textblock->words->size();
}
} else {
- oofm = false;
+ oofmIndex = -1;
index = -1;
}
@@ -53,10 +54,10 @@ Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
core::Content::Type mask,
- bool oofm, int index):
+ int oofmIndex, int index):
core::Iterator (textblock, mask, false)
{
- this->oofm = oofm;
+ this->oofmIndex = oofmIndex;
this->index = index;
// TODO To be completely exact, oofm should be considered here.
@@ -70,18 +71,16 @@ Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
object::Object *Textblock::TextblockIterator::clone()
{
- return
- new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index);
+ return new TextblockIterator ((Textblock*)getWidget(), getMask(), oofmIndex,
+ 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;
+ if (oofmIndex != otherTI->oofmIndex)
+ return oofmIndex - otherTI->oofmIndex;
else
return index - otherTI->index;
}
@@ -93,51 +92,57 @@ bool Textblock::TextblockIterator::next ()
if (content.type == core::Content::END)
return false;
- short type;
-
do {
index++;
- if (oofm) {
+ if (oofmIndex >= 0) {
// Iterating over OOFM.
- if (index >= textblock->outOfFlowMgr->getNumWidgets()) {
- // End of OOFM list reached.
- content.type = core::Content::END;
- return false;
+ if (index >= textblock->outOfFlowMgr[oofmIndex]->getNumWidgets()) {
+ // End of current OOFM list reached.
+ oofmIndex++;
+ while (oofmIndex < NUM_OOFM &&
+ textblock->outOfFlowMgr[oofmIndex]->getNumWidgets() == 0)
+ oofmIndex++;
+
+ if (oofmIndex == NUM_OOFM) {
+ content.type = core::Content::END;
+ return false;
+ } else
+ index = 0;
}
- type = core::Content::WIDGET_OOF_CONT;
+
+ content.type = core::Content::WIDGET_OOF_CONT;
+ content.widget =
+ textblock->outOfFlowMgr[oofmIndex]->getWidget (index);
} else {
// Iterating over words list.
if (index < textblock->words->size ())
- // Still words left.
- type = textblock->words->getRef(index)->content.type;
+ content = textblock->words->getRef(index)->content;
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).
+ if (textblock->outOfFlowMgr[0] == NULL) {
+ // No OOFM widgets (no OOFM at all).
+ content.type = core::Content::END;
+ return false;
+ } else {
+ oofmIndex = 0;
+ while (oofmIndex < NUM_OOFM &&
+ textblock->outOfFlowMgr[oofmIndex]->getNumWidgets() == 0)
+ oofmIndex++;
+
+ if (oofmIndex == NUM_OOFM) {
content.type = core::Content::END;
return false;
+ } else {
+ index = 0;
+ content.type = core::Content::WIDGET_OOF_CONT;
+ content.widget =
+ textblock->outOfFlowMgr[oofmIndex]->getWidget (index);
}
- } 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;
+ } while ((content.type & getMask()) == 0);
return true;
}
@@ -149,47 +154,48 @@ bool Textblock::TextblockIterator::prev ()
if (content.type == core::Content::START)
return false;
- short type;
-
do {
index--;
- if (oofm) {
+ if (oofmIndex >= 0) {
// 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;
+ if (index >= 0) {
+ content.type = core::Content::WIDGET_OOF_CONT;
+ content.widget =
+ textblock->outOfFlowMgr[oofmIndex]->getWidget (index);
+ } else {
+ oofmIndex--;
+ while (oofmIndex >= 0 &&
+ textblock->outOfFlowMgr[oofmIndex]->getNumWidgets() == 0)
+ oofmIndex--;
+
+ if (oofmIndex >= 0) {
+ index = textblock->outOfFlowMgr[oofmIndex]->getNumWidgets() - 1;
+ content.type = core::Content::WIDGET_OOF_CONT;
+ content.widget =
+ textblock->outOfFlowMgr[oofmIndex]->getWidget (index);
+ } else {
+ 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;
+ }
+ content = textblock->words->getRef(index)->content;
}
- 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;
+ content = textblock->words->getRef(index)->content;
}
- } 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;
+ } while ((content.type & getMask()) == 0);
return true;
}
@@ -197,7 +203,7 @@ bool Textblock::TextblockIterator::prev ()
void Textblock::TextblockIterator::highlight (int start, int end,
core::HighlightLayer layer)
{
- if (!oofm) {
+ if (oofmIndex == -1) {
Textblock *textblock = (Textblock*)getWidget();
int index1 = index, index2 = index;
@@ -237,7 +243,7 @@ void Textblock::TextblockIterator::highlight (int start, int end,
void Textblock::TextblockIterator::unhighlight (int direction,
core::HighlightLayer layer)
{
- if (!oofm) {
+ if (oofmIndex == -1) {
Textblock *textblock = (Textblock*)getWidget();
int index1 = index, index2 = index;
@@ -279,10 +285,11 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
{
Textblock *textblock = (Textblock*)getWidget();
- if (oofm) {
+ if (oofmIndex >= 0) {
// TODO Consider start and end?
*allocation =
- *(textblock->outOfFlowMgr->getWidget(index)->getAllocation());
+ *(textblock->outOfFlowMgr[oofmIndex]->getWidget(index)
+ ->getAllocation());
} else {
int lineIndex = textblock->findLineOfWord (index);
Line *line = textblock->lines->getRef (lineIndex);
@@ -329,8 +336,7 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
void Textblock::TextblockIterator::print ()
{
Iterator::print ();
- printf (", oofm = %s, index = %d", oofm ? "true" : "false", index);
-
+ printf (", oofmIndex = %d, index = %d", oofmIndex, index);
}
} // namespace dw
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index 0d21c461..619c97ce 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -733,14 +733,15 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
startSearch, breakPos);
for (int i = startSearch; newFloatPos == -1 && i <= breakPos; i++) {
core::Content *content = &(words->getRef(i)->content);
- if (content->type == core::Content::WIDGET_OOF_REF &&
- // Later, absolutepositioned elements (which do not affect
- // borders) can be ignored at this point.
- (containingBlock->outOfFlowMgr->affectsLeftBorder
- (content->widget) ||
- containingBlock->outOfFlowMgr->affectsRightBorder
- (content->widget)))
- newFloatPos = i;
+ if (content->type == core::Content::WIDGET_OOF_REF) {
+ for (int j = 0; newFloatPos == -1 && j < NUM_OOFM; j++) {
+ if ((containingBlock[j]->outOfFlowMgr[j]
+ ->affectsLeftBorder (content->widget) ||
+ containingBlock[j]->outOfFlowMgr[j]
+ ->affectsRightBorder (content->widget)))
+ newFloatPos = i;
+ }
+ }
}
DBG_OBJ_MSGF ("construct.word", 2, "newFloatPos = %d", newFloatPos);
@@ -753,8 +754,9 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
// Step 2: position the float and re-calculate the line.
lastFloatPos = newFloatPos;
- containingBlock->outOfFlowMgr->tellPosition
- (words->getRef(lastFloatPos)->content.widget, yNewLine);
+ for (int i = 0; i < NUM_OOFM; i++)
+ containingBlock[i]->outOfFlowMgr[i]->tellPosition
+ (words->getRef(lastFloatPos)->content.widget, yNewLine);
balanceBreakPosAndHeight (wordIndex, firstIndex, &searchUntil,
tempNewLine, penaltyIndex, false,
@@ -820,8 +822,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
firstWordWithoutLine = lines->getLastRef()->lastWord + 1;
if (wordIndex >= firstWordWithoutLine) {
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lines->size ());
+ word->content.widget->parentRef = makeParentRefInFlow (lines->size ());
PRINTF ("The %s %p is assigned parentRef = %d.\n",
word->content.widget->getClassName(), word->content.widget,
word->content.widget->parentRef);
@@ -1414,8 +1415,11 @@ 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 (containingBlock[i]->outOfFlowMgr[i])
+ containingBlock[i]->outOfFlowMgr[i]->moveExternalIndices (this,
+ wordIndex,
+ num);
for (int i = lines->size () - 1; i >= 0; i--) {
Line *line = lines->getRef (i);
@@ -1491,8 +1495,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
+ word->content.widget->getStyle()->margin.top
- collapseMarginTop);
- word->content.widget->parentRef =
- OutOfFlowMgr::createRefNormalFlow (lineIndex);
+ word->content.widget->parentRef = makeParentRefInFlow (lineIndex);
} else {
line->marginDescent =
misc::max (line->marginDescent, line->boxDescent);
@@ -1897,12 +1900,17 @@ void Textblock::initNewLine ()
// At the very beginning, in Textblock::Textblock, where this
// method is called, containingBlock is not yet defined.
- if (containingBlock && containingBlock->outOfFlowMgr) {
- if (lines->size () == 0) {
- int clearPosition =
- containingBlock->outOfFlowMgr->getClearPosition (this);
- setVerticalOffset (misc::max (clearPosition, 0));
- }
+ if (lines->size () == 0) {
+ int clearPosition = 0;
+
+ for (int i = 0; i < NUM_OOFM; i++)
+ if (containingBlock[i] && containingBlock[i]->outOfFlowMgr[i])
+ clearPosition =
+ misc::max (clearPosition,
+ containingBlock[i]->outOfFlowMgr[i]->getClearPosition
+ (this));
+
+ setVerticalOffset (misc::max (clearPosition, 0));
}
calcBorders (lines->size() > 0 ?
@@ -1922,81 +1930,88 @@ 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;
- int firstWordOfLine = lines->size() > 0 ?
- lines->getLastRef()->lastWord + 1 : 0;
+ // Either none or all are defined:
+ if (containingBlock[0] && containingBlock[0]->outOfFlowMgr[0]) {
+ int firstWordOfLine =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
int effOofRef = misc::max (lastOofRef, firstWordOfLine - 1);
-
int y = yOffsetOfPossiblyMissingLine (lines->size ());
-
- newLineHasFloatLeft =
- containingBlock->outOfFlowMgr->hasFloatLeft (this, y, height, this,
- effOofRef);
- newLineHasFloatRight =
- containingBlock->outOfFlowMgr->hasFloatRight (this, y, height, this,
- effOofRef);
- newLineLeftBorder =
- containingBlock->outOfFlowMgr->getLeftBorder (this, y, height, this,
- effOofRef);
- newLineRightBorder =
- containingBlock->outOfFlowMgr->getRightBorder (this, y, height, this,
- effOofRef);
- newLineLeftFloatHeight = newLineHasFloatLeft ?
- containingBlock->outOfFlowMgr->getLeftFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
- newLineRightFloatHeight = newLineHasFloatRight ?
- containingBlock->outOfFlowMgr->getRightFloatHeight (this, y, height,
- this, effOofRef) :
- 0;
-
- DBG_OBJ_MSGF ("construct.line", 1,
- "%d * %d (%s) / %d * %d (%s), at %d (%d), until %d = "
- "max (%d, %d - 1)",
- newLineLeftBorder, newLineLeftFloatHeight,
- newLineHasFloatLeft ? "true" : "false",
- newLineRightBorder, newLineRightFloatHeight,
- newLineHasFloatRight ? "true" : "false",
- y, height, effOofRef, lastOofRef, firstWordOfLine);
- } else {
- newLineHasFloatLeft = newLineHasFloatRight = false;
- newLineLeftBorder = newLineRightBorder = 0;
- newLineLeftFloatHeight = newLineRightFloatHeight = 0;
-
- DBG_OBJ_MSG ("construct.line", 0, "<i>no CB of OOFM</i>");
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ // 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;
+ OutOfFlowMgr *oofm = containingBlock[i]->outOfFlowMgr[i];
+
+ 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,
+ "%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);
+ }
}
DBG_OBJ_SET_BOOL ("newLineHasFloatLeft", newLineHasFloatLeft);