diff options
author | Sebastian Geerken <devnull@localhost> | 2014-09-01 00:30:01 +0200 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2014-09-01 00:30:01 +0200 |
commit | a2cf34555c64fa87bd146071cf46bd381c695761 (patch) | |
tree | a49d40dd73dd486d0f0111e28dd7a7189ed60970 | |
parent | 9430132423d99689de9c02db79df60fd1b4a5703 (diff) |
Many changes: split up OutOfFlowMgr for floats, and absolutely and fixedly positioned elements; also with different containing blocks.
-rw-r--r-- | dw/Makefile.am | 8 | ||||
-rw-r--r-- | dw/alignedtablecell.cc | 2 | ||||
-rw-r--r-- | dw/ooffloatsmgr.cc | 2248 | ||||
-rw-r--r-- | dw/ooffloatsmgr.hh | 377 | ||||
-rw-r--r-- | dw/oofposabsmgr.cc | 29 | ||||
-rw-r--r-- | dw/oofposabsmgr.hh | 16 | ||||
-rw-r--r-- | dw/oofposfixedmgr.cc | 29 | ||||
-rw-r--r-- | dw/oofposfixedmgr.hh | 16 | ||||
-rw-r--r-- | dw/oofpositionedmgr.cc | 428 | ||||
-rw-r--r-- | dw/oofpositionedmgr.hh | 87 | ||||
-rw-r--r-- | dw/outofflowmgr.cc | 2436 | ||||
-rw-r--r-- | dw/outofflowmgr.hh | 501 | ||||
-rw-r--r-- | dw/textblock.cc | 356 | ||||
-rw-r--r-- | dw/textblock.hh | 62 | ||||
-rw-r--r-- | dw/textblock_iterator.cc | 158 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 203 |
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); |