diff options
42 files changed, 5249 insertions, 3464 deletions
diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc index d02c3b28..ca2653bb 100644 --- a/doc/dw-out-of-flow.doc +++ b/doc/dw-out-of-flow.doc @@ -5,6 +5,32 @@ padding: 0.5em 1em; background-color: #ffffe0"><b>Info:</b> Should be incorporated into dw::Textblock.</div> +<div style="border: 2px solid #ff4040; margin-bottom: 0.5em; +padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b> +Not up to date; incorporate these two changes: (i) there are different +containing blocks for floats and absolutely (furthermore also fixedly) +positioned elements; (ii) dw::OutOfFlowMgr is now only the base class: +floats and absolutely positioned elements are seperated: +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", dir="both"]; + fontname=Helvetica; fontsize=8; + + OutOfFlowMgr [URL="\ref dw::OutOfFlowMgr"]; + OOFFloatsMgr [URL="\ref dw::OOFFloatsMgr"]; + OOFPositionedMgr [URL="\ref dw::OOFPositionedMgr"]; + OOFPosAbsMgr [URL="\ref dw::OOFPosAbsMgr"]; + OOFPosFixedMgr [URL="\ref dw::OOFPosFixedMgr"]; + + OutOfFlowMgr -> OOFFloatsMgr; + OutOfFlowMgr -> OOFPositionedMgr; + OOFPositionedMgr -> OOFPosAbsMgr; + OOFPositionedMgr -> OOFPosFixedMgr; +} +\enddot +</div> + Introduction ============ diff --git a/dw/Makefile.am b/dw/Makefile.am index 0b4b7bb4..15055ad8 100644 --- a/dw/Makefile.am +++ b/dw/Makefile.am @@ -23,6 +23,8 @@ libDw_core_a_SOURCES = \ platform.hh \ selection.hh \ selection.cc \ + stackingcontextmgr.hh \ + stackingcontextmgr.cc \ style.cc \ style.hh \ types.cc \ @@ -69,6 +71,17 @@ libDw_widgets_a_SOURCES = \ image.hh \ listitem.cc \ listitem.hh \ + oofawarewidget.cc \ + oofawarewidget_iterator.cc \ + oofawarewidget.hh \ + ooffloatsmgr.cc \ + ooffloatsmgr.hh \ + oofposabsmgr.cc \ + oofposabsmgr.hh \ + oofposfixedmgr.cc \ + oofposfixedmgr.hh \ + oofpositionedmgr.cc \ + oofpositionedmgr.hh \ outofflowmgr.cc \ outofflowmgr.hh \ ruler.cc \ diff --git a/dw/alignedtablecell.cc b/dw/alignedtablecell.cc index 633c4e68..e7ab2741 100644 --- a/dw/alignedtablecell.cc +++ b/dw/alignedtablecell.cc @@ -129,6 +129,11 @@ int AlignedTableCell::applyPerHeight (int containerHeight, return tablecell::applyPerHeight (this, containerHeight, perHeight); } +bool AlignedTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +} + int AlignedTableCell::wordWrap(int wordIndex, bool wrapAll) { Textblock::Word *word; @@ -191,7 +196,7 @@ int AlignedTableCell::getValue () void AlignedTableCell::setMaxValue (int maxValue, int value) { line1Offset = maxValue - value; - queueResize (OutOfFlowMgr::createRefNormalFlow (0), true); + queueResize (makeParentRefInFlow (0), true); } } // namespace dw diff --git a/dw/alignedtablecell.hh b/dw/alignedtablecell.hh index 5ea606d7..5325ba63 100644 --- a/dw/alignedtablecell.hh +++ b/dw/alignedtablecell.hh @@ -22,6 +22,8 @@ protected: bool getAdjustMinWidth (); + bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); + int wordWrap (int wordIndex, bool wrapAll); int getValue (); @@ -25,6 +25,7 @@ class Layout; class View; class Widget; class Iterator; +class StackingContextMgr; // Nothing yet to free. inline void freeall () { } @@ -53,6 +54,7 @@ class ResourceFactory; #include "selection.hh" #include "layout.hh" #include "widget.hh" +#include "stackingcontextmgr.hh" #include "ui.hh" #undef __INCLUDED_FROM_DW_CORE_HH__ diff --git a/dw/image.cc b/dw/image.cc index 20460f33..8a4be32f 100644 --- a/dw/image.cc +++ b/dw/image.cc @@ -334,7 +334,7 @@ void Image::leaveNotifyImpl (core::EventCrossing *event) */ int Image::contentX (core::MousePositionEvent *event) { - int ret = event->xWidget - getStyle()->boxOffsetX(); + int ret = event->xWidget - boxOffsetX(); ret = misc::min(getContentWidth(), misc::max(ret, 0)); return ret; @@ -342,7 +342,7 @@ int Image::contentX (core::MousePositionEvent *event) int Image::contentY (core::MousePositionEvent *event) { - int ret = event->yWidget - getStyle()->boxOffsetY(); + int ret = event->yWidget - boxOffsetY(); ret = misc::min(getContentHeight(), misc::max(ret, 0)); return ret; @@ -412,8 +412,8 @@ void Image::draw (core::View *view, core::Rectangle *area) drawWidgetBox (view, area, false); if (buffer) { - dx = getStyle()->boxOffsetX (); - dy = getStyle()->boxOffsetY (); + dx = boxOffsetX (); + dy = boxOffsetY (); content.x = dx; content.y = dy; content.width = getContentWidth (); @@ -440,31 +440,29 @@ void Image::draw (core::View *view, core::Rectangle *area) (getContentHeight() < getStyle()->font->ascent + getStyle()->font->descent)) { clippingView = usedView = - view->getClippingView (allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY (), + view->getClippingView (allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight()); } usedView->drawSimpleWrappedText (getStyle()->font, getStyle()->color, core::style::Color::SHADING_NORMAL, - allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY (), + allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight(), altText); if (clippingView) view->mergeClippingView (clippingView); } if (mapKey) { - clippingView = view->getClippingView (allocation.x + - getStyle()->boxOffsetX (), - allocation.y + - getStyle()->boxOffsetY (), + clippingView = view->getClippingView (allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight()); mapList->drawMap(mapKey, clippingView, getStyle(), - allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY ()); + allocation.x + boxOffsetX (), + allocation.y + boxOffsetY ()); view->mergeClippingView (clippingView); } } @@ -515,9 +513,8 @@ void Image::drawRow (int row) buffer->getRowArea (row, &area); if (area.width && area.height) - queueDrawArea (area.x + getStyle()->boxOffsetX (), - area.y + getStyle()->boxOffsetY (), - area.width, area.height); + queueDrawArea (area.x + boxOffsetX (), area.y + boxOffsetY (), area.width, + area.height); } void Image::finish () diff --git a/dw/layout.cc b/dw/layout.cc index 2845a8e9..d46d2455 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -374,6 +374,13 @@ void Layout::addWidget (Widget *widget) return; } + // The toplevel widget always establishes a stacking context. It could + // already be set in Widget::setStyle(). + if (widget->stackingContextMgr == NULL) { + widget->stackingContextMgr = new StackingContextMgr (widget); + DBG_OBJ_ASSOC (widget, widget->stackingContextMgr); + } + topLevel = widget; widget->layout = this; widget->container = NULL; diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc new file mode 100644 index 00000000..f8e3c497 --- /dev/null +++ b/dw/oofawarewidget.cc @@ -0,0 +1,343 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofawarewidget.hh" +#include "ooffloatsmgr.hh" +#include "oofposabsmgr.hh" +#include "oofposfixedmgr.hh" + +using namespace dw; +using namespace dw::core; +using namespace lout::misc; + +namespace dw { + +namespace oof { + +int OOFAwareWidget::CLASS_ID = -1; + +OOFAwareWidget::OOFAwareWidget () +{ + DBG_OBJ_CREATE ("dw::oof::OOFAwareWidget"); + registerName ("dw::oof::OOFAwareWidget", &CLASS_ID); + + for (int i = 0; i < NUM_OOFM; i++) { + oofContainer[i] = NULL; + outOfFlowMgr[i] = NULL; + } +} + +OOFAwareWidget::~OOFAwareWidget () +{ + for (int i = 0; i < NUM_OOFM; i++) { + if(outOfFlowMgr[i]) { + // I feel more comfortable by letting the OOF aware widget delete + // these widgets, instead of doing this in ~OutOfFlowMgr. + for (int j = 0; j < outOfFlowMgr[i]->getNumWidgets (); j++) + delete outOfFlowMgr[i]->getWidget (j); + + delete outOfFlowMgr[i]; + } + } + + DBG_OBJ_DELETE (); +} + +void OOFAwareWidget::notifySetAsTopLevel() +{ + oofContainer[OOFM_FLOATS] = oofContainer[OOFM_ABSOLUTE] + = oofContainer[OOFM_FIXED] = this; +} + +bool OOFAwareWidget::isOOFContainer (Widget *widget, int oofmIndex) +{ + // TODO The methods isPossibleContainer() and isPossibleContainerParent() + // are only used in few cases. Does not matter currently, however. + + switch (oofmIndex) { + case OOFM_FLOATS: + return widget->instanceOf (OOFAwareWidget::CLASS_ID) && + (// For floats, only some OOF aware widgets are considered as + // containers. + ((OOFAwareWidget*)widget)->isPossibleContainer (OOFM_FLOATS) && + // The second condition: that this block is "out of flow", in a + // wider sense. + (// The toplevel widget is "out of flow", since there is no + // parent, and so no context. + widget->getParent() == NULL || + // A similar reasoning applies to a widget with an + // unsuitable parent (typical example: a table cell (this + // is also a text block, so possible float container) + // within a table widget, which is not a suitable float + // container parent). + !(widget->getParent()->instanceOf (OOFAwareWidget::CLASS_ID) && + ((OOFAwareWidget*)widget->getParent()) + ->isPossibleContainerParent (OOFM_FLOATS)) || + // Inline blocks are containing blocks, too. + widget->getStyle()->display == core::style::DISPLAY_INLINE_BLOCK || + // 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, + // relatively, and fixedly positioned elements constitute the + // containing block for absolutely positioned elements, but + // neither floats nor other elements like table cells. + // + // (Notice that relative positions are not yet supported, but + // only tested to get the correct containing block. Furthermore, + // it seems that this test would be incorrect for floats.) + // + // 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 (OOFAwareWidget::CLASS_ID) && + (widget->getParent() == NULL || + testWidgetAbsolutelyPositioned (widget) || + testWidgetRelativelyPositioned (widget) || + testWidgetFixedlyPositioned (widget)); + + case OOFM_FIXED: + // The single container for fixedly positioned elements is the + // toplevel (canvas; actually the viewport). (The toplevel + // widget should always be a textblock; at least this is the + // case in dillo.) + return widget->getParent() == NULL; + + default: + // compiler happiness + lout::misc::assertNotReached (); + return false; + } +} + +void OOFAwareWidget::notifySetParent () +{ + // Search for containing blocks. + for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) { + oofContainer[oofmIndex] = NULL; + + for (Widget *widget = this; + widget != NULL && oofContainer[oofmIndex] == NULL; + widget = widget->getParent ()) + if (isOOFContainer (widget, oofmIndex)) { + assert (widget->instanceOf (OOFAwareWidget::CLASS_ID)); + oofContainer[oofmIndex] = (OOFAwareWidget*)widget; + } + + DBG_OBJ_ARRSET_PTR ("oofContainer", oofmIndex, oofContainer[oofmIndex]); + + assert (oofContainer[oofmIndex] != NULL); + } +} + +void OOFAwareWidget::initOutOfFlowMgrs () +{ + if (oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] == NULL) { + oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] = + new OOFFloatsMgr (oofContainer[OOFM_FLOATS]); + DBG_OBJ_ASSOC (oofContainer[OOFM_FLOATS], + oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS]); + } + + if (oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] == NULL) { + oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] = + new OOFPosAbsMgr (oofContainer[OOFM_ABSOLUTE]); + DBG_OBJ_ASSOC (oofContainer[OOFM_ABSOLUTE], + oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE]); + } + + if (oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] == NULL) { + oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] = + new OOFPosFixedMgr (oofContainer[OOFM_FIXED]); + DBG_OBJ_ASSOC (oofContainer[OOFM_FIXED], + oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED]); + } +} + +void OOFAwareWidget::correctRequisitionByOOF (Requisition *requisition, + void (*splitHeightFun) (int, int*, + int*)) +{ + for (int i = 0; i < NUM_OOFM; i++) { + if (outOfFlowMgr[i]) { + int oofWidth, oofHeight; + DBG_OBJ_MSGF ("resize", 1, + "before considering widgets by OOFM #%d: %d * (%d + %d)", + i, requisition->width, requisition->ascent, + requisition->descent); + + outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight); + + if (oofWidth > requisition->width) { + if (adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) + extraSpace.right = max (extraSpace.right, + oofWidth - requisition->width); + requisition->width = oofWidth; + } + + if (oofHeight > requisition->ascent + requisition->descent) { + if (adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) + extraSpace.bottom = max (extraSpace.bottom, + oofHeight - (requisition->ascent + + requisition->descent)); + splitHeightFun (oofHeight, + &requisition->ascent, &requisition->descent); + } + } + } +} + +void OOFAwareWidget::correctExtremesByOOF (Extremes *extremes) +{ + for (int i = 0; i < NUM_OOFM; i++) { + if (outOfFlowMgr[i]) { + int oofMinWidth, oofMaxWidth; + outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth); + + DBG_OBJ_MSGF ("resize", 1, "OOFM (#%d) correction: %d / %d", + i, oofMinWidth, oofMaxWidth); + + extremes->minWidth = max (extremes->minWidth, oofMinWidth); + extremes->minWidthIntrinsic = max (extremes->minWidthIntrinsic, + oofMinWidth); + extremes->maxWidth = max (extremes->maxWidth, oofMaxWidth); + extremes->maxWidthIntrinsic = max (extremes->maxWidthIntrinsic, + oofMinWidth); + } + } +} + +void OOFAwareWidget::sizeAllocateStart (core::Allocation *allocation) +{ + + for (int i = 0; i < NUM_OOFM; i++) + if (oofContainer[i]->outOfFlowMgr[i]) + oofContainer[i]->outOfFlowMgr[i]->sizeAllocateStart (this, allocation); +} + +void OOFAwareWidget::sizeAllocateEnd () +{ + for (int i = 0; i < NUM_OOFM; i++) + if (oofContainer[i]->outOfFlowMgr[i]) + oofContainer[i]->outOfFlowMgr[i]->sizeAllocateEnd (this); +} + +void OOFAwareWidget::containerSizeChangedForChildrenOOF () +{ + for (int i = 0; i < NUM_OOFM; i++) + if (outOfFlowMgr[i]) + outOfFlowMgr[i]->containerSizeChangedForChildren (); +} + +void OOFAwareWidget::drawOOF (View *view, Rectangle *area) +{ + for (int i = 0; i < NUM_OOFM; i++) + if(outOfFlowMgr[i]) + outOfFlowMgr[i]->draw(view, area); +} + +Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y, int level) +{ + for (int i = 0; i < NUM_OOFM; i++) { + Widget *oofWidget = + outOfFlowMgr[i] ? + outOfFlowMgr[i]->getWidgetAtPoint (x, y, level) : NULL; + if (oofWidget) + return oofWidget; + } + + return NULL; +} + + +int OOFAwareWidget::getAvailWidthOfChild (Widget *child, bool forceValue) +{ + if (isWidgetOOF(child)) { + assert (getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)); + return getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child, + forceValue); + } else + return Widget::getAvailWidthOfChild (child, forceValue); +} + +int OOFAwareWidget::getAvailHeightOfChild (Widget *child, bool forceValue) +{ + if (isWidgetOOF(child)) { + assert (getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)); + return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child, + forceValue); + } else + return Widget::getAvailWidthOfChild (child, forceValue); +} + +void OOFAwareWidget::removeChild (Widget *child) +{ + // Sub classes should implement this method (and Textblock and + // Table do so), so this point is only reached from + // ~OOFAwareWidget, which removes widgets out of flow. + assert (isWidgetOOF (child)); +} + +void OOFAwareWidget::borderChanged (int y, Widget *vloat) +{ + assertNotReached (); +} + +void OOFAwareWidget::oofSizeChanged (bool extremesChanged) +{ + DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s", + extremesChanged ? "true" : "false"); + queueResize (-1, extremesChanged); + + // Extremes changes may become also relevant for the children. + if (extremesChanged) + containerSizeChanged (); + + DBG_OBJ_LEAVE (); +} + +int OOFAwareWidget::getLineBreakWidth () +{ + assertNotReached (); + return 0; +} + +bool OOFAwareWidget::isPossibleContainer (int oofmIndex) +{ + return oofmIndex != OOFM_FLOATS; +} + +bool OOFAwareWidget::isPossibleContainerParent (int oofmIndex) +{ + return oofmIndex != OOFM_FLOATS; +} + +bool OOFAwareWidget::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return true; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh new file mode 100644 index 00000000..af6a18e0 --- /dev/null +++ b/dw/oofawarewidget.hh @@ -0,0 +1,198 @@ +#ifndef __DW_OOFAWAREWIDGET_HH__ +#define __DW_OOFAWAREWIDGET_HH__ + +#include "core.hh" +#include "outofflowmgr.hh" + +namespace dw { + +namespace oof { + +/** + * \brief Base class for widgets which can act as container and + * generator for widgets out of flow. + * + * (Perhaps it should be diffenciated between the two roles, container + * and generator, but this would make multiple inheritance necessary.) + * + * Requirements for sub classes (in most cases refer to dw::Textblock + * as a good example): + * + * - A sub class should at least take care to call these methods at the + * respective points: + * + * - dw::oof::OOFAwareWidget::correctRequisitionByOOF (from + * dw::core::Widget::getExtremesImpl) + * - dw::oof::OOFAwareWidget::correctExtremesByOOF (from + * dw::core::Widget::sizeRequestImpl) + * - dw::oof::OOFAwareWidget::sizeAllocateStart + * - dw::oof::OOFAwareWidget::sizeAllocateEnd (latter two from + * dw::core::Widget::sizeAllocateImpl) + * - dw::oof::OOFAwareWidget::containerSizeChangedForChildrenOOF + * (from dw::core::Widget::containerSizeChangedForChildren) + * - dw::oof::OOFAwareWidget::drawOOF (from dw::core::Widget::draw) + * - dw::oof::OOFAwareWidget::getWidgetOOFAtPoint (from + * dw::core::Widget::getWidgetAtPoint) + * + * - Implementations of dw::core::Widget::getAvailWidthOfChild and + * dw::core::Widget::getAvailHeightOfChild have to distinguish + * between widgets in flow and out of flow; see implementations of + * dw::oof::OOFAwareWidget. (Open issue: What about + * dw::core::Widget::correctRequisitionOfChild and + * dw::core::Widget::correctExtremesOfChild? Currently, all widgets + * are used the default implementation.) + * + * - Iterators have to consider widgets out of flow; + * dw::oof::OOFAwareWidget::OOFAwareWidgetIterator is recommended as + * base class. + * + * - dw::core::Widget::parentRef has to be set for widgets in flow; if + * not used further, a simple *makeParentRefInFlow(0)* is sufficient + * (as dw::Table::addCell does). Widgets which are only containers, + * but not generators, do not have to care about widgets out of + * flow in this regard. + * + * For both generators and containers of floats (which is only + * implemented by dw::Textblock) it gets a bit more complicated. + * + * \todo Currently, on the level of dw::oof::OOFAwareWidget, nothing + * is done about dw::core::Widget::markSizeChange and + * dw::core::Widget::markExtremesChange. This does not matter, though: + * dw::Textblock takes care of these, and dw::Table is only connected + * to subclasses of dw::oof::OOFPositionedMgr, which do care about + * these. However, this should be considered for completeness. + */ +class OOFAwareWidget: public core::Widget +{ +protected: + enum { OOFM_FLOATS, OOFM_ABSOLUTE, OOFM_FIXED, NUM_OOFM }; + enum { PARENT_REF_OOFM_BITS = 2, + PARENT_REF_OOFM_MASK = (1 << PARENT_REF_OOFM_BITS) - 1 }; + + class OOFAwareWidgetIterator: public core::Iterator + { + private: + enum { NUM_SECTIONS = NUM_OOFM + 1 }; + int sectionIndex; // 0 means in flow, otherwise OOFM index + 1 + int index; + + int numParts (int sectionIndex, int numContentsInFlow = -1); + void getPart (int sectionIndex, int index, core::Content *content); + + protected: + virtual int numContentsInFlow () = 0; + virtual void getContentInFlow (int index, core::Content *content) = 0; + + void setValues (int sectionIndex, int index); + inline void cloneValues (OOFAwareWidgetIterator *other) + { other->setValues (sectionIndex, index); } + + inline bool inFlow () { return sectionIndex == 0; } + inline bool getInFlowIndex () { assert (inFlow ()); return index; } + void highlightOOF (int start, int end, core::HighlightLayer layer); + void unhighlightOOF (int direction, core::HighlightLayer layer); + void getAllocationOOF (int start, int end, core::Allocation *allocation); + + public: + OOFAwareWidgetIterator (OOFAwareWidget *widget, core::Content::Type mask, + bool atEnd, int numContentsInFlow); + + int compareTo(lout::object::Comparable *other); + + bool next (); + bool prev (); + void print (); + }; + + inline bool isParentRefOOF (int parentRef) + { return parentRef != -1 && (parentRef & PARENT_REF_OOFM_MASK); } + + inline int makeParentRefInFlow (int inFlowSubRef) + { return (inFlowSubRef << PARENT_REF_OOFM_BITS); } + inline int getParentRefInFlowSubRef (int parentRef) + { assert (!isParentRefOOF (parentRef)); + return parentRef >> PARENT_REF_OOFM_BITS; } + + inline int makeParentRefOOF (int oofmIndex, int oofmSubRef) + { return (oofmSubRef << PARENT_REF_OOFM_BITS) | (oofmIndex + 1); } + inline int getParentRefOOFSubRef (int parentRef) + { assert (isParentRefOOF (parentRef)); + return parentRef >> PARENT_REF_OOFM_BITS; } + inline int getParentRefOOFIndex (int parentRef) + { assert (isParentRefOOF (parentRef)); + return (parentRef & PARENT_REF_OOFM_MASK) - 1; } + inline oof::OutOfFlowMgr *getParentRefOutOfFlowMgr (int parentRef) + { return outOfFlowMgr[getParentRefOOFIndex (parentRef)]; } + + inline bool isWidgetOOF (Widget *widget) + { return isParentRefOOF (widget->parentRef); } + + inline int getWidgetInFlowSubRef (Widget *widget) + { return getParentRefInFlowSubRef (widget->parentRef); } + + inline int getWidgetOOFSubRef (Widget *widget) + { return getParentRefOOFSubRef (widget->parentRef); } + inline int getWidgetOOFIndex (Widget *widget) + { return getParentRefOOFIndex (widget->parentRef); } + inline oof::OutOfFlowMgr *getWidgetOutOfFlowMgr (Widget *widget) + { return getParentRefOutOfFlowMgr (widget->parentRef); } + + OOFAwareWidget *oofContainer[NUM_OOFM]; + OutOfFlowMgr *outOfFlowMgr[NUM_OOFM]; + + inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex) + { return oofContainer[oofmIndex] ? + oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; } + + static inline bool testWidgetFloat (Widget *widget) + { return widget->getStyle()->vloat != core::style::FLOAT_NONE; } + static inline bool testWidgetAbsolutelyPositioned (Widget *widget) + { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; } + static inline bool testWidgetFixedlyPositioned (Widget *widget) + { return widget->getStyle()->position == core::style::POSITION_FIXED; } + static inline bool testWidgetOutOfFlow (Widget *widget) + { return testWidgetFloat (widget) || testWidgetAbsolutelyPositioned (widget) + || testWidgetFixedlyPositioned (widget); } + + static inline bool testWidgetRelativelyPositioned (Widget *widget) + { return widget->getStyle()->position == core::style::POSITION_RELATIVE; } + + void initOutOfFlowMgrs (); + void correctRequisitionByOOF (core::Requisition *requisition, + void (*splitHeightFun) (int, int*, int*)); + void correctExtremesByOOF (core::Extremes *extremes); + void sizeAllocateStart (core::Allocation *allocation); + void sizeAllocateEnd (); + void containerSizeChangedForChildrenOOF (); + void drawOOF (core::View *view, core::Rectangle *area); + core::Widget *getWidgetOOFAtPoint (int x, int y, int level); + + static bool isOOFContainer (Widget *widget, int oofmIndex); + + void notifySetAsTopLevel(); + void notifySetParent(); + + int getAvailWidthOfChild (Widget *child, bool forceValue); + int getAvailHeightOfChild (Widget *child, bool forceValue); + + void removeChild (Widget *child); + +public: + static int CLASS_ID; + + OOFAwareWidget (); + ~OOFAwareWidget (); + + virtual void borderChanged (int y, core::Widget *vloat); + virtual void oofSizeChanged (bool extremesChanged); + virtual int getLineBreakWidth (); // Should perhaps be renamed. + virtual bool isPossibleContainer (int oofmIndex); + virtual bool isPossibleContainerParent (int oofmIndex); + virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFAWAREWIDGET_HH__ diff --git a/dw/oofawarewidget_iterator.cc b/dw/oofawarewidget_iterator.cc new file mode 100644 index 00000000..74b3ea53 --- /dev/null +++ b/dw/oofawarewidget_iterator.cc @@ -0,0 +1,192 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofawarewidget.hh" +#include "ooffloatsmgr.hh" +#include "oofposabsmgr.hh" +#include "oofposfixedmgr.hh" + +using namespace dw; +using namespace dw::core; +using namespace lout::misc; +using namespace lout::object; + +namespace dw { + +namespace oof { + +// "numContentsInFlow" is passed here to avoid indirectly callin the (virtual) +// method numContentsInFlow() from the constructor. +OOFAwareWidget::OOFAwareWidgetIterator::OOFAwareWidgetIterator + (OOFAwareWidget *widget, Content::Type mask, bool atEnd, + int numContentsInFlow) : + Iterator (widget, mask, atEnd) +{ + if (atEnd) { + sectionIndex = NUM_SECTIONS - 1; + while (sectionIndex >= 0 && + numParts (sectionIndex, numContentsInFlow) == 0) + sectionIndex--; + index = numParts (sectionIndex, numContentsInFlow); + } else { + sectionIndex = 0; + index = -1; + } + + content.type = atEnd ? core::Content::END : core::Content::START; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::setValues (int sectionIndex, + int index) +{ + this->sectionIndex = sectionIndex; + this->index = index; + + if (sectionIndex == 0 && index < 0) + content.type = core::Content::START; + else if (sectionIndex == NUM_SECTIONS - 1 && + index >= numParts (sectionIndex)) + content.type = core::Content::END; + else + getPart (sectionIndex, index, &content); +} + +int OOFAwareWidget::OOFAwareWidgetIterator::numParts (int sectionIndex, + int numContentsInFlow) +{ + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + + if (sectionIndex == 0) + return numContentsInFlow == -1 ? + this->numContentsInFlow () : numContentsInFlow; + else + return widget->outOfFlowMgr[sectionIndex - 1] ? + widget->outOfFlowMgr[sectionIndex - 1]->getNumWidgets () : 0; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::getPart (int sectionIndex, + int index, + Content *content) +{ + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + + if (sectionIndex == 0) + getContentInFlow (index, content); + else { + content->type = Content::WIDGET_OOF_CONT; + content->widget = + widget->outOfFlowMgr[sectionIndex - 1]->getWidget (index); + } +} + +int OOFAwareWidget::OOFAwareWidgetIterator::compareTo (Comparable *other) +{ + OOFAwareWidgetIterator *otherTI = (OOFAwareWidgetIterator*)other; + + if (sectionIndex != otherTI->sectionIndex) + return sectionIndex - otherTI->sectionIndex; + else + return index - otherTI->index; +} + +bool OOFAwareWidget::OOFAwareWidgetIterator::next () +{ + if (content.type == Content::END) + return false; + + do { + index++; + + if (index >= numParts(sectionIndex)) { + sectionIndex++; + while (sectionIndex < NUM_SECTIONS && numParts (sectionIndex) == 0) + sectionIndex++; + + if (sectionIndex == NUM_SECTIONS) { + content.type = Content::END; + return false; + } else + index = 0; + } + + getPart (sectionIndex, index, &content); + } while ((content.type & getMask()) == 0); + + return true; +} + +bool OOFAwareWidget::OOFAwareWidgetIterator::prev () +{ + if (content.type == Content::START) + return false; + + do { + index--; + + if (index < 0) { + sectionIndex--; + while (sectionIndex >= 0 && numParts (sectionIndex) == 0) + sectionIndex--; + + if (sectionIndex < 0) { + content.type = Content::START; + return false; + } else + index = numParts (sectionIndex) - 1; + } + + getPart (sectionIndex, index, &content); + } while ((content.type & getMask()) == 0); + + return true; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::highlightOOF (int start, int end, + HighlightLayer layer) +{ + // TODO What about OOF widgets? +} + +void OOFAwareWidget::OOFAwareWidgetIterator::unhighlightOOF (int direction, + HighlightLayer + layer) +{ + // TODO What about OOF widgets? +} + +void OOFAwareWidget::OOFAwareWidgetIterator::getAllocationOOF (int start, + int end, + Allocation + *allocation) +{ + // TODO Consider start and end? + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + *allocation = *(widget->outOfFlowMgr[sectionIndex - 1] + ->getWidget(index)->getAllocation()); +} + +void OOFAwareWidget::OOFAwareWidgetIterator::print () +{ + Iterator::print (); + printf (", sectionIndex = %d, index = %d", sectionIndex, index); +} + +} // namespace oof + +} // namespace dw diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc new file mode 100644 index 00000000..7850b18f --- /dev/null +++ b/dw/ooffloatsmgr.cc @@ -0,0 +1,2287 @@ +/* + * Dillo Widget + * + * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ooffloatsmgr.hh" +#include "oofawarewidget.hh" +#include "../lout/debug.hh" + +#include <limits.h> + +using namespace lout::object; +using namespace lout::container::typed; +using namespace lout::misc; +using namespace dw::core; +using namespace dw::core::style; + +namespace dw { + +namespace oof { + +OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget) +{ + this->oofm = oofm; + this->widget = widget; + wasAllocated = false; + xCB = yCB = width = height = -1; +} + +void OOFFloatsMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB, + int width, int height) +{ + DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d", + wasAllocated ? "true" : "false", xCB, yCB, width, height); + + this->wasAllocated = wasAllocated; + this->xCB = xCB; + this->yCB = yCB; + this->width = width; + this->height = height; + + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height); + + DBG_OBJ_LEAVE_O (widget); +} + +// ---------------------------------------------------------------------- + +OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget, + OOFAwareWidget *generatingBlock, int externalIndex) + : WidgetInfo (oofm, widget) +{ + this->generatingBlock = generatingBlock; + this->externalIndex = externalIndex; + + yReq = yReal = size.width = size.ascent = size.descent = 0; + dirty = sizeChangedSinceLastAllocation = true; + indexGBList = indexCBList = -1; + + // Sometimes a float with widget = NULL is created as a key; this + // is not interesting for RTFL. + if (widget) { + DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock); + DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex); + DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq); + DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent); + DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty); + DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation", + sizeChangedSinceLastAllocation); + } +} + +void OOFFloatsMgr::Float::updateAllocation () +{ + DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); + + update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), + getNewHeight ()); + + DBG_OBJ_LEAVE_O (getWidget ()); +} + +void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb) +{ + sb->append ("{ widget = "); + sb->appendPointer (getWidget ()); + + if (getWidget ()) { + sb->append (" ("); + sb->append (getWidget()->getClassName ()); + sb->append (")"); + } + + sb->append (", indexGBList = "); + sb->appendInt (indexGBList); + sb->append (", indexCBList = "); + sb->appendInt (indexCBList); + sb->append (", sideSpanningIndex = "); + sb->appendInt (sideSpanningIndex); + sb->append (", generatingBlock = "); + sb->appendPointer (generatingBlock); + sb->append (", yReq = "); + sb->appendInt (yReq); + sb->append (", yReal = "); + sb->appendInt (yReal); + sb->append (", size = { "); + sb->appendInt (size.width); + sb->append (" * "); + sb->appendInt (size.ascent); + sb->append (" + "); + sb->appendInt (size.descent); + sb->append (" }, dirty = "); + sb->appendBool (dirty); + sb->append (", sizeChangedSinceLastAllocation = "); + sb->appendBool (sizeChangedSinceLastAllocation); + sb->append (" }"); +} + +bool OOFFloatsMgr::Float::covers (OOFAwareWidget *textblock, int y, int h) +{ + DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers", + "%p, %d, %d [vloat: %p]", + textblock, y, h, getWidget ()); + + bool b; + + if (textblock == generatingBlock) { + int reqyGB = y; + int flyGB = yReal; + getOOFFloatsMgr()->ensureFloatSize (this); + int flh = size.ascent + size.descent; + b = flyGB + flh > reqyGB && flyGB < reqyGB + h; + + DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (), + "for generator: reqyGB = %d, flyGB = %d, " + "flh = %d + %d = %d => %s", + reqyGB, flyGB, size.ascent, size.descent, flh, + b ? "true" : "false"); + } else { + assert (getOOFFloatsMgr()->wasAllocated (generatingBlock)); + assert (getOOFFloatsMgr()->wasAllocated (textblock)); + + if (!getWidget()->wasAllocated ()) { + DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (), + "not generator (not allocated) => false"); + b = false; + } else { + Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock), + //*gba = getOOFFloatsMgr()->getAllocation(generatingBlock), + *fla = getWidget()->getAllocation (); + int reqyCanv = tba->y + y; + int flyCanv = fla->y; + int flh = fla->ascent + fla->descent; + b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h; + + DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (), + "not generator (allocated): reqyCanv = %d + %d = %d, " + "flyCanv = %d, flh = %d + %d = %d => %s", + tba->y, y, reqyCanv, flyCanv, + fla->ascent, fla->descent, flh, b ? "true" : "false"); + } + } + + DBG_OBJ_LEAVE_O (getOOFFloatsMgr ()); + + return b; +} + +int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2) +{ + Float *fl1 = (Float*)o1, *fl2 = (Float*)o2; + int r; + + DBG_OBJ_ENTER_O ("border", 1, oofm, + "ComparePosition/compare", "(#%d, #%d) [refTB = %p]", + fl1->getIndex (type), fl2->getIndex (type), refTB); + + if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) { + DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats"); + r = fl1->yReal - fl2->yReal; + } else { + DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats"); + DBG_OBJ_MSG_START_O (oofm); + + assert (oofm->wasAllocated (fl1->generatingBlock)); + assert (oofm->wasAllocated (fl2->generatingBlock)); + + DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p", + fl1->generatingBlock, fl2->generatingBlock); + + // (i) Floats may not yet been allocated (although the + // generators are). Non-allocated floats do not have an effect + // yet, they are considered "at the end" of the list. + + // (ii) Float::widget for the key used for binary search. In + // this case, Float::yReal is used instead (which is set in + // SortedFloatsVector::find). + + bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true; + bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true; + + DBG_OBJ_MSGF_O ("border", 2, oofm, + "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s", + fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (), + a2 ? "yes" : "no"); + + if (a1 && a2) { + int fly1, fly2; + + if (fl1->getWidget()) { + fly1 = fl1->getWidget()->getAllocation()->y; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1); + } else { + fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d", + oofm->getAllocation(fl1->generatingBlock)->y, + fl1->yReal, fly1); + } + + if (fl2->getWidget()) { + fly2 = fl2->getWidget()->getAllocation()->y; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2); + } else { + fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d", + oofm->getAllocation(fl2->generatingBlock)->y, + fl2->yReal, fly2); + } + + r = fly1 - fly2; + + DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r); + } else if (a1 && !a2) + r = -1; + else if (!a1 && a2) + r = +1; + else // if (!a1 && !a2) + return 0; + + DBG_OBJ_MSG_END_O (oofm); + } + + DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1, + Object *o2) +{ + return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex; +} + +int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2) +{ + Float *f1 = (Float*)o1, *f2 = (Float*)o2; + int r = -123; // Compiler happiness: GCC 4.7 does not handle this?; + + DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare", + "#%d -> %p/%d, #%d -> %p/#%d", + f1->getIndex (type), f1->generatingBlock, f1->externalIndex, + f2->getIndex (type), f2->generatingBlock, + f2->externalIndex); + + if (f1->generatingBlock == f2->generatingBlock) { + r = f1->externalIndex - f2->externalIndex; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(a) generating blocks equal => %d - %d = %d", + f1->externalIndex, f2->externalIndex, r); + } else { + TBInfo *t1 = oofm->getOOFAwareWidget (f1->generatingBlock), + *t2 = oofm->getOOFAwareWidget (f2->generatingBlock); + bool rdef = false; + + for (TBInfo *t = t1; t != NULL; t = t->parent) + if (t->parent == t2) { + rdef = true; + r = t->parentExtIndex - f2->externalIndex; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(b) %p is an achestor of %p; direct child is " + "%p (%d) => %d - %d = %d\n", + t2->getOOFAwareWidget (), t1->getOOFAwareWidget (), + t->getOOFAwareWidget (), t->parentExtIndex, + t->parentExtIndex, f2->externalIndex, r); + } + + for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent) + if (t->parent == t1) { + r = f1->externalIndex - t->parentExtIndex; + rdef = true; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(c) %p is an achestor of %p; direct child is %p " + "(%d) => %d - %d = %d\n", + t1->getOOFAwareWidget (), t2->getOOFAwareWidget (), + t->getOOFAwareWidget (), t->parentExtIndex, + f1->externalIndex, t->parentExtIndex, r); + } + + if (!rdef) { + r = t1->index - t2->index; + DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d", + t1->index, t2->index, r); + } + } + + DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB, + int lastExtIndex) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d", + lastGB, lastExtIndex); + + Float key (oofm, NULL, lastGB, lastExtIndex); + key.setIndex (type, -1); // for debugging + Float::CompareGBAndExtIndex comparator (oofm, type); + int i = bsearch (&key, false, &comparator); + + // At position i is the next larger element, so element i should + // not included, but i - 1 returned; except if the exact element is + // found: then include it and so return i. + int r; + if (i == size()) + r = i - 1; + else { + Float *f = get (i); + if (comparator.compare (f, &key) == 0) + r = i; + else + r = i - 1; + } + + //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); " + // "in %s list %p on the %s side\n", + // oofm->container, lastGB, lastExtIndex, i, r, size (), + // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right"); + + //for (int i = 0; i < size (); i++) { + // Float *f = get(i); + // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock); + // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock, + // t->index, t->parent ? t->parent->textblock : NULL, + // get(i)->externalIndex); + //} + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::SortedFloatsVector::find (OOFAwareWidget *textblock, int y, + int start, int end) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d", + textblock, y, start, end); + + Float key (oofm, NULL, NULL, 0); + key.generatingBlock = textblock; + key.yReal = y; + key.setIndex (type, -1); // for debugging + Float::ComparePosition comparator (oofm, textblock, type); + int result = bsearch (&key, false, start, end, &comparator); + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); + DBG_OBJ_LEAVE_O (oofm); + return result; +} + +int OOFFloatsMgr::SortedFloatsVector::findFirst (OOFAwareWidget *textblock, + int y, int h, + OOFAwareWidget *lastGB, + int lastExtIndex, + int *lastReturn) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d", + textblock, y, h, lastGB, lastExtIndex); + + DBG_IF_RTFL { + DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:"); + DBG_OBJ_MSG_START_O (oofm); + + for (int i = 0; i < size(); i++) { + DBG_OBJ_MSGF_O ("border", 2, oofm, + "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), " + "%s, %s, ext = %d, GB = %p); widget at (%d, %d)", + i, get(i)->getWidget (), get(i)->getIndex (type), + get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal, + get(i)->size.width, get(i)->size.ascent, + get(i)->size.descent, + get(i)->dirty ? "dirty" : "clean", + get(i)->sizeChangedSinceLastAllocation ? "scsla" + : "sNcsla", + get(i)->externalIndex, get(i)->generatingBlock, + get(i)->getWidget()->getAllocation()->x, + get(i)->getWidget()->getAllocation()->y); + } + + DBG_OBJ_MSG_END_O (oofm); + } + + int last = findFloatIndex (lastGB, lastExtIndex); + DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last); + assert (last < size()); + + // If the caller wants to reuse this value: + if (lastReturn) + *lastReturn = last; + + int i = find (textblock, y, 0, last), result; + DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i); + + // Note: The smallest value of "i" is 0, which means that "y" is before or + // equal to the first float. The largest value is "last + 1", which means + // that "y" is after the last float. In both cases, the first or last, + // respectively, float is a candidate. Generally, both floats, before and + // at the search position, are candidates. + + if (i > 0 && get(i - 1)->covers (textblock, y, h)) + result = i - 1; + else if (i <= last && get(i)->covers (textblock, y, h)) + result = i; + else + result = -1; + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); + DBG_OBJ_LEAVE_O (oofm); + return result; +} + +int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex + (int sideSpanningIndex) +{ + OOFFloatsMgr::Float::CompareSideSpanningIndex comparator; + Float key (NULL, NULL, NULL, 0); + key.sideSpanningIndex = sideSpanningIndex; + return bsearch (&key, false, &comparator) - 1; +} + +void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat) +{ + lout::container::typed::Vector<Float>::put (vloat); + vloat->setIndex (type, size() - 1); +} + +OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock, + TBInfo *parent, int parentExtIndex) : + WidgetInfo (oofm, textblock) +{ + this->parent = parent; + this->parentExtIndex = parentExtIndex; + + leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB); + rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB); + + wasAllocated = getWidget()->wasAllocated (); + allocation = *(getWidget()->getAllocation ()); +} + +OOFFloatsMgr::TBInfo::~TBInfo () +{ + delete leftFloatsGB; + delete rightFloatsGB; +} + +void OOFFloatsMgr::TBInfo::updateAllocation () +{ + DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); + + update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), + getNewHeight ()); + + DBG_OBJ_LEAVE_O (getWidget ()); +} + +OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container) +{ + DBG_OBJ_CREATE ("dw::OOFFloatsMgr"); + + this->container = (OOFAwareWidget*)container; + + leftFloatsCB = new SortedFloatsVector (this, LEFT, CB); + rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB); + + DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); + DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); + + leftFloatsAll = new Vector<Float> (1, true); + rightFloatsAll = new Vector<Float> (1, true); + + DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); + DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); + + floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false); + + tbInfos = new Vector<TBInfo> (1, false); + tbInfosByOOFAwareWidget = + new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true); + + leftFloatsMark = rightFloatsMark = 0; + lastLeftTBIndex = lastRightTBIndex = 0; + + containerWasAllocated = container->wasAllocated (); + containerAllocation = *(container->getAllocation()); + + addWidgetInFlow (this->container, NULL, 0); +} + +OOFFloatsMgr::~OOFFloatsMgr () +{ + //printf ("OOFFloatsMgr::~OOFFloatsMgr\n"); + + delete leftFloatsCB; + delete rightFloatsCB; + + // Order is important: tbInfosByOOFAwareWidget is owner of the instances + // of TBInfo.tbInfosByOOFAwareWidget + delete tbInfos; + delete tbInfosByOOFAwareWidget; + + delete floatsByWidget; + + // Order is important, since the instances of Float are owned by + // leftFloatsAll and rightFloatsAll, so these should be deleted + // last. + delete leftFloatsAll; + delete rightFloatsAll; + + DBG_OBJ_DELETE (); +} + +void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller, + Allocation *allocation) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart", + "%p, (%d, %d, %d * (%d + %d))", + caller, allocation->x, allocation->y, allocation->width, + allocation->ascent, allocation->descent); + + // Some callers are not registered, especially tables. (Where the + // floats manager is actually empty?) + TBInfo *oofAWInfo = getOOFAwareWidgetWhenRegistered (caller); + if (oofAWInfo) { + oofAWInfo->allocation = *allocation; + oofAWInfo->wasAllocated = true; + } + + if (caller == container) { + // In the size allocation process, the *first* OOFM method + // called is sizeAllocateStart, with the containing block as an + // argument. So this is the correct point to initialize size + // allocation. + + containerAllocation = *allocation; + containerWasAllocated = true; + + // Move floats from GB lists to the one CB list. + moveFromGBToCB (LEFT); + moveFromGBToCB (RIGHT); + + // These attributes are used to keep track which floats have + // been allocated (referring to leftFloatsCB and rightFloatsCB). + lastAllocatedLeftFloat = lastAllocatedRightFloat = -1; + } + + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::sizeAllocateEnd (OOFAwareWidget *caller) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller); + + if (isOOFAwareWidgetRegistered (caller)) { + if (caller != container) { + // Allocate all floats "before" this textblock. + sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1)); + sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1)); + } + + if (caller == container) { + // In the size allocation process, the *last* OOFM method called + // is sizeAllocateEnd, with the containing block as an + // argument. So this is the correct point to finish size + // allocation. + + // Allocate all remaining floats. + sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1); + sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1); + + // Check changes of both textblocks and floats allocation. (All + // is checked by hasRelationChanged (...).) + for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> > + it = tbInfosByOOFAwareWidget->iterator (); + it.hasNext (); ) { + TypedPointer <OOFAwareWidget> *key = it.getNext (); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key); + OOFAwareWidget *tb = key->getTypedValue(); + + int minFloatPos; + Widget *minFloat; + if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat)) + tb->borderChanged (minFloatPos, minFloat); + } + + checkAllocatedFloatCollisions (LEFT); + checkAllocatedFloatCollisions (RIGHT); + + // Store some information for later use. + for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> > + it = tbInfosByOOFAwareWidget->iterator (); + it.hasNext (); ) { + TypedPointer <OOFAwareWidget> *key = it.getNext (); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key); + OOFAwareWidget *tb = key->getTypedValue(); + + tbInfo->updateAllocation (); + tbInfo->lineBreakWidth = tb->getLineBreakWidth (); + } + + // There are cases where some allocated floats (TODO: later also + // absolutely positioned elements?) exceed the CB allocation. + bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT); + + // Similar for extremes. (TODO: here also absolutely positioned + // elements?) + bool extremesChanged = + haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT); + + for (int i = 0; i < leftFloatsCB->size(); i++) + leftFloatsCB->get(i)->updateAllocation (); + + for (int i = 0; i < rightFloatsCB->size(); i++) + rightFloatsCB->get(i)->updateAllocation (); + + if (sizeChanged || extremesChanged) + container->oofSizeChanged (extremesChanged); + } + } + + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::containerSizeChangedForChildren () +{ + DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren"); + + for (int i = 0; i < leftFloatsAll->size (); i++) + leftFloatsAll->get(i)->getWidget()->containerSizeChanged (); + for (int i = 0; i < rightFloatsAll->size (); i++) + rightFloatsAll->get(i)->getWidget()->containerSizeChanged (); + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos, + Widget **minFloat) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", + "<i>widget:</i> %p, ...", tbInfo->getWidget ()); + + int leftMinPos, rightMinPos; + Widget *leftMinFloat, *rightMinFloat; + bool c1 = + hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat); + bool c2 = + hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat); + if (c1 || c2) { + if (!c1) { + *minFloatPos = rightMinPos; + *minFloat = rightMinFloat; + } else if (!c2) { + *minFloatPos = leftMinPos; + *minFloat = leftMinFloat; + } else { + if (leftMinPos < rightMinPos) { + *minFloatPos = leftMinPos; + *minFloat = leftMinFloat; + } else{ + *minFloatPos = rightMinPos; + *minFloat = rightMinFloat; + } + } + } + + if (c1 || c2) + DBG_OBJ_MSGF ("resize.oofm", 1, + "has changed: minFloatPos = %d, minFloat = %p", + *minFloatPos, *minFloat); + else + DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); + + DBG_OBJ_LEAVE (); + return c1 || c2; +} + +bool OOFFloatsMgr::hasRelationChanged (TBInfo *tbInfo, Side side, + int *minFloatPos, Widget **minFloat) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", + "<i>widget:</i> %p, %s, ...", + tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT"); + + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + bool changed = false; + + for (int i = 0; i < list->size(); i++) { + // TODO binary search? + Float *vloat = list->get(i); + int floatPos; + + if (tbInfo->getOOFAwareWidget () == vloat->generatingBlock) + DBG_OBJ_MSGF ("resize.oofm", 1, + "not checking (generating!) textblock %p against float " + "%p", tbInfo->getWidget (), vloat->getWidget ()); + else { + Allocation *gba = getAllocation (vloat->generatingBlock); + + int newFlx = + calcFloatX (vloat, side, + gba->x - containerAllocation.x, gba->width, + vloat->generatingBlock->getLineBreakWidth ()); + int newFly = vloat->generatingBlock->getAllocation()->y + - containerAllocation.y + vloat->yReal; + + DBG_OBJ_MSGF ("resize.oofm", 1, + "checking textblock %p against float %p", + tbInfo->getWidget (), vloat->getWidget ()); + DBG_OBJ_MSG_START (); + + if (hasRelationChanged (tbInfo->wasThenAllocated (), + tbInfo->getOldXCB (), tbInfo->getOldYCB (), + tbInfo->getNewWidth (), + tbInfo->getNewHeight (), + tbInfo->getNewXCB (), tbInfo->getNewYCB (), + tbInfo->getNewWidth (), + tbInfo->getNewHeight (), + vloat->wasThenAllocated (), + // When not allocated before, these values + // are undefined, but this does not matter, + // since they are neither used. + vloat->getOldXCB (), vloat->getOldYCB (), + vloat->getOldWidth (), vloat->getOldHeight (), + newFlx, newFly, vloat->size.width, + vloat->size.ascent + vloat->size.descent, + side, &floatPos)) { + if (!changed || floatPos < *minFloatPos) { + *minFloatPos = floatPos; + *minFloat = vloat->getWidget (); + } + changed = true; + } else + DBG_OBJ_MSG ("resize.oofm", 0, "No."); + + DBG_OBJ_MSG_END (); + } + + // All floarts are searched, to find the minimum. TODO: Are + // floats sorted, so this can be shortened? (The first is the + // minimum?) + } + + if (changed) + DBG_OBJ_MSGF ("resize.oofm", 1, + "has changed: minFloatPos = %d, minFloat = %p", + *minFloatPos, *minFloat); + else + DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); + + DBG_OBJ_LEAVE (); + return changed; +} + +/** + * \brief ... + * + * All coordinates are given relative to the CB. *floatPos is relative + * to the TB, and may be negative. + */ +bool OOFFloatsMgr::hasRelationChanged (bool oldTBAlloc, + int oldTBx, int oldTBy, int oldTBw, + int oldTBh, int newTBx, int newTBy, + int newTBw, int newTBh, + bool oldFlAlloc, + int oldFlx, int oldFly, int oldFlw, + int oldFlh, int newFlx, int newFly, + int newFlw, int newFlh, + Side side, int *floatPos) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", + "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT"); + + if (oldTBAlloc) + DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d", + oldTBx, oldTBy, oldTBw, oldTBh); + else + DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined"); + DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d", + newTBx, newTBy, newTBw, newTBh); + + if (oldFlAlloc) + DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d", + oldFlx, oldFly, oldFlw, oldFlh); + else + DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined"); + DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d", + newFlx, newFly, newFlw, newFlh); + + bool result; + if (oldTBAlloc && oldFlAlloc) { + bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh; + bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh; + + DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.", + oldCov ? "yes" : "no", newCov ? "yes" : "no"); + DBG_OBJ_MSG_START (); + + if (oldCov && newCov) { + int yOld = oldFly - oldTBy, yNew = newFly - newTBy; + if (yOld == yNew) { + DBG_OBJ_MSGF ("resize.oofm", 2, + "old (%d - %d) and new (%d - %d) position equal: %d", + oldFly, oldTBy, newFly, newTBy, yOld); + + // Float position has not changed, but perhaps the amout + // how far the float reaches into the TB. (TODO: + // Generally, not only here, it could be tested whether + // the float reaches into the TB at all.) + int wOld, wNew; + if (side == LEFT) { + wOld = oldFlx + oldFlw - oldTBx; + wNew = newFlx + newFlw - newTBx; + } else { + wOld = oldTBx + oldTBw - oldFlx; + wNew = newTBx + newTBw - newFlx; + } + + DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n", + wOld, wNew); + + if (wOld == wNew) { + if (oldFlh == newFlh) + result = false; + else { + // Only heights of floats changed. Relevant only + // from bottoms of float. + *floatPos = min (yOld + oldFlh, yNew + newFlh); + result = true; + } + } else { + *floatPos = yOld; + result = true; + } + } else { + DBG_OBJ_MSGF ("resize.oofm", 2, + "old (%d - %d = %d) and new (%d - %d = %d) position " + "different", + oldFly, oldTBy, yOld, newFly, newTBy, yNew); + *floatPos = min (yOld, yNew); + result = true; + } + } else if (oldCov) { + *floatPos = oldFly - oldTBy; + result = true; + DBG_OBJ_MSGF ("resize.oofm", 2, + "returning old position: %d - %d = %d", oldFly, oldTBy, + *floatPos); + } else if (newCov) { + *floatPos = newFly - newTBy; + result = true; + DBG_OBJ_MSGF ("resize.oofm", 2, + "returning new position: %d - %d = %d", newFly, newTBy, + *floatPos); + } else + result = false; + + DBG_OBJ_MSG_END (); + } else { + // Not allocated before: ignore all old values, only check whether + // TB is covered by Float. + if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) { + *floatPos = newFly - newTBy; + result = true; + } else + result = false; + } + + if (result) + DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d", + *floatPos); + else + DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); + + DBG_OBJ_LEAVE (); + + return result; +} + +void OOFFloatsMgr::checkAllocatedFloatCollisions (Side side) +{ + // In some cases, the collision detection in tellPosition() is + // based on the wrong allocations. Here (just after all Floats have + // been allocated), we correct this. + + // TODO In some cases this approach is rather slow, causing a too + // long queueResize() cascade. + + DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s", + side == LEFT ? "LEFT" : "RIGHT"); + + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB; + + // While iterating through the list of floats to be checked, we + // iterate equally through the list of the opposite floats, using + // this index: + int oppIndex = 0; + + for (int index = 0; index < list->size (); index++) { + Float *vloat = list->get(index); + bool needsChange = false; + int yRealNew = INT_MAX; + + // Same side. + if (index >= 1) { + Float *other = list->get(index - 1); + DBG_OBJ_MSGF ("resize.oofm", 1, + "same side: checking %p (#%d, GB: %p) against " + "%p (#%d, GB: %p)", + vloat->getWidget (), index, vloat->generatingBlock, + other->getWidget (), index - 1, other->generatingBlock); + + if (vloat->generatingBlock != other->generatingBlock) { + int yRealNewSame; + if (collidesV (vloat, other, CB, &yRealNewSame)) { + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> collides, new yReal = %d (old: %d)", + yRealNewSame, vloat->yReal); + if (vloat->yReal != yRealNewSame) { + needsChange = true; + yRealNew = min (yRealNew, yRealNewSame); + } + } else + DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision"); + } + } + + if (oppList->size () > 0) { + // Other side. Iterate to next float on the other side, + // before this float. + while (oppIndex + 1 < oppList->size () && + oppList->get(oppIndex + 1)->sideSpanningIndex + < vloat->sideSpanningIndex) + oppIndex++; + + if (oppList->get(oppIndex)->sideSpanningIndex + < vloat->sideSpanningIndex) { + int oppIndexTmp = oppIndex, yRealNewOpp; + + // Aproach is similar to tellPosition(); see comments + // there. Again, loop as long as the vertical dimensions test + // is positive (and, of course, there are floats), ... + for (bool foundColl = false; + !foundColl && oppIndexTmp >= 0 && + collidesV (vloat, oppList->get (oppIndexTmp), CB, + &yRealNewOpp); + oppIndexTmp--) { + DBG_OBJ_MSGF ("resize.oofm", 1, + "opposite side (after collision (v) test): " + "checking %p (#%d/%d, GB: %p) against " + "%p (#%d/%d, GB: %p)", + vloat->getWidget (), index, + vloat->sideSpanningIndex, + vloat->generatingBlock, + oppList->get(oppIndexTmp)->getWidget (), + oppList->get(oppIndexTmp)->getIndex (CB), + oppList->get(oppIndexTmp)->sideSpanningIndex, + oppList->get(oppIndexTmp)->generatingBlock); + + // ... but stop the loop as soon as the horizontal dimensions + // test is positive. + if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) { + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> collides (h), new yReal = %d (old: %d)", + yRealNewOpp, vloat->yReal); + foundColl = true; + if (vloat->yReal != yRealNewOpp) { + needsChange = true; + yRealNew = min (yRealNew, yRealNewOpp); + } + } else + DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)"); + } + } + } + + if (needsChange) + vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew), + vloat->getWidget ()); + } + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::doFloatsExceedCB (Side side) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s", + side == LEFT ? "LEFT" : "RIGHT"); + + // This method is called to determine whether the *requisition* of + // the CB must be recalculated. So, we check the float allocations + // against the *requisition* of the CB, which may (e. g. within + // tables) differ from the new allocation. (Generally, a widget may + // allocated at a different size.) + core::Requisition cbReq; + container->sizeRequest (&cbReq); + + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + bool exceeds = false; + + DBG_OBJ_MSG_START (); + + for (int i = 0; i < list->size () && !exceeds; i++) { + Float *vloat = list->get (i); + if (vloat->getWidget()->wasAllocated ()) { + Allocation *fla = vloat->getWidget()->getAllocation (); + DBG_OBJ_MSGF ("resize.oofm", 2, + "Does FlA = (%d, %d, %d * %d) exceed CB req+alloc = " + "(%d, %d, %d * %d)?", + fla->x, fla->y, fla->width, fla->ascent + fla->descent, + containerAllocation.x, containerAllocation.y, + cbReq.width, cbReq.ascent + cbReq.descent); + if (fla->x + fla->width > containerAllocation.x + cbReq.width || + fla->y + fla->ascent + fla->descent + > containerAllocation.y + cbReq.ascent + cbReq.descent) { + exceeds = true; + DBG_OBJ_MSG ("resize.oofm", 2, "Yes."); + } else + DBG_OBJ_MSG ("resize.oofm", 2, "No."); + } + } + + DBG_OBJ_MSG_END (); + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false"); + DBG_OBJ_LEAVE (); + + return exceeds; +} + +bool OOFFloatsMgr::haveExtremesChanged (Side side) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s", + side == LEFT ? "LEFT" : "RIGHT"); + + // This is quite different from doFloatsExceedCB, since there is no + // counterpart to getExtremes, as sizeAllocate is a counterpart to + // sizeRequest. So we have to determine whether the allocation has + // changed the extremes, which is done by examining the part of the + // allocation which is part of the extremes calculation (see + // getFloatsExtremes). Changes of the extremes are handled by the + // normal queueResize mechanism. + + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + bool changed = false; + + for (int i = 0; i < list->size () && !changed; i++) { + Float *vloat = list->get (i); + // When the GB is the CB, an allocation change does not play a + // role here. + if (vloat->generatingBlock != container) { + if (!vloat->wasThenAllocated () && vloat->isNowAllocated ()) + changed = true; + else { + // This method is called within sizeAllocateEnd, where + // containinBlock->getAllocation() (old value) and + // containinBlockAllocation (new value) are different. + + Allocation *oldCBA = container->getAllocation (); + Allocation *newCBA = &containerAllocation; + + // Compare also to getFloatsExtremes. The box difference + // of the GB (from style) has not changed in this context, + // so it is ignored. + + int oldDiffLeft = vloat->getOldXCB (); + int newDiffLeft = vloat->getNewXCB (); + int oldDiffRight = + oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ()); + int newDiffRight = + newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ()); + + if (// regarding minimum + (side == LEFT && oldDiffLeft != newDiffLeft) || + (side == RIGHT && oldDiffRight != newDiffRight) || + // regarding maximum + oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight) + changed = true; + } + } + } + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false"); + DBG_OBJ_LEAVE (); + + return changed; +} + +void OOFFloatsMgr::moveFromGBToCB (Side side) +{ + DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s", + side == LEFT ? "LEFT" : "RIGHT"); + + SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB; + int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark; + + for (int mark = 0; mark <= *floatsMark; mark++) + for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator (); + it.hasNext (); ) { + TBInfo *tbInfo = it.getNext (); + SortedFloatsVector *src = + side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; + for (int i = 0; i < src->size (); i++) { + Float *vloat = src->get (i); + // "vloat->indexCBList == -1": prevent copying the vloat twice. + if (vloat->indexCBList == -1 && vloat->mark == mark) { + dest->put (vloat); + DBG_OBJ_MSGF ("oofm.resize", 1, + "moving float %p (mark %d) to CB list\n", + vloat->getWidget (), vloat->mark); + DBG_OBJ_SET_NUM (side == LEFT ? + "leftFloatsCB.size" : "rightFloatsCB.size", + dest->size()); + DBG_OBJ_ARRATTRSET_PTR (side == LEFT ? + "leftFloatsCB" : "rightFloatsCB", + dest->size() - 1, "widget", + vloat->getWidget ()); + + } + } + } + + *floatsMark = 0; + + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat) +{ + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + int *lastAllocatedFloat = + side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat; + + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats", + "%s, [%d ->] %d [size = %d]", + side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat, + newLastAllocatedFloat, list->size ()); + + Allocation *cba = &containerAllocation; + + for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) { + Float *vloat = list->get(i); + ensureFloatSize (vloat); + + Allocation *gba = getAllocation (vloat->generatingBlock); + int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth(); + + Allocation childAllocation; + childAllocation.x = cba->x + + calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth); + childAllocation.y = gba->y + vloat->yReal; + childAllocation.width = vloat->size.width; + childAllocation.ascent = vloat->size.ascent; + childAllocation.descent = vloat->size.descent; + + vloat->getWidget()->sizeAllocate (&childAllocation); + } + + *lastAllocatedFloat = newLastAllocatedFloat; + + DBG_OBJ_LEAVE (); +} + + +/** + * \brief ... + * + * gbX is given relative to the CB, as is the return value. + */ +int OOFFloatsMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, + int gbLineBreakWidth) +{ + DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d, %d", + vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX, + gbWidth, gbLineBreakWidth); + int x; + + switch (side) { + case LEFT: + // Left floats are always aligned on the left side of the + // generator (content, not allocation) ... + x = gbX + vloat->generatingBlock->boxOffsetX(); + DBG_OBJ_MSGF ("resize.oofm", 1, "left: x = %d + %d = %d", + gbX, vloat->generatingBlock->boxOffsetX(), x); + // ... but when the float exceeds the line break width of the + // container, it is corrected (but not left of the container). + // This way, we save space and, especially within tables, avoid + // some problems. + if (wasAllocated (container) && + x + vloat->size.width > container->getLineBreakWidth ()) { + x = max (0, container->getLineBreakWidth () - vloat->size.width); + DBG_OBJ_MSGF ("resize.common", 1, + "corrected to: max (0, %d - %d) = %d", + container->getLineBreakWidth (), vloat->size.width, + x); + } + break; + + case RIGHT: + // Similar for right floats, but in this case, floats are + // shifted to the right when they are too big (instead of + // shifting the generator to the right). + + // Notice that not the actual width, but the line break width is + // used. (This changed for GROWS, where the width of a textblock + // is often smaller that the line break.) + + x = max (gbX + gbLineBreakWidth - vloat->size.width + - vloat->generatingBlock->boxRestWidth(), + // Do not exceed CB allocation: + 0); + DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d", + gbX, gbLineBreakWidth, vloat->size.width, + vloat->generatingBlock->boxRestWidth(), x); + break; + + default: + assertNotReached (); + x = 0; + break; + } + + DBG_OBJ_LEAVE (); + return x; +} + + +void OOFFloatsMgr::draw (View *view, Rectangle *area) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + + drawFloats (leftFloatsCB, view, area); + drawFloats (rightFloatsCB, view, area); + + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view, + Rectangle *area) +{ + // This could be improved, since the list is sorted: search the + // first float fitting into the area, and iterate until one is + // found below the area. + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + Rectangle childArea; + if (vloat->getWidget()->intersects (area, &childArea)) + vloat->getWidget()->draw (view, &childArea); + } +} + +void OOFFloatsMgr::addWidgetInFlow (OOFAwareWidget *textblock, + OOFAwareWidget *parentBlock, + int externalIndex) +{ + //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n", + // container, textblock, parentBlock, externalIndex); + + TBInfo *tbInfo = + new TBInfo (this, textblock, + parentBlock ? getOOFAwareWidget (parentBlock) : NULL, + externalIndex); + tbInfo->index = tbInfos->size(); + + tbInfos->put (tbInfo); + tbInfosByOOFAwareWidget->put (new TypedPointer<OOFAwareWidget> (textblock), + tbInfo); +} + +int OOFFloatsMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generatingBlock, + int externalIndex) +{ + DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d", + widget, generatingBlock, externalIndex); + + int subRef; + + TBInfo *tbInfo = getOOFAwareWidget (generatingBlock); + Float *vloat = new Float (this, widget, generatingBlock, externalIndex); + + // Note: Putting the float first in the GB list, and then, possibly + // into the CB list (in that order) will trigger setting + // Float::inCBList to the right value. + + switch (widget->getStyle()->vloat) { + case FLOAT_LEFT: + leftFloatsAll->put (vloat); + DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); + DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1, + "widget", vloat->getWidget ()); + + subRef = createSubRefLeftFloat (leftFloatsAll->size() - 1); + tbInfo->leftFloatsGB->put (vloat); + + if (wasAllocated (generatingBlock)) { + leftFloatsCB->put (vloat); + DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); + DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1, + "widget", vloat->getWidget ()); + } else { + if (tbInfo->index < lastLeftTBIndex) + leftFloatsMark++; + + vloat->mark = leftFloatsMark; + lastLeftTBIndex = tbInfo->index; + } + break; + + case FLOAT_RIGHT: + rightFloatsAll->put (vloat); + DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); + DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1, + "widget", vloat->getWidget ()); + + subRef = createSubRefRightFloat (rightFloatsAll->size() - 1); + tbInfo->rightFloatsGB->put (vloat); + + if (wasAllocated (generatingBlock)) { + rightFloatsCB->put (vloat); + DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); + DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1, + "widget", vloat->getWidget ()); + } else { + if (tbInfo->index < lastRightTBIndex) + rightFloatsMark++; + + vloat->mark = rightFloatsMark; + lastRightTBIndex = tbInfo->index; + } + + break; + + default: + assertNotReached(); + } + + // "sideSpanningIndex" is only compared, so this simple assignment + // is sufficient; differenciation between GB and CB lists is not + // neccessary. TODO: Can this also be applied to "index", to + // simplify the current code? Check: where is "index" used. + vloat->sideSpanningIndex = + leftFloatsAll->size() + rightFloatsAll->size() - 1; + + floatsByWidget->put (new TypedPointer<Widget> (widget), vloat); + + DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef); + DBG_OBJ_LEAVE (); + return subRef; +} + +void OOFFloatsMgr::moveExternalIndices (OOFAwareWidget *generatingBlock, + int oldStartIndex, int diff) +{ + TBInfo *tbInfo = getOOFAwareWidget (generatingBlock); + moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff); + moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff); +} + +void OOFFloatsMgr::moveExternalIndices (SortedFloatsVector *list, + int oldStartIndex, int diff) +{ + // Could be faster with binary search, but the GB (not CB!) lists + // should be rather small. + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + if (vloat->externalIndex >= oldStartIndex) { + vloat->externalIndex += diff; + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex", + vloat->externalIndex); + } + } +} + +OOFFloatsMgr::Float *OOFFloatsMgr::findFloatByWidget (Widget *widget) +{ + TypedPointer <Widget> key (widget); + Float *vloat = floatsByWidget->get (&key); + assert (vloat != NULL); + return vloat; +} + +void OOFFloatsMgr::markSizeChange (int ref) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref); + + Float *vloat; + + if (isSubRefLeftFloat (ref)) + vloat = leftFloatsAll->get (getFloatIndexFromSubRef (ref)); + else if (isSubRefRightFloat (ref)) + vloat = rightFloatsAll->get (getFloatIndexFromSubRef (ref)); + else { + assertNotReached(); + vloat = NULL; // compiler happiness + } + + vloat->dirty = vloat->sizeChangedSinceLastAllocation = true; + + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), + "<Float>.sizeChangedSinceLastAllocation", + vloat->sizeChangedSinceLastAllocation); + + // The generating block is told directly about this. (Others later, in + // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which + // differentiates many special cases), but the size is not known yet, + vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ()); + + DBG_OBJ_LEAVE (); +} + + +void OOFFloatsMgr::markExtremesChange (int ref) +{ + // Nothing to do here. +} + +Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y, 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 x, int y) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d, %d", + widget, x, y); + + assert (y >= 0); + + Float *vloat = findFloatByWidget(widget); + + SortedFloatsVector *listSame, *listOpp; + Side side; + getFloatsListsAndSide (vloat, &listSame, &listOpp, &side); + ensureFloatSize (vloat); + + // "yReal" may change due to collisions (see below). + vloat->yReq = vloat->yReal = y; + + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq); + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); + + // Test collisions (on this side). Although there are (rare) cases + // where it could make sense, the horizontal dimensions are not + // tested; especially since searching and border calculation would + // be confused. For this reaspn, only the previous float is + // relevant. (Cf. below, collisions on the other side.) + int index = vloat->getIndex (listSame->type), yRealNew; + if (index >= 1 && + collidesV (vloat, listSame->get (index - 1), listSame->type, + &yRealNew)) { + vloat->yReal = yRealNew; + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); + } + + // Test collisions (on the opposite side). There are cases when + // more than one float has to be tested. Consider the following + // HTML snippet ("id" attribute only used for simple reference + // below, as #f1, #f2, and #f3): + // + // <div style="float:left" id="f1"> + // Left left left left left left left left left left. + // </div> + // <div style="float:left" id="f2">Also left.</div> + // <div style="float:right" id="f3">Right.</div> + // + // When displayed with a suitable window width (only slightly wider + // than the text within #f1), this should look like this: + // + // --------------------------------------------------------- + // | Left left left left left left left left left left. | + // | Also left. Right. | + // --------------------------------------------------------- + // + // Consider float #f3: a collision test with #f2, considering + // vertical dimensions, is positive, but not the test with + // horizontal dimensions (because #f2 and #f3 are too + // narrow). However, a collision has to be tested with #f1; + // otherwise #f3 and #f1 would overlap. + + int oppFloatIndex = + listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex); + // Generally, the rules are simple: loop as long as the vertical + // dimensions test is positive (and, of course, there are floats), + // ... + for (bool foundColl = false; + !foundColl && oppFloatIndex >= 0 && + collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type, + &yRealNew); + oppFloatIndex--) { + // ... but stop the loop as soon as the horizontal dimensions + // test is positive. + if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) { + vloat->yReal = yRealNew; + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); + foundColl = true; + } + } + + DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d", + vloat->yReq, vloat->yReal); + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::collidesV (Float *vloat, Float *other, SFVType type, + int *yReal) +{ + // Only checks vertical (possible) collisions, and only refers to + // vloat->yReal; never to vloat->allocation->y, even when the GBs are + // different. Used only in tellPosition. + + DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...", + vloat->getIndex (type), vloat->getWidget (), + other->getIndex (type), other->getWidget ()); + + bool result; + + DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal); + + if (vloat->generatingBlock == other->generatingBlock) { + ensureFloatSize (other); + int otherBottomGB = + other->yReal + other->size.ascent + other->size.descent; + + DBG_OBJ_MSGF ("resize.oofm", 1, + "same generators: otherBottomGB = %d + (%d + %d) = %d", + other->yReal, other->size.ascent, other->size.descent, + otherBottomGB); + + if (vloat->yReal < otherBottomGB) { + *yReal = otherBottomGB; + result = true; + } else + result = false; + } else { + assert (wasAllocated (vloat->generatingBlock)); + assert (wasAllocated (other->generatingBlock)); + + // If the other float is not allocated, there is no collision. The + // allocation of this float (vloat) is not used at all. + if (!other->getWidget()->wasAllocated ()) + result = false; + else { + Allocation *gba = getAllocation (vloat->generatingBlock), + *flaOther = other->getWidget()->getAllocation (); + int otherBottomGB = + flaOther->y + flaOther->ascent + flaOther->descent - gba->y; + + DBG_OBJ_MSGF ("resize.oofm", 1, + "different generators: " + "otherBottomGB = %d + (%d + %d) - %d = %d", + flaOther->y, flaOther->ascent, flaOther->descent, gba->y, + otherBottomGB); + + if (vloat->yReal < otherBottomGB) { + *yReal = otherBottomGB; + result = true; + } else + result = false; + } + } + + if (result) + DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal); + else + DBG_OBJ_MSG ("resize.oofm", 1, "does not collide"); + + DBG_OBJ_LEAVE (); + return result; +} + + +bool OOFFloatsMgr::collidesH (Float *vloat, Float *other, SFVType type) +{ + // Only checks horizontal collision. For a complete test, use + // collidesV (...) && collidesH (...). + bool collidesH; + + if (vloat->generatingBlock == other->generatingBlock) + collidesH = vloat->size.width + other->size.width + + vloat->generatingBlock->boxDiffWidth() + > vloat->generatingBlock->getLineBreakWidth(); + else { + assert (wasAllocated (vloat->generatingBlock)); + assert (wasAllocated (other->generatingBlock)); + + // Again, if the other float is not allocated, there is no + // collision. Compare to collidesV. (But vloat->size is used + // here.) + if (!other->getWidget()->wasAllocated ()) + collidesH = false; + else { + Allocation *gba = getAllocation (vloat->generatingBlock); + int vloatX = + calcFloatX (vloat, + vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ? + LEFT : RIGHT, + gba->x, gba->width, + vloat->generatingBlock->getLineBreakWidth ()); + + // Generally: right border of the left float > left border of + // the right float (all in canvas coordinates). + if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT) + // "vloat" is left, "other" is right + collidesH = vloatX + vloat->size.width + > other->getWidget()->getAllocation()->x; + else + // "other" is left, "vloat" is right + collidesH = other->getWidget()->getAllocation()->x + + other->getWidget()->getAllocation()->width + > vloatX; + } + } + + return collidesH; +} + +void OOFFloatsMgr::getFloatsListsAndSide (Float *vloat, + SortedFloatsVector **listSame, + SortedFloatsVector **listOpp, + Side *side) +{ + TBInfo *tbInfo = getOOFAwareWidget (vloat->generatingBlock); + + switch (vloat->getWidget()->getStyle()->vloat) { + case FLOAT_LEFT: + if (wasAllocated (vloat->generatingBlock)) { + if (listSame) *listSame = leftFloatsCB; + if (listOpp) *listOpp = rightFloatsCB; + } else { + if (listSame) *listSame = tbInfo->leftFloatsGB; + if (listOpp) *listOpp = tbInfo->rightFloatsGB; + } + if (side) *side = LEFT; + break; + + case FLOAT_RIGHT: + if (wasAllocated (vloat->generatingBlock)) { + if (listSame) *listSame = rightFloatsCB; + if (listOpp) *listOpp = leftFloatsCB; + } else { + if (listSame) *listSame = tbInfo->rightFloatsGB; + if (listOpp) *listOpp = tbInfo->leftFloatsGB; + } + if (side) *side = RIGHT; + break; + + default: + assertNotReached(); + } +} + +void OOFFloatsMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight) +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); + + int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight; + getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft); + getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight); + + // Floats must be within the *content* area of the containing + // block, not its *margin* area (which is equivalent to the + // requisition / allocation). For this reason, boxRestWidth() and + // boxRestHeight() are added here. + + *oofWidth = + max (oofWidthtLeft, oofWidthRight) + container->boxRestWidth (); + *oofHeight = + max (oofHeightLeft, oofHeightRight) + container->boxRestHeight (); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)", + oofWidthtLeft, oofWidthRight, *oofWidth, oofHeightLeft, + oofHeightRight, *oofHeight); + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::getFloatsSize (Requisition *cbReq, Side side, int *width, + int *height) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...", + cbReq->width, cbReq->ascent, cbReq->descent, + side == LEFT ? "LEFT" : "RIGHT"); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side); + + *width = *height = 0; + + DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size()); + + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + + if (vloat->generatingBlock == container || + wasAllocated (vloat->generatingBlock)) { + ensureFloatSize (vloat); + int x, y; + + if (vloat->generatingBlock == container) { + x = calcFloatX (vloat, side, 0, cbReq->width, + vloat->generatingBlock->getLineBreakWidth ()); + y = vloat->yReal; + } else { + Allocation *gba = getAllocation(vloat->generatingBlock); + x = calcFloatX (vloat, side, + gba->x - containerAllocation.x, gba->width, + vloat->generatingBlock->getLineBreakWidth ()); + y = gba->y - containerAllocation.y + vloat->yReal; + } + + *width = max (*width, x + vloat->size.width); + *height = max (*height, y + vloat->size.ascent + vloat->size.descent); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: (%d + %d) * " + "(%d + (%d + %d)) => %d * %d", + vloat->getWidget (), vloat->generatingBlock, + x, vloat->size.width, + y, vloat->size.ascent, vloat->size.descent, + *width, *height); + } else + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: not allocated", + vloat->getWidget (), vloat->generatingBlock); + } + + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth, + int *oofMaxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", + cbExtr->minWidth, cbExtr->maxWidth); + + int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight; + getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft); + getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight); + + *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight); + *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)", + oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth, + oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth); + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side, + int *minWidth, int *maxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...", + cbExtr->minWidth, cbExtr->maxWidth, + side == LEFT ? "LEFT" : "RIGHT"); + + *minWidth = *maxWidth = 0; + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side); + DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size()); + + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + int leftDiff, rightDiff; + + if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) { + Extremes extr; + vloat->getWidget()->getExtremes (&extr); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: %d / %d", + vloat->getWidget (), vloat->generatingBlock, + extr.minWidth, extr.maxWidth); + + // TODO: Or zero (instead of rightDiff) for right floats? + *minWidth = + max (*minWidth, + extr.minWidth + (side == LEFT ? leftDiff : rightDiff)); + *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff); + + DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth); + } else + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: not allocated", + vloat->getWidget (), vloat->generatingBlock); + } + + DBG_OBJ_LEAVE (); +} + +// Returns "false" when borders cannot yet determined; *leftDiff and +// *rightDiff are undefined in this case. +bool OOFFloatsMgr::getFloatDiffToCB (Float *vloat, int *leftDiff, + int *rightDiff) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB", + "float %p [generated by %p], ...", + vloat->getWidget (), vloat->generatingBlock); + + bool result; + + if (vloat->generatingBlock == container) { + *leftDiff = vloat->generatingBlock->boxOffsetX(); + *rightDiff = vloat->generatingBlock->boxRestWidth(); + result = true; + DBG_OBJ_MSGF ("resize.oofm", 1, + "GB == CB => leftDiff = %d, rightDiff = %d", + *leftDiff, *rightDiff); + } else if (wasAllocated (vloat->generatingBlock)) { + Allocation *gba = getAllocation(vloat->generatingBlock); + *leftDiff = gba->x - containerAllocation.x + + vloat->generatingBlock->boxOffsetX(); + *rightDiff = + (containerAllocation.x + containerAllocation.width) + - (gba->x + gba->width) + + vloat->generatingBlock->boxRestWidth(); + result = true; + DBG_OBJ_MSGF ("resize.oofm", 1, + "GB != CB => leftDiff = %d - %d + %d = %d, " + "rightDiff = (%d + %d) - (%d + %d) + %d = %d", + gba->x, containerAllocation.x, + vloat->generatingBlock->boxOffsetX(), *leftDiff, + containerAllocation.x, containerAllocation.width, + gba->x, gba->width, vloat->generatingBlock->boxRestWidth(), + *rightDiff); + } else { + DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated"); + result = false; + } + + DBG_OBJ_LEAVE (); + return result; +} + +OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidgetWhenRegistered + (OOFAwareWidget *widget) +{ + DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidgetWhenRegistered", "%p", + widget); + TypedPointer<OOFAwareWidget> key (widget); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (&key); + DBG_OBJ_MSGF ("oofm.common", 1, "found? %s", tbInfo ? "yes" : "no"); + DBG_OBJ_LEAVE (); + return tbInfo; +} + +OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidget (OOFAwareWidget *widget) +{ + DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidget", "%p", widget); + TBInfo *tbInfo = getOOFAwareWidgetWhenRegistered (widget); + assert (tbInfo); + DBG_OBJ_LEAVE (); + return tbInfo; +} + +/** + * Get the left border for the vertical position of *y*, for a height + * of *h", based on floats; relative to the allocation of the calling + * textblock. + * + * The border includes marging/border/padding of the calling textblock + * but is 0 if there is no float, so a caller should also consider + * other borders. + */ +int OOFFloatsMgr::getLeftBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d", + textblock, y, h, lastGB, lastExtIndex, b); + return b; +} + +/** + * Get the right border for the vertical position of *y*, for a height + * of *h*, based on floats. + * + * See also getLeftBorder(int, int); + */ +int OOFFloatsMgr::getRightBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d", + textblock, y, h, lastGB, lastExtIndex, b); + return b; +} + +int OOFFloatsMgr::getBorder (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int last; + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last); + + DBG_OBJ_MSGF ("border", 1, "first = %d", first); + + if (first == -1) { + // No float. + DBG_OBJ_LEAVE (); + return 0; + } else { + // It is not sufficient to find the first float, since a line + // (with height h) may cover the region of multiple float, of + // which the widest has to be choosen. + int border = 0; + bool covers = true; + + // We are not searching until the end of the list, but until the + // float defined by lastGB and lastExtIndex. + for (int i = first; covers && i <= last; i++) { + Float *vloat = list->get(i); + covers = vloat->covers (textblock, y, h); + DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.", + i, vloat->getWidget(), covers ? "<b>yes</b>" : "no"); + + if (covers) { + int thisBorder; + if (vloat->generatingBlock == textblock) { + int borderIn = side == LEFT ? + vloat->generatingBlock->boxOffsetX() : + vloat->generatingBlock->boxRestWidth(); + thisBorder = vloat->size.width + borderIn; + DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d", + vloat->size.width, borderIn, thisBorder); + } else { + assert (wasAllocated (vloat->generatingBlock)); + assert (vloat->getWidget()->wasAllocated ()); + + Allocation *tba = getAllocation(textblock), + *fla = vloat->getWidget()->getAllocation (); + if (side == LEFT) { + thisBorder = fla->x + fla->width - tba->x; + DBG_OBJ_MSGF ("border", 1, + "not GB: thisBorder = %d + %d - %d = %d", + fla->x, fla->width, tba->x, thisBorder); + } else { + // See also calcFloatX. + thisBorder = + tba->x + textblock->getLineBreakWidth () - fla->x; + DBG_OBJ_MSGF ("border", 1, + "not GB: thisBorder = %d + %d - %d " + "= %d", + tba->x, textblock->getLineBreakWidth (), fla->x, + thisBorder); + } + } + + border = max (border, thisBorder); + DBG_OBJ_MSGF ("border", 1, "=> border = %d", border); + } + } + + DBG_OBJ_LEAVE (); + return border; + } +} + + +OOFFloatsMgr::SortedFloatsVector *OOFFloatsMgr::getFloatsListForOOFAwareWidget + (OOFAwareWidget *textblock, Side side) +{ + DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForOOFAwareWidget", "%p, %s", + textblock, side == LEFT ? "LEFT" : "RIGHT"); + + OOFFloatsMgr::SortedFloatsVector *list; + + if (wasAllocated (textblock)) { + DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list"); + list = side == LEFT ? leftFloatsCB : rightFloatsCB; + } else { + DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list"); + TBInfo *tbInfo = getOOFAwareWidget (textblock); + list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; + } + + DBG_OBJ_LEAVE (); + return list; +} + + +bool OOFFloatsMgr::hasFloatLeft (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s", + textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); + return b; +} + +bool OOFFloatsMgr::hasFloatRight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s", + textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); + return b; +} + +bool OOFFloatsMgr::hasFloat (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); + + DBG_OBJ_MSGF ("border", 1, "first = %d", first); + DBG_OBJ_LEAVE (); + return first != -1; +} + +int OOFFloatsMgr::getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex); +} + +int OOFFloatsMgr::getRightFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex); +} + +// Calculate height from the position *y*. +int OOFFloatsMgr::getFloatHeight (OOFAwareWidget *textblock, Side side, int y, + int h, OOFAwareWidget *lastGB, + int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); + assert (first != -1); /* This method must not be called when there is no + float on the respective side. */ + + Float *vloat = list->get(first); + int yRelToFloat; + + if (vloat->generatingBlock == textblock) { + yRelToFloat = y - vloat->yReal; + DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d", + y, vloat->yReal, yRelToFloat); + } else { + // The respective widgets are allocated; otherwise, hasFloat() would have + // returned false. + assert (wasAllocated (textblock)); + assert (vloat->getWidget()->wasAllocated ()); + + Allocation *tba = getAllocation(textblock), + *fla = vloat->getWidget()->getAllocation (); + yRelToFloat = 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 (OOFAwareWidget *textblock) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", textblock); + + int pos; + + if (textblock->getStyle()) { + bool left = false, right = false; + switch (textblock->getStyle()->clear) { + case CLEAR_NONE: break; + case CLEAR_LEFT: left = true; break; + case CLEAR_RIGHT: right = true; break; + case CLEAR_BOTH: left = right = true; break; + default: assertNotReached (); + } + + pos = max (left ? 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; +}; + +bool OOFFloatsMgr::mayAffectBordersAtAll () +{ + return true; +} + +int OOFFloatsMgr::getClearPosition (OOFAwareWidget *textblock, Side side) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s", + textblock, side == LEFT ? "LEFT" : "RIGHT"); + + int pos; + + if (!wasAllocated (textblock)) + // There is no relation yet to floats generated by other + // textblocks, and this textblocks floats are unimportant for + // the "clear" property. + pos = 0; + else { + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + + // Search the last float before (therfore -1) this textblock. + int i = list->findFloatIndex (textblock, -1); + if (i < 0) { + pos = 0; + DBG_OBJ_MSG ("resize.oofm", 1, "no float"); + } else { + Float *vloat = list->get(i); + assert (vloat->generatingBlock != textblock); + 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 = container->getLineBreakWidth (); + vloat->dirty = false; + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); + + DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)", + vloat->size.width, vloat->size.ascent, vloat->size.descent); + + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width", + vloat->size.width); + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent", + vloat->size.ascent); + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent", + vloat->size.descent); + + // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd() + } + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::dealingWithSizeOfChild (core::Widget *child) +{ + return false; +} + +int OOFFloatsMgr::getAvailWidthOfChild (Widget *child, bool forceValue) +{ + assertNotReached (); + return 0; +} + +int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue) +{ + assertNotReached (); + return 0; +} + +int OOFFloatsMgr::getNumWidgets () +{ + return leftFloatsAll->size() + rightFloatsAll->size(); +} + +Widget *OOFFloatsMgr::getWidget (int i) +{ + if (i < leftFloatsAll->size()) + return leftFloatsAll->get(i)->getWidget (); + else + return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget (); +} + +} // namespace oof + +} // namespace dw diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh new file mode 100644 index 00000000..47bcbab4 --- /dev/null +++ b/dw/ooffloatsmgr.hh @@ -0,0 +1,396 @@ +#ifndef __DW_OOFFLOATSMGR_HH__ +#define __DW_OOFFLOATSMGR_HH__ + +#include "outofflowmgr.hh" + +namespace dw { + +namespace oof { + +/** + * \brief OutOfFlowMgr implementation dealing with floats. + * + * Note: The identifiers and comments of this class still refer to + * "Textblock" instead of "OOFAwareWidget"; should be cleaned up some + * day. (OTOH, these widgets are always textblocks.) + */ +class OOFFloatsMgr: public OutOfFlowMgr +{ + friend class WidgetInfo; + +private: + enum Side { LEFT, RIGHT }; + enum SFVType { GB, CB }; + + OOFAwareWidget *container; + + // These two values are redundant to TBInfo::wasAllocated and + // TBInfo::allocation, for some special cases. + bool containerWasAllocated; + core::Allocation containerAllocation; + + class WidgetInfo: public lout::object::Object + { + private: + bool wasAllocated; + int xCB, yCB; // relative to the containing block + int width, height; + + OOFFloatsMgr *oofm; + core::Widget *widget; + + protected: + OOFFloatsMgr *getOOFFloatsMgr () { return oofm; } + + public: + WidgetInfo (OOFFloatsMgr *oofm, core::Widget *widget); + + inline bool wasThenAllocated () { return wasAllocated; } + inline int getOldXCB () { return xCB; } + inline int getOldYCB () { return yCB; } + inline int getOldWidth () { return width; } + inline int getOldHeight () { return height; } + + + void update (bool wasAllocated, int xCB, int yCB, int width, int height); + + inline core::Widget *getWidget () { return widget; } + }; + + class Float: public WidgetInfo + { + public: + class ComparePosition: public lout::object::Comparator + { + private: + OOFFloatsMgr *oofm; + OOFAwareWidget *refTB; + SFVType type; // actually only used for debugging + + public: + ComparePosition (OOFFloatsMgr *oofm, OOFAwareWidget *refTB, + SFVType type) + { this->oofm = oofm; this->refTB = refTB; this->type = type; } + int compare(Object *o1, Object *o2); + }; + + class CompareSideSpanningIndex: public lout::object::Comparator + { + public: + int compare(Object *o1, Object *o2); + }; + + class CompareGBAndExtIndex: public lout::object::Comparator + { + private: + OOFFloatsMgr *oofm; + SFVType type; // actually only used for debugging + + public: + CompareGBAndExtIndex (OOFFloatsMgr *oofm, SFVType type) + { this->oofm = oofm; this->type = type; } + int compare(Object *o1, Object *o2); + }; + + OOFAwareWidget *generatingBlock; + int externalIndex; + int yReq, yReal; // relative to generator, not container + int indexGBList; /* Refers to TBInfo::leftFloatsGB or + TBInfo::rightFloatsGB, respectively. -1 + initially. */ + int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB, + respectively. -1 initially. */ + int sideSpanningIndex, mark; + core::Requisition size; + int cbLineBreakWidth; /* On which the calculation of relative sizes + is based. Height not yet used, and probably + not added before size redesign. */ + bool dirty, sizeChangedSinceLastAllocation; + + Float (OOFFloatsMgr *oofm, core::Widget *widget, + OOFAwareWidget *generatingBlock, int externalIndex); + + inline bool isNowAllocated () { return getWidget()->wasAllocated (); } + inline int getNewXCB () { return getWidget()->getAllocation()->x - + getOOFFloatsMgr()->containerAllocation.x; } + inline int getNewYCB () { return getWidget()->getAllocation()->y - + getOOFFloatsMgr()->containerAllocation.y; } + inline int getNewWidth () { return getWidget()->getAllocation()->width; } + inline int getNewHeight () { return getWidget()->getAllocation()->ascent + + getWidget()->getAllocation()->descent; } + void updateAllocation (); + + inline int *getIndexRef (SFVType type) { + return type == GB ? &indexGBList : &indexCBList; } + inline int getIndex (SFVType type) { return *(getIndexRef (type)); } + inline void setIndex (SFVType type, int value) { + *(getIndexRef (type)) = value; } + + void intoStringBuffer(lout::misc::StringBuffer *sb); + + bool covers (OOFAwareWidget *textblock, int y, int h); + }; + + /** + * This list is kept sorted. + * + * To prevent accessing methods of the base class in an + * uncontrolled way, the inheritance is private, not public; this + * means that all methods must be delegated (see iterator(), size() + * etc. below.) + * + * TODO Update comment: still sorted, but ... + * + * More: add() and change() may check order again. + */ + class SortedFloatsVector: private lout::container::typed::Vector<Float> + { + public: + SFVType type; + + private: + OOFFloatsMgr *oofm; + Side side; + + public: + inline SortedFloatsVector (OOFFloatsMgr *oofm, Side side, SFVType type) : + lout::container::typed::Vector<Float> (1, false) + { this->oofm = oofm; this->side = side; this->type = type; } + + int findFloatIndex (OOFAwareWidget *lastGB, int lastExtIndex); + int find (OOFAwareWidget *textblock, int y, int start, int end); + int findFirst (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex, int *lastReturn); + int findLastBeforeSideSpanningIndex (int sideSpanningIndex); + void put (Float *vloat); + + inline lout::container::typed::Iterator<Float> iterator() + { return lout::container::typed::Vector<Float>::iterator (); } + inline int size () + { return lout::container::typed::Vector<Float>::size (); } + inline Float *get (int pos) + { return lout::container::typed::Vector<Float>::get (pos); } + inline void clear () + { lout::container::typed::Vector<Float>::clear (); } + }; + + class TBInfo: public WidgetInfo + { + public: + int lineBreakWidth; + int index; // position within "tbInfos" + + TBInfo *parent; + int parentExtIndex; + + // These two values are set by sizeAllocateStart(), and they are + // accessable also within sizeAllocateEnd() for the same + // textblock, for which allocation and WAS_ALLOCATED is set + // *after* sizeAllocateEnd(). See the two functions + // wasAllocated(Widget*) and getAllocation(Widget*) (further + // down) for usage. + bool wasAllocated; + core::Allocation allocation; + + // These two lists store all floats generated by this textblock, + // as long as this textblock is not allocates. + SortedFloatsVector *leftFloatsGB, *rightFloatsGB; + + TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock, + TBInfo *parent, int parentExtIndex); + ~TBInfo (); + + inline bool isNowAllocated () { + return getOOFFloatsMgr()->wasAllocated (getOOFAwareWidget ()); } + inline int getNewXCB () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->x - + getOOFFloatsMgr()->containerAllocation.x; } + inline int getNewYCB () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->y - + getOOFFloatsMgr()->containerAllocation.y; } + inline int getNewWidth () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->width; } + inline int getNewHeight () { + core::Allocation *allocation = + getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ()); + return allocation->ascent + allocation->descent; } + void updateAllocation (); + + inline OOFAwareWidget *getOOFAwareWidget () + { return (OOFAwareWidget*)getWidget (); } + }; + + // These two lists store all floats, in the order in which they are + // defined. Only used for iterators. + lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll; + + // These two lists store all floats whose generators are already + // allocated. + SortedFloatsVector *leftFloatsCB, *rightFloatsCB; + + // These two attributes are used in the size allocation process; + // see sizeAllocateStart and sizeAllocateEnd. + int lastAllocatedLeftFloat, lastAllocatedRightFloat; + + lout::container::typed::HashTable<lout::object::TypedPointer + <dw::core::Widget>, Float> *floatsByWidget; + + lout::container::typed::Vector<TBInfo> *tbInfos; + lout::container::typed::HashTable<lout::object::TypedPointer<OOFAwareWidget>, + TBInfo> *tbInfosByOOFAwareWidget; + + int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark; + + /** + * Variant of Widget::wasAllocated(), which can also be used within + * OOFM::sizeAllocateEnd(). + */ + inline bool wasAllocated (OOFAwareWidget *textblock) { + return getOOFAwareWidget(textblock)->wasAllocated; + } + + /** + * Variant of Widget::getAllocation(), which can also be used + * within OOFM::sizeAllocateEnd(). + */ + inline core::Allocation *getAllocation (OOFAwareWidget *textblock) { + return &(getOOFAwareWidget(textblock)->allocation); + } + + void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex, + int diff); + Float *findFloatByWidget (core::Widget *widget); + + void moveFromGBToCB (Side side); + void sizeAllocateFloats (Side side, int newLastAllocatedFloat); + int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, + int gbLineBreakWidth); + + bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos, + core::Widget **minFloat); + bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos, + core::Widget **minFloat); + bool hasRelationChanged (bool oldTBAlloc, + int oldTBx, int oldTBy, int oldTBw, int oldTBh, + int newTBx, int newTBy, int newTBw, int newTBh, + bool oldFlAlloc, + int oldFlx, int oldFly, int oldFlw, int oldFlh, + int newFlx, int newFly, int newFlw, int newFlh, + Side side, int *floatPos); + + void checkAllocatedFloatCollisions (Side side); + + bool doFloatsExceedCB (Side side); + bool haveExtremesChanged (Side side); + + void drawFloats (SortedFloatsVector *list, core::View *view, + core::Rectangle *area); + core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, + 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 *getOOFAwareWidget (OOFAwareWidget *widget); + TBInfo *getOOFAwareWidgetWhenRegistered (OOFAwareWidget *widget); + inline bool isOOFAwareWidgetRegistered (OOFAwareWidget *widget) + { return getOOFAwareWidgetWhenRegistered (widget) != NULL; } + int getBorder (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + SortedFloatsVector *getFloatsListForOOFAwareWidget (OOFAwareWidget + *textblock, + Side side); + bool hasFloat (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int getFloatHeight (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int getClearPosition (OOFAwareWidget *textblock, Side side); + + void ensureFloatSize (Float *vloat); + + inline static int createSubRefLeftFloat (int index) { return index << 1; } + inline static int createSubRefRightFloat (int index) + { return (index << 1) | 1; } + + inline static bool isSubRefLeftFloat (int ref) + { return ref != -1 && (ref & 1) == 0; } + inline static bool isSubRefRightFloat (int ref) + { return ref != -1 && (ref & 1) == 1; } + + inline static int getFloatIndexFromSubRef (int ref) + { return ref == -1 ? ref : (ref >> 1); } + +public: + OOFFloatsMgr (OOFAwareWidget *container); + ~OOFFloatsMgr (); + + void sizeAllocateStart (OOFAwareWidget *caller, + core::Allocation *allocation); + void sizeAllocateEnd (OOFAwareWidget *caller); + void containerSizeChangedForChildren (); + void draw (core::View *view, core::Rectangle *area); + + void markSizeChange (int ref); + void markExtremesChange (int ref); + core::Widget *getWidgetAtPoint (int x, int y, int level); + + static bool _isWidgetOutOfFlow (core::Widget *widget); + static bool _isWidgetHandledByOOFM (core::Widget *widget); + void addWidgetInFlow (OOFAwareWidget *textblock, OOFAwareWidget *parentBlock, + int externalIndex); + int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generatingBlock, + int externalIndex); + void moveExternalIndices (OOFAwareWidget *generatingBlock, int oldStartIndex, + int diff); + + void tellPosition (core::Widget *widget, int x, int y); + + void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight); + void getExtremes (core::Extremes *cbExtr, + int *oofMinWidth, int *oofMaxWidth); + + int getLeftBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + int getRightBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + bool hasFloatLeft (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + bool hasFloatRight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + int getRightFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + bool affectsLeftBorder (core::Widget *widget); + bool affectsRightBorder (core::Widget *widget); + bool mayAffectBordersAtAll (); + + int getClearPosition (OOFAwareWidget *textblock); + + bool dealingWithSizeOfChild (core::Widget *child); + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + + int getNumWidgets (); + core::Widget *getWidget (int i); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFFLOATSMGR_HH__ diff --git a/dw/oofposabsmgr.cc b/dw/oofposabsmgr.cc new file mode 100644 index 00000000..07daca86 --- /dev/null +++ b/dw/oofposabsmgr.cc @@ -0,0 +1,69 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofposabsmgr.hh" +#include "oofawarewidget.hh" + +namespace dw { + +namespace oof { + +OOFPosAbsMgr::OOFPosAbsMgr (OOFAwareWidget *container) : + OOFPositionedMgr (container) +{ + DBG_OBJ_CREATE ("dw::OOFPosAbsMgr"); +} + +OOFPosAbsMgr::~OOFPosAbsMgr () +{ + DBG_OBJ_DELETE (); +} + +// Comment for all containerBox* implementations: for the toplevel +// widget, assume margin = border = 0 (should perhaps set so when +// widgets are constructed), so that the padding area is actually the +// allocation. + +int OOFPosAbsMgr::containerBoxOffsetX () +{ + return container->getParent () ? + container->boxOffsetX () - container->getStyle()->padding.left : 0; +} + +int OOFPosAbsMgr::containerBoxOffsetY () +{ + return container->getParent () ? + container->boxOffsetY () - container->getStyle()->padding.top : 0; +} + +int OOFPosAbsMgr::containerBoxRestWidth () +{ + return container->getParent () ? + container->boxRestWidth () - container->getStyle()->padding.right : 0; +} + +int OOFPosAbsMgr::containerBoxRestHeight () +{ + return container->getParent () ? + container->boxRestHeight () - container->getStyle()->padding.bottom : 0; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofposabsmgr.hh b/dw/oofposabsmgr.hh new file mode 100644 index 00000000..20c09535 --- /dev/null +++ b/dw/oofposabsmgr.hh @@ -0,0 +1,27 @@ +#ifndef __DW_OOFPOSABSMGR_HH__ +#define __DW_OOFPOSABSMGR_HH__ + +#include "oofpositionedmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPosAbsMgr: public OOFPositionedMgr +{ +protected: + int containerBoxOffsetX (); + int containerBoxOffsetY (); + int containerBoxRestWidth (); + int containerBoxRestHeight (); + +public: + OOFPosAbsMgr (OOFAwareWidget *container); + ~OOFPosAbsMgr (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSABSMGR_HH__ diff --git a/dw/oofposfixedmgr.cc b/dw/oofposfixedmgr.cc new file mode 100644 index 00000000..22cca983 --- /dev/null +++ b/dw/oofposfixedmgr.cc @@ -0,0 +1,60 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofposfixedmgr.hh" + +namespace dw { + +namespace oof { + +OOFPosFixedMgr::OOFPosFixedMgr (OOFAwareWidget *container) : + OOFPositionedMgr (container) +{ + DBG_OBJ_CREATE ("dw::OOFPosFixedMgr"); +} + +OOFPosFixedMgr::~OOFPosFixedMgr () +{ + DBG_OBJ_DELETE (); +} + + +int OOFPosFixedMgr::containerBoxOffsetX () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxOffsetY () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxRestWidth () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxRestHeight () +{ + return 0; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofposfixedmgr.hh b/dw/oofposfixedmgr.hh new file mode 100644 index 00000000..38937878 --- /dev/null +++ b/dw/oofposfixedmgr.hh @@ -0,0 +1,27 @@ +#ifndef __DW_OOFPOSFIXEDMGR_HH__ +#define __DW_OOFPOSFIXEDMGR_HH__ + +#include "oofpositionedmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPosFixedMgr: public OOFPositionedMgr +{ +protected: + int containerBoxOffsetX (); + int containerBoxOffsetY (); + int containerBoxRestWidth (); + int containerBoxRestHeight (); + +public: + OOFPosFixedMgr (OOFAwareWidget *container); + ~OOFPosFixedMgr (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSFIXEDMGR_HH__ diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc new file mode 100644 index 00000000..3efb5002 --- /dev/null +++ b/dw/oofpositionedmgr.cc @@ -0,0 +1,572 @@ +/* + * Dillo Widget + * + * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofpositionedmgr.hh" +#include "oofawarewidget.hh" +#include "../lout/debug.hh" + +using namespace lout::object; +using namespace lout::container::typed; +using namespace lout::misc; +using namespace dw::core; +using namespace dw::core::style; + +namespace dw { + +namespace oof { + +OOFPositionedMgr::OOFPositionedMgr (OOFAwareWidget *container) +{ + DBG_OBJ_CREATE ("dw::OOFPositionedMgr"); + + this->container = (OOFAwareWidget*)container; + children = new Vector<Child> (1, false); + childrenByWidget = new HashTable<TypedPointer<Widget>, Child> (true, true); + + DBG_OBJ_SET_NUM ("children.size", children->size()); +} + +OOFPositionedMgr::~OOFPositionedMgr () +{ + delete children; + delete childrenByWidget; + + DBG_OBJ_DELETE (); +} + +void OOFPositionedMgr::sizeAllocateStart (OOFAwareWidget *caller, + Allocation *allocation) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart", + "%p, (%d, %d, %d * (%d + %d))", + caller, allocation->x, allocation->y, allocation->width, + allocation->ascent, allocation->descent); + if (caller == container) + containerAllocation = *allocation; + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::sizeAllocateEnd (OOFAwareWidget *caller) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller); + + if (caller == container) { + sizeAllocateChildren (); + + bool sizeChanged = doChildrenExceedContainer (); + bool extremesChanged = haveExtremesChanged (); + if (sizeChanged || extremesChanged) + container->oofSizeChanged (extremesChanged); + } + + DBG_OBJ_LEAVE (); +} + + +void OOFPositionedMgr::sizeAllocateChildren () +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "sizeAllocateChildren"); + + int refWidth = container->getAvailWidth (true) - containerBoxDiffWidth (); + int refHeight = container->getAvailHeight (true) - containerBoxDiffHeight (); + + for (int i = 0; i < children->size(); i++) { + Child *child = children->get (i); + + int x, y, width, ascent, descent; + calcPosAndSizeChildOfChild (child, refWidth, refHeight, &x, &y, &width, + &ascent, &descent); + + Allocation childAllocation; + childAllocation.x = containerAllocation.x + x + containerBoxOffsetX (); + childAllocation.y = containerAllocation.y + y + containerBoxOffsetY (); + childAllocation.width = width; + childAllocation.ascent = ascent; + childAllocation.descent = descent; + + child->widget->sizeAllocate (&childAllocation); + } + + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::containerSizeChangedForChildren () +{ + DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren"); + + for (int i = 0; i < children->size(); i++) + children->get(i)->widget->containerSizeChanged (); + + DBG_OBJ_LEAVE (); +} + +bool OOFPositionedMgr::doChildrenExceedContainer () +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "doChildrenExceedContainer"); + + // This method is called to determine whether the *requisition* of + // the container must be recalculated. So, we check the allocations + // of the children against the *requisition* of the container, + // which may (e. g. within tables) differ from the new allocation. + // (Generally, a widget may allocated at a different size.) + Requisition containerReq; + container->sizeRequest (&containerReq); + bool exceeds = false; + + DBG_OBJ_MSG_START (); + + for (int i = 0; i < children->size () && !exceeds; i++) { + Child *child = children->get (i); + Allocation *childAlloc = child->widget->getAllocation (); + DBG_OBJ_MSGF ("resize.oofm", 2, + "Does childAlloc = (%d, %d, %d * %d) exceed container " + "alloc+req = (%d, %d, %d * %d)?", + childAlloc->x, childAlloc->y, childAlloc->width, + childAlloc->ascent + childAlloc->descent, + containerAllocation.x, containerAllocation.y, + containerReq.width, + containerReq.ascent + containerReq.descent); + if (childAlloc->x + childAlloc->width + > containerAllocation.x + containerReq.width || + childAlloc->y + childAlloc->ascent + childAlloc->descent + > containerAllocation.y + + containerReq.ascent + containerReq.descent) { + exceeds = true; + DBG_OBJ_MSG ("resize.oofm", 2, "Yes."); + } else + DBG_OBJ_MSG ("resize.oofm", 2, "No."); + } + + DBG_OBJ_MSG_END (); + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false"); + DBG_OBJ_LEAVE (); + + return exceeds; +} + +bool OOFPositionedMgr::haveExtremesChanged () +{ + // TODO Something to do? + return false; +} + + +void OOFPositionedMgr::draw (View *view, Rectangle *area) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + + for (int i = 0; i < children->size(); i++) { + Widget *childWidget = children->get(i)->widget; + Rectangle childArea; + if (childWidget->intersects (area, &childArea)) + childWidget->draw (view, &childArea); + } + + DBG_OBJ_LEAVE (); +} + + +void OOFPositionedMgr::addWidgetInFlow (OOFAwareWidget *widget, + OOFAwareWidget *parent, + int externalIndex) +{ +} + +int OOFPositionedMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generator, + int externalIndex) +{ + DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d", + widget, generator, externalIndex); + + Child *child = new Child (widget, generator); + children->put (child); + childrenByWidget->put (new TypedPointer<Widget> (widget), child); + + int subRef = children->size() - 1; + DBG_OBJ_SET_NUM ("children.size", children->size()); + DBG_OBJ_ARRSET_PTR ("children", children->size() - 1, widget); + + DBG_OBJ_SET_PTR_O (widget, "<Positioned>.generator", generator); + + DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef); + DBG_OBJ_LEAVE (); + return subRef; +} + +void OOFPositionedMgr::moveExternalIndices (OOFAwareWidget *generator, + int oldStartIndex, int diff) +{ +} + +void OOFPositionedMgr::markSizeChange (int ref) +{ +} + + +void OOFPositionedMgr::markExtremesChange (int ref) +{ +} + +Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y, int level) +{ + for (int i = 0; i < children->size(); i++) { + Widget *childWidget = children->get(i)->widget; + if (childWidget->wasAllocated ()) { + Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y, level + 1); + if (childAtPoint) + return childAtPoint; + } + } + + return NULL; +} + +void OOFPositionedMgr::tellPosition (Widget *widget, int x, int y) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d, %d", + widget, x, y); + + TypedPointer<Widget> key (widget); + Child *child = childrenByWidget->get (&key); + assert (child); + + child->x = x; + child->y = y; + + DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.x", x); + DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.y", y); + + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::getSize (Requisition *containerReq, int *oofWidth, + int *oofHeight) +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); + + *oofWidth = *oofHeight = 0; + + int refWidth = container->getAvailWidth (true); + int refHeight = container->getAvailHeight (true); + + for (int i = 0; i < children->size(); i++) { + Child *child = children->get(i); + int x, y, width, ascent, descent; + calcPosAndSizeChildOfChild (child, refWidth, refHeight, &x, &y, &width, + &ascent, &descent); + *oofWidth = max (*oofWidth, x + width) + containerBoxDiffWidth (); + *oofHeight = + max (*oofHeight, y + ascent + descent) + containerBoxDiffHeight (); + } + + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth, + int *oofMaxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", + containerExtr->minWidth, containerExtr->maxWidth); + + // TODO Something to do? + *oofMinWidth = *oofMaxWidth = 0; + + DBG_OBJ_LEAVE (); +} + + +int OOFPositionedMgr::getLeftBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) +{ + return 0; +} + +int OOFPositionedMgr::getRightBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) +{ + return 0; +} + +bool OOFPositionedMgr::hasFloatLeft (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) +{ + return false; +} + +bool OOFPositionedMgr::hasFloatRight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) +{ + return false; +} + + +int OOFPositionedMgr::getLeftFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, + int lastExtIndex) +{ + return 0; +} + +int OOFPositionedMgr::getRightFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, + int lastExtIndex) +{ + return 0; +} + +int OOFPositionedMgr::getClearPosition (OOFAwareWidget *widget) +{ + return 0; +} + +bool OOFPositionedMgr::affectsLeftBorder (Widget *widget) +{ + return false; +} + +bool OOFPositionedMgr::affectsRightBorder (Widget *widget) +{ + return false; +} + +bool OOFPositionedMgr::mayAffectBordersAtAll () +{ + return false; +} + +bool OOFPositionedMgr::dealingWithSizeOfChild (Widget *child) +{ + return true; +} + +int OOFPositionedMgr::getAvailWidthOfChild (Widget *child, bool forceValue) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, + "OOFPositionedMgr/getAvailWidthOfChild", "%p, %s", + child, forceValue ? "true" : "false"); + + int width; + + if (child->getStyle()->width == style::LENGTH_AUTO && + child->getStyle()->minWidth == style::LENGTH_AUTO && + child->getStyle()->maxWidth == style::LENGTH_AUTO) { + // TODO This should (perhaps?) only used when 'width' is undefined. + // TODO Is "boxDiffWidth()" correct here? + DBG_OBJ_MSG ("resize.oofm", 1, "no specification"); + if (forceValue) { + int availWidth = container->getAvailWidth (true); + width = max (availWidth - containerBoxDiffWidth () + // Regard an undefined value as 0: + - max (getPosLeft (child, availWidth), 0), + - max (getPosRight (child, availWidth), 0), + 0); + } else + width = -1; + } else { + if (forceValue) { + int availWidth = container->getAvailWidth (true); + child->calcFinalWidth (child->getStyle(), + availWidth - containerBoxDiffWidth (), NULL, + 0, true, &width); + } else + width = -1; + } + + if (width != -1) + width = max (width, child->getMinWidth (NULL, forceValue)); + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", width); + DBG_OBJ_LEAVE (); + + return width; +} + +int OOFPositionedMgr::getAvailHeightOfChild (Widget *child, bool forceValue) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, + "OOFPositionedMgr/getAvailHeightOfChild", "%p, %s", + child, forceValue ? "true" : "false"); + + int height; + + if (child->getStyle()->height == style::LENGTH_AUTO && + child->getStyle()->minHeight == style::LENGTH_AUTO && + child->getStyle()->maxHeight == style::LENGTH_AUTO) { + // TODO This should (perhaps?) only used when 'height' is undefined. + // TODO Is "boxDiffHeight()" correct here? + DBG_OBJ_MSG ("resize.oofm", 1, "no specification"); + if (forceValue) { + int availHeight = container->getAvailHeight (true); + height = max (availHeight - containerBoxDiffHeight () + // Regard an undefined value as 0: + - max (getPosTop (child, availHeight), 0), + - max (getPosBottom (child, availHeight), 0), + 0); + } else + height = -1; + } else { + if (forceValue) { + int availHeight = container->getAvailHeight (true); + height = child->calcHeight (child->getStyle()->height, true, + availHeight - containerBoxDiffHeight (), + NULL, true); + } else + height = -1; + } + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", height); + DBG_OBJ_LEAVE (); + + return height; +} + +int OOFPositionedMgr::getPosBorder (style::Length cssValue, int refLength) +{ + if (style::isAbsLength (cssValue)) + return style::absLengthVal (cssValue); + else if (style::isPerLength (cssValue)) + return style::multiplyWithPerLength (refLength, cssValue); + else + // -1 means "undefined": + return -1; +} + +void OOFPositionedMgr::calcPosAndSizeChildOfChild (Child *child, int refWidth, + int refHeight, int *x, + int *y, int *width, + int *ascent, int *descent) +{ + // *x and *y refer to reference area; caller must adjust them. + + DBG_OBJ_ENTER ("resize.oofm", 0, "calcPosAndSizeChildOfChild", + "%p, %d, %d, ...", child, refWidth, refHeight); + + // TODO (i) Consider {min|max}-{width|heigt}. (ii) Height is always + // apportioned to descent (ascent is preserved), which makes sense + // when the children are textblocks. (iii) Consider minimal width + // (getMinWidth)? + + Requisition childRequisition; + child->widget->sizeRequest (&childRequisition); + + bool widthDefined; + if (style::isAbsLength (child->widget->getStyle()->width)) { + DBG_OBJ_MSGF ("resize.oofm", 1, "absolute width: %dpx", + style::absLengthVal (child->widget->getStyle()->width)); + *width = style::absLengthVal (child->widget->getStyle()->width) + + child->widget->boxDiffWidth (); + widthDefined = true; + } else if (style::isPerLength (child->widget->getStyle()->width)) { + DBG_OBJ_MSGF ("resize.oofm", 1, "percentage width: %g%%", + 100 * style::perLengthVal_useThisOnlyForDebugging + (child->widget->getStyle()->width)); + *width = style::multiplyWithPerLength (refWidth, + child->widget->getStyle()->width) + + child->widget->boxDiffWidth (); + widthDefined = true; + } else { + DBG_OBJ_MSG ("resize.oofm", 1, "width not specified"); + *width = childRequisition.width; + widthDefined = false; + } + + int left = getPosLeft (child->widget, refWidth), + right = getPosRight (child->widget, refWidth); + DBG_OBJ_MSGF ("resize.oofm", 1, + "left = %d, right = %d, width = %d (defined: %s)", + left, right, *width, widthDefined ? "true" : "false"); + + if (left == -1 && right == -1) + *x = child->generator->getAllocation()->x + child->x; + else if (left == -1 && right != -1) + *x = refWidth - *width - right; + else if (left != -1 && right == -1) + *x = left; + else { + *x = left; + if (!widthDefined) + *width = refWidth - (left + right); + } + + bool heightDefined; + *ascent = childRequisition.ascent; + *descent = childRequisition.descent; + if (style::isAbsLength (child->widget->getStyle()->height)) { + DBG_OBJ_MSGF ("resize.oofm", 1, "absolute height: %dpx", + style::absLengthVal (child->widget->getStyle()->height)); + int height = style::absLengthVal (child->widget->getStyle()->height) + + child->widget->boxDiffHeight (); + splitHeightPreserveAscent (height, ascent, descent); + heightDefined = true; + } else if (style::isPerLength (child->widget->getStyle()->height)) { + DBG_OBJ_MSGF ("resize.oofm", 1, "percentage height: %g%%", + 100 * style::perLengthVal_useThisOnlyForDebugging + (child->widget->getStyle()->height)); + int height = + style::multiplyWithPerLength (refHeight, + child->widget->getStyle()->height) + + child->widget->boxDiffHeight (); + splitHeightPreserveAscent (height, ascent, descent); + heightDefined = true; + } else { + DBG_OBJ_MSG ("resize.oofm", 1, "height not specified"); + heightDefined = false; + } + + int top = getPosTop (child->widget, refHeight), + bottom = getPosBottom (child->widget, refHeight); + DBG_OBJ_MSGF ("resize.oofm", 1, + "top = %d, bottom = %d, height = %d + %d (defined: %s)", + top, bottom, *ascent, *descent, + heightDefined ? "true" : "false"); + + if (top == -1 && bottom == -1) + *y = child->generator->getAllocation()->y + child->y; + else if (top == -1 && bottom != -1) + *y = refHeight - (*ascent + *descent) - bottom; + else if (top != -1 && bottom == -1) + *y = top; + else { + *y = top; + if (!heightDefined) { + int height = refHeight - (top + bottom); + splitHeightPreserveAscent (height, ascent, descent); + } + } + + DBG_OBJ_MSGF ("resize.oofm", 0, "=> %d, %d, %d * (%d + %d)", + *x, *y, *width, *ascent, *descent); + DBG_OBJ_LEAVE (); +} + +int OOFPositionedMgr::getNumWidgets () +{ + return children->size(); +} + +Widget *OOFPositionedMgr::getWidget (int i) +{ + return children->get(i)->widget; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh new file mode 100644 index 00000000..ad469b8f --- /dev/null +++ b/dw/oofpositionedmgr.hh @@ -0,0 +1,120 @@ +#ifndef __DW_OOFPOSITIONEDMGR_HH__ +#define __DW_OOFPOSITIONEDMGR_HH__ + +#include "outofflowmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPositionedMgr: public OutOfFlowMgr +{ +protected: + class Child: public lout::object::Object + { + public: + core::Widget *widget, *generator; + int x, y; + + inline Child (core::Widget *widget, core::Widget *generator) + { this->widget = widget; this->generator = generator; x = y = 0; } + }; + + virtual int containerBoxOffsetX () = 0; + virtual int containerBoxOffsetY () = 0; + virtual int containerBoxRestWidth () = 0; + virtual int containerBoxRestHeight () = 0; + + inline int containerBoxDiffWidth () + { return containerBoxOffsetX () + containerBoxRestWidth (); } + inline int containerBoxDiffHeight () + { return containerBoxOffsetY () + containerBoxRestHeight (); } + + OOFAwareWidget *container; + core::Allocation containerAllocation; + + lout::container::typed::Vector<Child> *children; + lout::container::typed::HashTable<lout::object::TypedPointer + <dw::core::Widget>, + Child> *childrenByWidget; + + bool doChildrenExceedContainer (); + bool haveExtremesChanged (); + void sizeAllocateChildren (); + + inline int getPosLeft (core::Widget *child, int availWidth) + { return getPosBorder (child->getStyle()->left, availWidth); } + inline int getPosRight (core::Widget *child, int availWidth) + { return getPosBorder (child->getStyle()->right, availWidth); } + inline int getPosTop (core::Widget *child, int availHeight) + { return getPosBorder (child->getStyle()->top, availHeight); } + inline int getPosBottom (core::Widget *child, int availHeight) + { return getPosBorder (child->getStyle()->bottom, availHeight); } + + int getPosBorder (core::style::Length cssValue, int refLength); + void calcPosAndSizeChildOfChild (Child *child, int refWidth, int refHeight, + int *x, int *y, int *width, int *ascent, + int *descent); + +public: + OOFPositionedMgr (OOFAwareWidget *container); + ~OOFPositionedMgr (); + + void sizeAllocateStart (OOFAwareWidget *caller, + core::Allocation *allocation); + void sizeAllocateEnd (OOFAwareWidget *caller); + void containerSizeChangedForChildren (); + void draw (core::View *view, core::Rectangle *area); + + void markSizeChange (int ref); + void markExtremesChange (int ref); + core::Widget *getWidgetAtPoint (int x, int y, int level); + + void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent, + int externalIndex); + int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator, + int externalIndex); + void moveExternalIndices (OOFAwareWidget *generator, int oldStartIndex, + int diff); + + void tellPosition (core::Widget *widget, int x, int y); + + void getSize (core::Requisition *containerReq, int *oofWidth, + int *oofHeight); + void getExtremes (core::Extremes *containerExtr, + int *oofMinWidth, int *oofMaxWidth); + + int getLeftBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + int getRightBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + bool hasFloatLeft (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + bool hasFloatRight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + int getRightFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + int getClearPosition (OOFAwareWidget *widget); + + bool affectsLeftBorder (core::Widget *widget); + bool affectsRightBorder (core::Widget *widget); + bool mayAffectBordersAtAll (); + + bool dealingWithSizeOfChild (core::Widget *child); + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + + int getNumWidgets (); + core::Widget *getWidget (int i); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSITIONEDMGR_HH__ diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc index d9c19cc5..405c5e62 100644 --- a/dw/outofflowmgr.cc +++ b/dw/outofflowmgr.cc @@ -19,2364 +19,22 @@ #include "outofflowmgr.hh" -#include "textblock.hh" +#include "oofawarewidget.hh" #include "../lout/debug.hh" -using namespace lout::object; -using namespace lout::container::typed; -using namespace lout::misc; -using namespace dw::core; -using namespace dw::core::style; namespace dw { -OutOfFlowMgr::WidgetInfo::WidgetInfo (OutOfFlowMgr *oofm, Widget *widget) -{ - this->oofm = oofm; - this->widget = widget; - wasAllocated = false; - xCB = yCB = width = height = -1; -} - -void OutOfFlowMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB, - int width, int height) -{ - DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d", - wasAllocated ? "true" : "false", xCB, yCB, width, height); - - this->wasAllocated = wasAllocated; - this->xCB = xCB; - this->yCB = yCB; - this->width = width; - this->height = height; - - DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB); - DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB); - DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width); - DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height); - - DBG_OBJ_LEAVE_O (widget); -} - -// ---------------------------------------------------------------------- - -OutOfFlowMgr::Float::Float (OutOfFlowMgr *oofm, Widget *widget, - Textblock *generatingBlock, int externalIndex) : - WidgetInfo (oofm, widget) -{ - this->generatingBlock = generatingBlock; - this->externalIndex = externalIndex; - - yReq = yReal = size.width = size.ascent = size.descent = 0; - dirty = sizeChangedSinceLastAllocation = true; - indexGBList = indexCBList = -1; - - // Sometimes a float with widget = NULL is created as a key; this - // is not interesting for RTFL. - if (widget) { - DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock); - DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex); - DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq); - DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal); - DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width); - DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent); - DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent); - DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty); - DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation", - sizeChangedSinceLastAllocation); - } -} - -void OutOfFlowMgr::Float::updateAllocation () -{ - DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); - - update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), - getNewHeight ()); +namespace oof { - DBG_OBJ_LEAVE_O (getWidget ()); -} - -void OutOfFlowMgr::Float::intoStringBuffer(StringBuffer *sb) +OutOfFlowMgr::OutOfFlowMgr () { - 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::AbsolutelyPositioned::AbsolutelyPositioned (OutOfFlowMgr *oofm, - Widget *widget, - Textblock - *generatingBlock, - int externalIndex) -{ - this->widget = widget; - dirty = true; -} - -OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock) -{ - DBG_OBJ_CREATE ("dw::OutOfFlowMgr"); - - this->containingBlock = containingBlock; - - leftFloatsCB = new SortedFloatsVector (this, LEFT, CB); - rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB); - - DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); - DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); - - leftFloatsAll = new Vector<Float> (1, true); - rightFloatsAll = new Vector<Float> (1, true); - - DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); - DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); - - floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false); - - tbInfos = new Vector<TBInfo> (1, false); - tbInfosByTextblock = - new HashTable <TypedPointer <Textblock>, TBInfo> (true, true); - - leftFloatsMark = rightFloatsMark = 0; - lastLeftTBIndex = lastRightTBIndex = 0; - - absolutelyPositioned = new Vector<AbsolutelyPositioned> (1, true); - - containingBlockWasAllocated = containingBlock->wasAllocated (); - containingBlockAllocation = *(containingBlock->getAllocation()); - - addWidgetInFlow (containingBlock, NULL, 0); } OutOfFlowMgr::~OutOfFlowMgr () { - //printf ("OutOfFlowMgr::~OutOfFlowMgr\n"); - - delete leftFloatsCB; - delete rightFloatsCB; - - // Order is important: tbInfosByTextblock is owner of the instances - // of TBInfo.tbInfosByTextblock - delete tbInfos; - delete tbInfosByTextblock; - - delete floatsByWidget; - - // Order is important, since the instances of Float are owned by - // leftFloatsAll and rightFloatsAll, so these should be deleted - // last. - delete leftFloatsAll; - delete rightFloatsAll; - - delete absolutelyPositioned; - - DBG_OBJ_DELETE (); } -void OutOfFlowMgr::sizeAllocateStart (Textblock *caller, Allocation *allocation) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart", - "%p, (%d, %d, %d * (%d + %d))", - caller, allocation->x, allocation->y, allocation->width, - allocation->ascent, allocation->descent); - - getTextblock(caller)->allocation = *allocation; - getTextblock(caller)->wasAllocated = true; - - if (caller == containingBlock) { - // In the size allocation process, the *first* OOFM method - // called is sizeAllocateStart, with the containing block as an - // argument. So this is the correct point to initialize size - // allocation. - - containingBlockAllocation = *allocation; - containingBlockWasAllocated = true; - - // Move floats from GB lists to the one CB list. - moveFromGBToCB (LEFT); - moveFromGBToCB (RIGHT); - - // These attributes are used to keep track which floats have - // been allocated (referring to leftFloatsCB and rightFloatsCB). - lastAllocatedLeftFloat = lastAllocatedRightFloat = -1; - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller); - - // (Later, absolutely positioned blocks have to be allocated.) - - if (caller != containingBlock) { - // Allocate all floats "before" this textblock. - sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1)); - sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1)); - } - - if (caller == containingBlock) { - // In the size allocation process, the *last* OOFM method called - // is sizeAllocateEnd, with the containing block as an - // argument. So this is the correct point to finish size - // allocation. - - // Allocate all remaining floats. - sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1); - sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1); - - // Check changes of both textblocks and floats allocation. (All - // is checked by hasRelationChanged (...).) - for (lout::container::typed::Iterator<TypedPointer <Textblock> > it = - tbInfosByTextblock->iterator (); - it.hasNext (); ) { - TypedPointer <Textblock> *key = it.getNext (); - TBInfo *tbInfo = tbInfosByTextblock->get (key); - Textblock *tb = key->getTypedValue(); - - int minFloatPos; - Widget *minFloat; - if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat)) - tb->borderChanged (minFloatPos, minFloat); - } - - checkAllocatedFloatCollisions (LEFT); - checkAllocatedFloatCollisions (RIGHT); - - // Store some information for later use. - for (lout::container::typed::Iterator<TypedPointer <Textblock> > it = - tbInfosByTextblock->iterator (); - it.hasNext (); ) { - TypedPointer <Textblock> *key = it.getNext (); - TBInfo *tbInfo = tbInfosByTextblock->get (key); - Textblock *tb = key->getTypedValue(); - - tbInfo->updateAllocation (); - tbInfo->lineBreakWidth = tb->getLineBreakWidth (); - } - - // There are cases where some allocated floats (TODO: later also - // absolutely positioned elements?) exceed the CB allocation. - bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT); - - // Similar for extremes. (TODO: here also absolutely positioned - // elements?) - bool extremesChanged = - haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT); - - for (int i = 0; i < leftFloatsCB->size(); i++) - leftFloatsCB->get(i)->updateAllocation (); - - for (int i = 0; i < rightFloatsCB->size(); i++) - rightFloatsCB->get(i)->updateAllocation (); - - if (sizeChanged || extremesChanged) - containingBlock->oofSizeChanged (extremesChanged); - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::containerSizeChangedForChildren () -{ - DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren"); - - DBG_OBJ_MSGF ("resize", 0, - "%d left floats, %d right floats %d abspos", - leftFloatsAll->size (), rightFloatsAll->size (), - absolutelyPositioned->size()); - - for (int i = 0; i < leftFloatsAll->size (); i++) - leftFloatsAll->get(i)->getWidget()->containerSizeChanged (); - for (int i = 0; i < rightFloatsAll->size (); i++) - rightFloatsAll->get(i)->getWidget()->containerSizeChanged (); - for (int i = 0; i < absolutelyPositioned->size(); i++) - absolutelyPositioned->get(i)->widget->containerSizeChanged (); - - DBG_OBJ_LEAVE (); -} - -bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos, - Widget **minFloat) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", - "<i>widget:</i> %p, ...", tbInfo->getWidget ()); - - int leftMinPos, rightMinPos; - Widget *leftMinFloat, *rightMinFloat; - bool c1 = - hasRelationChanged (tbInfo, LEFT, &leftMinPos, &leftMinFloat); - bool c2 = - hasRelationChanged (tbInfo, RIGHT, &rightMinPos, &rightMinFloat); - if (c1 || c2) { - if (!c1) { - *minFloatPos = rightMinPos; - *minFloat = rightMinFloat; - } else if (!c2) { - *minFloatPos = leftMinPos; - *minFloat = leftMinFloat; - } else { - if (leftMinPos < rightMinPos) { - *minFloatPos = leftMinPos; - *minFloat = leftMinFloat; - } else{ - *minFloatPos = rightMinPos; - *minFloat = rightMinFloat; - } - } - } - - if (c1 || c2) - DBG_OBJ_MSGF ("resize.oofm", 1, - "has changed: minFloatPos = %d, minFloat = %p", - *minFloatPos, *minFloat); - else - DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); - - DBG_OBJ_LEAVE (); - return c1 || c2; -} - -bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, Side side, - int *minFloatPos, Widget **minFloat) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", - "<i>widget:</i> %p, %s, ...", - tbInfo->getWidget (), side == LEFT ? "LEFT" : "RIGHT"); - - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - bool changed = false; - - for (int i = 0; i < list->size(); i++) { - // TODO binary search? - Float *vloat = list->get(i); - int floatPos; - - if (tbInfo->getTextblock () == vloat->generatingBlock) - DBG_OBJ_MSGF ("resize.oofm", 1, - "not checking (generating!) textblock %p against float " - "%p", tbInfo->getWidget (), vloat->getWidget ()); - else { - Allocation *gba = getAllocation (vloat->generatingBlock); - - int newFlx = - calcFloatX (vloat, side, - gba->x - containingBlockAllocation.x, gba->width, - vloat->generatingBlock->getLineBreakWidth ()); - int newFly = vloat->generatingBlock->getAllocation()->y - - containingBlockAllocation.y + vloat->yReal; - - DBG_OBJ_MSGF ("resize.oofm", 1, - "checking textblock %p against float %p", - tbInfo->getWidget (), vloat->getWidget ()); - DBG_OBJ_MSG_START (); - - if (hasRelationChanged (tbInfo->wasThenAllocated (), - tbInfo->getOldXCB (), tbInfo->getOldYCB (), - tbInfo->getNewWidth (), - tbInfo->getNewHeight (), - tbInfo->getNewXCB (), tbInfo->getNewYCB (), - tbInfo->getNewWidth (), - tbInfo->getNewHeight (), - vloat->wasThenAllocated (), - // When not allocated before, these values - // are undefined, but this does not matter, - // since they are neither used. - vloat->getOldXCB (), vloat->getOldYCB (), - vloat->getOldWidth (), vloat->getOldHeight (), - newFlx, newFly, vloat->size.width, - vloat->size.ascent + vloat->size.descent, - side, &floatPos)) { - if (!changed || floatPos < *minFloatPos) { - *minFloatPos = floatPos; - *minFloat = vloat->getWidget (); - } - changed = true; - } else - DBG_OBJ_MSG ("resize.oofm", 0, "No."); - - DBG_OBJ_MSG_END (); - } - - // All floarts are searched, to find the minimum. TODO: Are - // floats sorted, so this can be shortened? (The first is the - // minimum?) - } - - if (changed) - DBG_OBJ_MSGF ("resize.oofm", 1, - "has changed: minFloatPos = %d, minFloat = %p", - *minFloatPos, *minFloat); - else - DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); - - DBG_OBJ_LEAVE (); - return changed; -} - -/** - * \brief ... - * - * All coordinates are given relative to the CB. *floatPos is relative - * to the TB, and may be negative. - */ -bool OutOfFlowMgr::hasRelationChanged (bool oldTBAlloc, - int oldTBx, int oldTBy, int oldTBw, - int oldTBh, int newTBx, int newTBy, - int newTBw, int newTBh, - bool oldFlAlloc, - int oldFlx, int oldFly, int oldFlw, - int oldFlh, int newFlx, int newFly, - int newFlw, int newFlh, - Side side, int *floatPos) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "hasRelationChanged", - "<i>see below</i>, %s, ...", side == LEFT ? "LEFT" : "RIGHT"); - - if (oldTBAlloc) - DBG_OBJ_MSGF ("resize.oofm", 1, "old TB: %d, %d; %d * %d", - oldTBx, oldTBy, oldTBw, oldTBh); - else - DBG_OBJ_MSG ("resize.oofm", 1, "old TB: undefined"); - DBG_OBJ_MSGF ("resize.oofm", 1, "new TB: %d, %d; %d * %d", - newTBx, newTBy, newTBw, newTBh); - - if (oldFlAlloc) - DBG_OBJ_MSGF ("resize.oofm", 1, "old Fl: %d, %d; %d * %d", - oldFlx, oldFly, oldFlw, oldFlh); - else - DBG_OBJ_MSG ("resize.oofm", 1, "old Fl: undefined"); - DBG_OBJ_MSGF ("resize.oofm", 1, "new Fl: %d, %d; %d * %d", - newFlx, newFly, newFlw, newFlh); - - bool result; - if (oldTBAlloc && oldFlAlloc) { - bool oldCov = oldFly + oldFlh > oldTBy && oldFly < oldTBy + oldTBh; - bool newCov = newFly + newFlh > newTBy && newFly < newTBy + newTBh; - - DBG_OBJ_MSGF ("resize.oofm", 1, "covered? then: %s, now: %s.", - oldCov ? "yes" : "no", newCov ? "yes" : "no"); - DBG_OBJ_MSG_START (); - - if (oldCov && newCov) { - int yOld = oldFly - oldTBy, yNew = newFly - newTBy; - if (yOld == yNew) { - DBG_OBJ_MSGF ("resize.oofm", 2, - "old (%d - %d) and new (%d - %d) position equal: %d", - oldFly, oldTBy, newFly, newTBy, yOld); - - // Float position has not changed, but perhaps the amout - // how far the float reaches into the TB. (TODO: - // Generally, not only here, it could be tested whether - // the float reaches into the TB at all.) - int wOld, wNew; - if (side == LEFT) { - wOld = oldFlx + oldFlw - oldTBx; - wNew = newFlx + newFlw - newTBx; - } else { - wOld = oldTBx + oldTBw - oldFlx; - wNew = newTBx + newTBw - newFlx; - } - - DBG_OBJ_MSGF ("resize.oofm", 2, "wOld = %d, wNew = %d\n", - wOld, wNew); - - if (wOld == wNew) { - if (oldFlh == newFlh) - result = false; - else { - // Only heights of floats changed. Relevant only - // from bottoms of float. - *floatPos = min (yOld + oldFlh, yNew + newFlh); - result = true; - } - } else { - *floatPos = yOld; - result = true; - } - } else { - DBG_OBJ_MSGF ("resize.oofm", 2, - "old (%d - %d = %d) and new (%d - %d = %d) position " - "different", - oldFly, oldTBy, yOld, newFly, newTBy, yNew); - *floatPos = min (yOld, yNew); - result = true; - } - } else if (oldCov) { - *floatPos = oldFly - oldTBy; - result = true; - DBG_OBJ_MSGF ("resize.oofm", 2, - "returning old position: %d - %d = %d", oldFly, oldTBy, - *floatPos); - } else if (newCov) { - *floatPos = newFly - newTBy; - result = true; - DBG_OBJ_MSGF ("resize.oofm", 2, - "returning new position: %d - %d = %d", newFly, newTBy, - *floatPos); - } else - result = false; - - DBG_OBJ_MSG_END (); - } else { - // Not allocated before: ignore all old values, only check whether - // TB is covered by Float. - if (newFly + newFlh > newTBy && newFly < newTBy + newTBh) { - *floatPos = newFly - newTBy; - result = true; - } else - result = false; - } - - if (result) - DBG_OBJ_MSGF ("resize.oofm", 1, "has changed: floatPos = %d", - *floatPos); - else - DBG_OBJ_MSG ("resize.oofm", 1, "has not changed"); - - DBG_OBJ_LEAVE (); - - return result; -} - -void OutOfFlowMgr::checkAllocatedFloatCollisions (Side side) -{ - // In some cases, the collision detection in tellPosition() is - // based on the wrong allocations. Here (just after all Floats have - // been allocated), we correct this. - - // TODO In some cases this approach is rather slow, causing a too - // long queueResize() cascade. - - DBG_OBJ_ENTER ("resize.oofm", 0, "checkAllocatedFloatCollisions", "%s", - side == LEFT ? "LEFT" : "RIGHT"); - - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - SortedFloatsVector *oppList = side == LEFT ? rightFloatsCB : leftFloatsCB; - - // While iterating through the list of floats to be checked, we - // iterate equally through the list of the opposite floats, using - // this index: - int oppIndex = 0; - - for (int index = 0; index < list->size (); index++) { - Float *vloat = list->get(index); - bool needsChange = false; - int yRealNew = INT_MAX; - - // Same side. - if (index >= 1) { - Float *other = list->get(index - 1); - DBG_OBJ_MSGF ("resize.oofm", 1, - "same side: checking %p (#%d, GB: %p) against " - "%p (#%d, GB: %p)", - vloat->getWidget (), index, vloat->generatingBlock, - other->getWidget (), index - 1, other->generatingBlock); - - if (vloat->generatingBlock != other->generatingBlock) { - int yRealNewSame; - if (collidesV (vloat, other, CB, &yRealNewSame)) { - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> collides, new yReal = %d (old: %d)", - yRealNewSame, vloat->yReal); - if (vloat->yReal != yRealNewSame) { - needsChange = true; - yRealNew = min (yRealNew, yRealNewSame); - } - } else - DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision"); - } - } - - if (oppList->size () > 0) { - // Other side. Iterate to next float on the other side, - // before this float. - while (oppIndex + 1 < oppList->size () && - oppList->get(oppIndex + 1)->sideSpanningIndex - < vloat->sideSpanningIndex) - oppIndex++; - - if (oppList->get(oppIndex)->sideSpanningIndex - < vloat->sideSpanningIndex) { - int oppIndexTmp = oppIndex, yRealNewOpp; - - // Aproach is similar to tellPosition(); see comments - // there. Again, loop as long as the vertical dimensions test - // is positive (and, of course, there are floats), ... - for (bool foundColl = false; - !foundColl && oppIndexTmp >= 0 && - collidesV (vloat, oppList->get (oppIndexTmp), CB, - &yRealNewOpp); - oppIndexTmp--) { - DBG_OBJ_MSGF ("resize.oofm", 1, - "opposite side (after collision (v) test): " - "checking %p (#%d/%d, GB: %p) against " - "%p (#%d/%d, GB: %p)", - vloat->getWidget (), index, - vloat->sideSpanningIndex, - vloat->generatingBlock, - oppList->get(oppIndexTmp)->getWidget (), - oppList->get(oppIndexTmp)->getIndex (CB), - oppList->get(oppIndexTmp)->sideSpanningIndex, - oppList->get(oppIndexTmp)->generatingBlock); - - // ... but stop the loop as soon as the horizontal dimensions - // test is positive. - if (collidesH (vloat, oppList->get (oppIndexTmp), CB)) { - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> collides (h), new yReal = %d (old: %d)", - yRealNewOpp, vloat->yReal); - foundColl = true; - if (vloat->yReal != yRealNewOpp) { - needsChange = true; - yRealNew = min (yRealNew, yRealNewOpp); - } - } else - DBG_OBJ_MSG ("resize.oofm", 1, "=> no collision (h)"); - } - } - } - - if (needsChange) - vloat->generatingBlock->borderChanged (min (vloat->yReal, yRealNew), - vloat->getWidget ()); - } - - DBG_OBJ_LEAVE (); -} - -bool OutOfFlowMgr::doFloatsExceedCB (Side side) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "doFloatsExceedCB", "%s", - side == LEFT ? "LEFT" : "RIGHT"); - - // This method is called to determine whether the *requisition* of - // the CB must be recalculated. So, we check the float allocations - // against the *requisition* of the CB, which may (e. g. within - // tables) differ from the new allocation. (Generally, a widget may - // allocated at a different size.) - core::Requisition cbReq; - containingBlock->sizeRequest (&cbReq); - - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - bool exceeds = false; - - DBG_OBJ_MSG_START (); - - for (int i = 0; i < list->size () && !exceeds; i++) { - Float *vloat = list->get (i); - if (vloat->getWidget()->wasAllocated ()) { - Allocation *fla = vloat->getWidget()->getAllocation (); - DBG_OBJ_MSGF ("resize.oofm", 2, - "Does FlA = (%d, %d, %d * %d) exceed CBA = " - "(%d, %d, %d * %d)?", - fla->x, fla->y, fla->width, fla->ascent + fla->descent, - containingBlockAllocation.x, containingBlockAllocation.y, - cbReq.width, cbReq.ascent + cbReq.descent); - if (fla->x + fla->width > containingBlockAllocation.x + cbReq.width || - fla->y + fla->ascent + fla->descent - > containingBlockAllocation.y + cbReq.ascent + cbReq.descent) { - exceeds = true; - DBG_OBJ_MSG ("resize.oofm", 2, "Yes."); - } else - DBG_OBJ_MSG ("resize.oofm", 2, "No."); - } - } - - DBG_OBJ_MSG_END (); - - DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", exceeds ? "true" : "false"); - DBG_OBJ_LEAVE (); - - return exceeds; -} - -bool OutOfFlowMgr::haveExtremesChanged (Side side) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "haveExtremesChanged", "%s", - side == LEFT ? "LEFT" : "RIGHT"); - - // This is quite different from doFloatsExceedCB, since there is no - // counterpart to getExtremes, as sizeAllocate is a counterpart to - // sizeRequest. So we have to determine whether the allocation has - // changed the extremes, which is done by examining the part of the - // allocation which is part of the extremes calculation (see - // getFloatsExtremes). Changes of the extremes are handled by the - // normal queueResize mechanism. - - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - bool changed = false; - - for (int i = 0; i < list->size () && !changed; i++) { - Float *vloat = list->get (i); - // When the GB is the CB, an allocation change does not play a - // role here. - if (vloat->generatingBlock != containingBlock) { - if (!vloat->wasThenAllocated () && vloat->isNowAllocated ()) - changed = true; - else { - // This method is called within sizeAllocateEnd, where - // containinBlock->getAllocation() (old value) and - // containinBlockAllocation (new value) are different. - - Allocation *oldCBA = containingBlock->getAllocation (); - Allocation *newCBA = &containingBlockAllocation; - - // Compare also to getFloatsExtremes. The box difference - // of the GB (from style) has not changed in this context, - // so it is ignored. - - int oldDiffLeft = vloat->getOldXCB (); - int newDiffLeft = vloat->getNewXCB (); - int oldDiffRight = - oldCBA->width - (vloat->getOldXCB () + vloat->getOldWidth ()); - int newDiffRight = - newCBA->width - (vloat->getNewXCB () + vloat->getNewWidth ()); - - if (// regarding minimum - (side == LEFT && oldDiffLeft != newDiffLeft) || - (side == RIGHT && oldDiffRight != newDiffRight) || - // regarding maximum - oldDiffLeft + oldDiffRight != newDiffLeft + newDiffRight) - changed = true; - } - } - } - - DBG_OBJ_MSGF ("resize.oofm", 1, "=> %s", changed ? "true" : "false"); - DBG_OBJ_LEAVE (); - - return changed; -} - -void OutOfFlowMgr::moveFromGBToCB (Side side) -{ - DBG_OBJ_ENTER ("oofm.resize", 0, "moveFromGBToCB", "%s", - side == LEFT ? "LEFT" : "RIGHT"); - - SortedFloatsVector *dest = side == LEFT ? leftFloatsCB : rightFloatsCB; - int *floatsMark = side == LEFT ? &leftFloatsMark : &rightFloatsMark; - - for (int mark = 0; mark <= *floatsMark; mark++) - for (lout::container::typed::Iterator<TBInfo> it = tbInfos->iterator (); - it.hasNext (); ) { - TBInfo *tbInfo = it.getNext (); - SortedFloatsVector *src = - side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; - for (int i = 0; i < src->size (); i++) { - Float *vloat = src->get (i); - // "vloat->indexCBList == -1": prevent copying the vloat twice. - if (vloat->indexCBList == -1 && vloat->mark == mark) { - dest->put (vloat); - DBG_OBJ_MSGF ("oofm.resize", 1, - "moving float %p (mark %d) to CB list\n", - vloat->getWidget (), vloat->mark); - DBG_OBJ_SET_NUM (side == LEFT ? - "leftFloatsCB.size" : "rightFloatsCB.size", - dest->size()); - DBG_OBJ_ARRATTRSET_PTR (side == LEFT ? - "leftFloatsCB" : "rightFloatsCB", - dest->size() - 1, "widget", - vloat->getWidget ()); - - } - } - } - - *floatsMark = 0; - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat) -{ - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - int *lastAllocatedFloat = - side == LEFT ? &lastAllocatedLeftFloat : &lastAllocatedRightFloat; - - DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateFloats", - "%s, [%d ->] %d [size = %d]", - side == LEFT ? "LEFT" : "RIGHT", *lastAllocatedFloat, - newLastAllocatedFloat, list->size ()); - - Allocation *cba = &containingBlockAllocation; - - for (int i = *lastAllocatedFloat + 1; i <= newLastAllocatedFloat; i++) { - Float *vloat = list->get(i); - ensureFloatSize (vloat); - - Allocation *gba = getAllocation (vloat->generatingBlock); - int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth(); - - Allocation childAllocation; - childAllocation.x = cba->x + - calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth); - childAllocation.y = gba->y + vloat->yReal; - childAllocation.width = vloat->size.width; - childAllocation.ascent = vloat->size.ascent; - childAllocation.descent = vloat->size.descent; - - vloat->getWidget()->sizeAllocate (&childAllocation); - } - - *lastAllocatedFloat = newLastAllocatedFloat; - - DBG_OBJ_LEAVE (); -} - - -/** - * \brief ... - * - * gbX is given relative to the CB, as is the return value. - */ -int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, - int gbLineBreakWidth) -{ - DBG_OBJ_ENTER ("resize.common", 0, "calcFloatX", "%p, %s, %d, %d, %d", - vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX, - gbWidth, gbLineBreakWidth); - int x; - - switch (side) { - case LEFT: - // Left floats are always aligned on the left side of the - // generator (content, not allocation) ... - x = gbX + vloat->generatingBlock->getStyle()->boxOffsetX(); - DBG_OBJ_MSGF ("resize.oofm", 1, "left: x = %d + %d = %d", - gbX, vloat->generatingBlock->getStyle()->boxOffsetX(), x); - // ... but when the float exceeds the line break width of the - // container, it is corrected (but not left of the container). - // This way, we save space and, especially within tables, avoid - // some problems. - if (wasAllocated (containingBlock) && - x + vloat->size.width > containingBlock->getLineBreakWidth ()) { - x = max (0, containingBlock->getLineBreakWidth () - vloat->size.width); - DBG_OBJ_MSGF ("resize.common", 1, - "corrected to: max (0, %d - %d) = %d", - containingBlock->getLineBreakWidth (), vloat->size.width, - x); - } - break; - - case RIGHT: - // Similar for right floats, but in this case, floats are - // shifted to the right when they are too big (instead of - // shifting the generator to the right). - - // Notice that not the actual width, but the line break width is - // used. (This changed for GROWS, where the width of a textblock - // is often smaller that the line break.) - - x = max (gbX + gbLineBreakWidth - vloat->size.width - - vloat->generatingBlock->getStyle()->boxRestWidth(), - // Do not exceed CB allocation: - 0); - DBG_OBJ_MSGF ("resize.common", 1, "x = max (%d + %d - %d - %d, 0) = %d", - gbX, gbLineBreakWidth, vloat->size.width, - vloat->generatingBlock->getStyle()->boxRestWidth(), x); - break; - - default: - assertNotReached (); - x = 0; - break; - } - - DBG_OBJ_LEAVE (); - return x; -} - - -void OutOfFlowMgr::draw (View *view, Rectangle *area) -{ - drawFloats (leftFloatsCB, view, area); - drawFloats (rightFloatsCB, view, area); - drawAbsolutelyPositioned (view, area); -} - -void OutOfFlowMgr::drawFloats (SortedFloatsVector *list, View *view, - Rectangle *area) -{ - // This could be improved, since the list is sorted: search the - // first float fitting into the area, and iterate until one is - // found below the area. - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - Rectangle childArea; - if (vloat->getWidget()->intersects (area, &childArea)) - vloat->getWidget()->draw (view, &childArea); - } -} - -void OutOfFlowMgr::drawAbsolutelyPositioned (View *view, Rectangle *area) -{ - for (int i = 0; i < absolutelyPositioned->size(); i++) { - AbsolutelyPositioned *abspos = absolutelyPositioned->get(i); - Rectangle childArea; - if (abspos->widget->intersects (area, &childArea)) - abspos->widget->draw (view, &childArea); - } -} - -/** - * This method consideres also the attributes not yet considered by - * dillo, so that the containing block is determined correctly, which - * leads sometimes to a cleaner rendering. - */ -bool OutOfFlowMgr::isWidgetOutOfFlow (Widget *widget) -{ - // This is only half-baked, will perhaps be reactivated: - // - //return - // widget->getStyle()->vloat != FLOAT_NONE || - // widget->getStyle()->position == POSITION_ABSOLUTE || - // widget->getStyle()->position == POSITION_FIXED; - - return isWidgetHandledByOOFM (widget); -} - -bool OutOfFlowMgr::isWidgetHandledByOOFM (Widget *widget) -{ - // May be extended for fixed (and relative?) positions. - return isWidgetFloat (widget); - // TODO temporary disabled: || isWidgetAbsolutelyPositioned (widget); -} - -void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock, - Textblock *parentBlock, int externalIndex) -{ - //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n", - // containingBlock, textblock, parentBlock, externalIndex); - - TBInfo *tbInfo = - new TBInfo (this, textblock, - parentBlock ? getTextblock (parentBlock) : NULL, - externalIndex); - tbInfo->index = tbInfos->size(); - - tbInfos->put (tbInfo); - tbInfosByTextblock->put (new TypedPointer<Textblock> (textblock), tbInfo); -} - -void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock, - int externalIndex) -{ - DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d", - widget, generatingBlock, externalIndex); - - if (isWidgetFloat (widget)) { - TBInfo *tbInfo = getTextblock (generatingBlock); - - Float *vloat = new Float (this, widget, generatingBlock, externalIndex); - - // Note: Putting the float first in the GB list, and then, - // possibly into the CB list (in that order) will trigger - // setting Float::inCBList to the right value. - - switch (widget->getStyle()->vloat) { - case FLOAT_LEFT: - leftFloatsAll->put (vloat); - DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); - DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1, - "widget", vloat->getWidget ()); - - widget->parentRef = createRefLeftFloat (leftFloatsAll->size() - 1); - tbInfo->leftFloatsGB->put (vloat); - - if (wasAllocated (generatingBlock)) { - leftFloatsCB->put (vloat); - DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); - DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1, - "widget", vloat->getWidget ()); - } else { - if (tbInfo->index < lastLeftTBIndex) - leftFloatsMark++; - - vloat->mark = leftFloatsMark; - //printf ("[%p] adding left float %p (%s %p, mark %d) to GB list " - // "(index %d, last = %d)\n", - // containingBlock, vloat, widget->getClassName(), widget, - // vloat->mark, tbInfo->index, lastLeftTBIndex); - - lastLeftTBIndex = tbInfo->index; - } - break; - - case FLOAT_RIGHT: - rightFloatsAll->put (vloat); - DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); - DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1, - "widget", vloat->getWidget ()); - - widget->parentRef = createRefRightFloat (rightFloatsAll->size() - 1); - tbInfo->rightFloatsGB->put (vloat); - - if (wasAllocated (generatingBlock)) { - rightFloatsCB->put (vloat); - DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); - DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1, - "widget", vloat->getWidget ()); - } else { - if (tbInfo->index < lastRightTBIndex) - rightFloatsMark++; - - vloat->mark = rightFloatsMark; - //printf ("[%p] adding right float %p (%s %p, mark %d) to GB list " - // "(index %d, last = %d)\n", - // containingBlock, vloat, widget->getClassName(), widget, - // vloat->mark, tbInfo->index, lastRightTBIndex); - - lastRightTBIndex = tbInfo->index; - } - - break; - - default: - assertNotReached(); - } - - // "sideSpanningIndex" is only compared, so this simple - // assignment is sufficient; differenciation between GB and CB - // lists is not neccessary. TODO: Can this also be applied to - // "index", to simplify the current code? Check: where is - // "index" used. - vloat->sideSpanningIndex = - leftFloatsAll->size() + rightFloatsAll->size() - 1; - - floatsByWidget->put (new TypedPointer<Widget> (widget), vloat); - } else if (isWidgetAbsolutelyPositioned (widget)) { - AbsolutelyPositioned *abspos = - new AbsolutelyPositioned (this, widget, generatingBlock, - externalIndex); - absolutelyPositioned->put (abspos); - widget->parentRef = - createRefAbsolutelyPositioned (absolutelyPositioned->size() - 1); - } else - // May be extended. - assertNotReached(); - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::moveExternalIndices (Textblock *generatingBlock, - int oldStartIndex, int diff) -{ - TBInfo *tbInfo = getTextblock (generatingBlock); - moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff); - moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff); -} - -void OutOfFlowMgr::moveExternalIndices (SortedFloatsVector *list, - int oldStartIndex, int diff) -{ - // Could be faster with binary search, but the GB (not CB!) lists - // should be rather small. - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - if (vloat->externalIndex >= oldStartIndex) { - vloat->externalIndex += diff; - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex", - vloat->externalIndex); - } - } -} - -OutOfFlowMgr::Float *OutOfFlowMgr::findFloatByWidget (Widget *widget) -{ - TypedPointer <Widget> key (widget); - Float *vloat = floatsByWidget->get (&key); - assert (vloat != NULL); - return vloat; -} - -void OutOfFlowMgr::markSizeChange (int ref) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref); - - if (isRefFloat (ref)) { - Float *vloat; - - if (isRefLeftFloat (ref)) { - int i = getFloatIndexFromRef (ref); - vloat = leftFloatsAll->get (i); - //printf (" => left float %d\n", i); - } else if (isRefRightFloat (ref)) { - int i = getFloatIndexFromRef (ref); - vloat = rightFloatsAll->get (i); - //printf (" => right float %d\n", i); - } else { - assertNotReached(); - vloat = NULL; // compiler happiness - } - - vloat->dirty = vloat->sizeChangedSinceLastAllocation = true; - - DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); - DBG_OBJ_SET_BOOL_O (vloat->getWidget (), - "<Float>.sizeChangedSinceLastAllocation", - vloat->sizeChangedSinceLastAllocation); - - // The generating block is told directly about this. (Others later, in - // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which - // differentiates many special cases), but the size is not known yet, - vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ()); - } else if (isRefAbsolutelyPositioned (ref)) { - int i = getAbsolutelyPositionedIndexFromRef (ref); - absolutelyPositioned->get(i)->dirty = true; - } else - assertNotReached(); - - DBG_OBJ_LEAVE (); -} - - -void OutOfFlowMgr::markExtremesChange (int ref) -{ - // Nothing to do here. -} - -Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level) -{ - Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level); - if (childAtPoint == NULL) - childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level); - if (childAtPoint == NULL) - childAtPoint = getAbsolutelyPositionedWidgetAtPoint (x, y, level); - return childAtPoint; -} - -Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, - int x, int y, int level) -{ - for (int i = 0; i < list->size(); i++) { - // Could use binary search to be faster. - Float *vloat = list->get(i); - if (vloat->getWidget()->wasAllocated ()) { - Widget *childAtPoint = - vloat->getWidget()->getWidgetAtPoint (x, y, level + 1); - if (childAtPoint) - return childAtPoint; - } - } - - return NULL; -} - -Widget *OutOfFlowMgr::getAbsolutelyPositionedWidgetAtPoint (int x, int y, - int level) -{ - for (int i = 0; i < absolutelyPositioned->size(); i++) { - AbsolutelyPositioned *abspos = absolutelyPositioned->get(i); - if (abspos->widget->wasAllocated ()) { - Widget *childAtPoint = - abspos->widget->getWidgetAtPoint (x, y, level + 1); - if (childAtPoint) - return childAtPoint; - } - } - - return NULL; -} - -void OutOfFlowMgr::tellPosition (Widget *widget, int yReq) -{ - if (isWidgetFloat (widget)) - tellFloatPosition (widget, yReq); - - // Nothing to do for absolutely positioned blocks. -} - - -void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "tellFloatPosition", "%p, %d", - widget, yReq); - - assert (yReq >= 0); - - Float *vloat = findFloatByWidget(widget); - - SortedFloatsVector *listSame, *listOpp; - Side side; - getFloatsListsAndSide (vloat, &listSame, &listOpp, &side); - ensureFloatSize (vloat); - - // "yReal" may change due to collisions (see below). - vloat->yReq = vloat->yReal = yReq; - - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq); - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); - - // Test collisions (on this side). Although there are (rare) cases - // where it could make sense, the horizontal dimensions are not - // tested; especially since searching and border calculation would - // be confused. For this reaspn, only the previous float is - // relevant. (Cf. below, collisions on the other side.) - int index = vloat->getIndex (listSame->type), yRealNew; - if (index >= 1 && - collidesV (vloat, listSame->get (index - 1), listSame->type, - &yRealNew)) { - vloat->yReal = yRealNew; - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); - } - - // Test collisions (on the opposite side). There are cases when - // more than one float has to be tested. Consider the following - // HTML snippet ("id" attribute only used for simple reference - // below, as #f1, #f2, and #f3): - // - // <div style="float:left" id="f1"> - // Left left left left left left left left left left. - // </div> - // <div style="float:left" id="f2">Also left.</div> - // <div style="float:right" id="f3">Right.</div> - // - // When displayed with a suitable window width (only slightly wider - // than the text within #f1), this should look like this: - // - // --------------------------------------------------------- - // | Left left left left left left left left left left. | - // | Also left. Right. | - // --------------------------------------------------------- - // - // Consider float #f3: a collision test with #f2, considering - // vertical dimensions, is positive, but not the test with - // horizontal dimensions (because #f2 and #f3 are too - // narrow). However, a collision has to be tested with #f1; - // otherwise #f3 and #f1 would overlap. - - int oppFloatIndex = - listOpp->findLastBeforeSideSpanningIndex (vloat->sideSpanningIndex); - // Generally, the rules are simple: loop as long as the vertical - // dimensions test is positive (and, of course, there are floats), - // ... - for (bool foundColl = false; - !foundColl && oppFloatIndex >= 0 && - collidesV (vloat, listOpp->get (oppFloatIndex), listSame->type, - &yRealNew); - oppFloatIndex--) { - // ... but stop the loop as soon as the horizontal dimensions - // test is positive. - if (collidesH (vloat, listOpp->get (oppFloatIndex), listSame->type)) { - vloat->yReal = yRealNew; - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); - foundColl = true; - } - } - - DBG_OBJ_MSGF ("resize.oofm", 1, "vloat->yReq = %d, vloat->yReal = %d", - vloat->yReq, vloat->yReal); - - DBG_OBJ_LEAVE (); -} - -bool OutOfFlowMgr::collidesV (Float *vloat, Float *other, SFVType type, - int *yReal) -{ - // Only checks vertical (possible) collisions, and only refers to - // vloat->yReal; never to vloat->allocation->y, even when the GBs are - // different. Used only in tellPosition. - - DBG_OBJ_ENTER ("resize.oofm", 0, "collidesV", "#%d [%p], #%d [%p], ...", - vloat->getIndex (type), vloat->getWidget (), - other->getIndex (type), other->getWidget ()); - - bool result; - - DBG_OBJ_MSGF ("resize.oofm", 1, "initial yReal = %d", vloat->yReal); - - if (vloat->generatingBlock == other->generatingBlock) { - ensureFloatSize (other); - int otherBottomGB = - other->yReal + other->size.ascent + other->size.descent; - - DBG_OBJ_MSGF ("resize.oofm", 1, - "same generators: otherBottomGB = %d + (%d + %d) = %d", - other->yReal, other->size.ascent, other->size.descent, - otherBottomGB); - - if (vloat->yReal < otherBottomGB) { - *yReal = otherBottomGB; - result = true; - } else - result = false; - } else { - assert (wasAllocated (vloat->generatingBlock)); - assert (wasAllocated (other->generatingBlock)); - - // If the other float is not allocated, there is no collision. The - // allocation of this float (vloat) is not used at all. - if (!other->getWidget()->wasAllocated ()) - result = false; - else { - Allocation *gba = getAllocation (vloat->generatingBlock), - *flaOther = other->getWidget()->getAllocation (); - int otherBottomGB = - flaOther->y + flaOther->ascent + flaOther->descent - gba->y; - - DBG_OBJ_MSGF ("resize.oofm", 1, - "different generators: " - "otherBottomGB = %d + (%d + %d) - %d = %d", - flaOther->y, flaOther->ascent, flaOther->descent, gba->y, - otherBottomGB); - - if (vloat->yReal < otherBottomGB) { - *yReal = otherBottomGB; - result = true; - } else - result = false; - } - } - - if (result) - DBG_OBJ_MSGF ("resize.oofm", 1, "collides: new yReal = %d", *yReal); - else - DBG_OBJ_MSG ("resize.oofm", 1, "does not collide"); - - DBG_OBJ_LEAVE (); - return result; -} - - -bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type) -{ - // Only checks horizontal collision. For a complete test, use - // collidesV (...) && collidesH (...). - bool collidesH; - - if (vloat->generatingBlock == other->generatingBlock) - collidesH = vloat->size.width + other->size.width - + vloat->generatingBlock->getStyle()->boxDiffWidth() - > vloat->generatingBlock->getLineBreakWidth(); - else { - assert (wasAllocated (vloat->generatingBlock)); - assert (wasAllocated (other->generatingBlock)); - - // Again, if the other float is not allocated, there is no - // collision. Compare to collidesV. (But vloat->size is used - // here.) - if (!other->getWidget()->wasAllocated ()) - collidesH = false; - else { - Allocation *gba = getAllocation (vloat->generatingBlock); - int vloatX = - calcFloatX (vloat, - vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ? - LEFT : RIGHT, - gba->x, gba->width, - vloat->generatingBlock->getLineBreakWidth ()); - - // Generally: right border of the left float > left border of - // the right float (all in canvas coordinates). - if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT) - // "vloat" is left, "other" is right - collidesH = vloatX + vloat->size.width - > other->getWidget()->getAllocation()->x; - else - // "other" is left, "vloat" is right - collidesH = other->getWidget()->getAllocation()->x - + other->getWidget()->getAllocation()->width - > vloatX; - } - } - - return collidesH; -} - -void OutOfFlowMgr::getFloatsListsAndSide (Float *vloat, - SortedFloatsVector **listSame, - SortedFloatsVector **listOpp, - Side *side) -{ - TBInfo *tbInfo = getTextblock (vloat->generatingBlock); - - switch (vloat->getWidget()->getStyle()->vloat) { - case FLOAT_LEFT: - if (wasAllocated (vloat->generatingBlock)) { - if (listSame) *listSame = leftFloatsCB; - if (listOpp) *listOpp = rightFloatsCB; - } else { - if (listSame) *listSame = tbInfo->leftFloatsGB; - if (listOpp) *listOpp = tbInfo->rightFloatsGB; - } - if (side) *side = LEFT; - break; - - case FLOAT_RIGHT: - if (wasAllocated (vloat->generatingBlock)) { - if (listSame) *listSame = rightFloatsCB; - if (listOpp) *listOpp = leftFloatsCB; - } else { - if (listSame) *listSame = tbInfo->rightFloatsGB; - if (listOpp) *listOpp = tbInfo->leftFloatsGB; - } - if (side) *side = RIGHT; - break; - - default: - assertNotReached(); - } -} - -void OutOfFlowMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight) -{ - DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); - - int oofWidthAbsPos, oofHeightAbsPos; - getAbsolutelyPositionedSize (cbReq, &oofWidthAbsPos, &oofHeightAbsPos); - - int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight; - getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft); - getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight); - - *oofWidth = max (oofWidthtLeft, oofWidthRight, oofWidthAbsPos); - *oofHeight = max (oofHeightLeft, oofHeightRight, oofHeightAbsPos); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> (a: %d, l: %d, r: %d => %d) * (a: %d, l: %d, r: %d => %d)", - oofWidthAbsPos, oofWidthtLeft, oofWidthRight, *oofWidth, - oofHeightAbsPos, oofHeightLeft, oofHeightRight, *oofHeight); - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width, - int *height) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...", - cbReq->width, cbReq->ascent, cbReq->descent, - side == LEFT ? "LEFT" : "RIGHT"); - - SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side); - - *width = *height = 0; - - DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size()); - - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - - if (vloat->generatingBlock == containingBlock || - wasAllocated (vloat->generatingBlock)) { - ensureFloatSize (vloat); - int x, y; - - if (vloat->generatingBlock == containingBlock) { - x = calcFloatX (vloat, side, 0, cbReq->width, - vloat->generatingBlock->getLineBreakWidth ()); - y = vloat->yReal; - } else { - Allocation *gba = getAllocation(vloat->generatingBlock); - x = calcFloatX (vloat, side, - gba->x - containingBlockAllocation.x, gba->width, - vloat->generatingBlock->getLineBreakWidth ()); - y = gba->y - containingBlockAllocation.y + vloat->yReal; - } - - *width = max (*width, x + vloat->size.width); - *height = max (*height, y + vloat->size.ascent + vloat->size.descent); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: (%d + %d) * " - "(%d + (%d + %d)) => %d * %d", - vloat->getWidget (), vloat->generatingBlock, - x, vloat->size.width, - y, vloat->size.ascent, vloat->size.descent, - *width, *height); - } else - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: not allocated", - vloat->getWidget (), vloat->generatingBlock); - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth, - int *oofMaxWidth) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", - cbExtr->minWidth, cbExtr->maxWidth); - - int oofMinWidthAbsPos, oofMaxWidthAbsPos; - getAbsolutelyPositionedExtremes (cbExtr, &oofMinWidthAbsPos, - &oofMaxWidthAbsPos); - - int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight; - getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft); - getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight); - - *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight, oofMinWidthAbsPos); - *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight, oofMaxWidthAbsPos); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> (a: %d, l: %d, r: %d => %d) / (a: %d, l: %d, r: %d => %d)", - oofMinWidthAbsPos, oofMinWidthtLeft, oofMinWidthRight, - *oofMinWidth, oofMaxWidthAbsPos, oofMaxWidthLeft, - oofMaxWidthRight, *oofMaxWidth); - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side, - int *minWidth, int *maxWidth) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...", - cbExtr->minWidth, cbExtr->maxWidth, - side == LEFT ? "LEFT" : "RIGHT"); - - *minWidth = *maxWidth = 0; - - SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side); - DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size()); - - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - int leftDiff, rightDiff; - - if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) { - Extremes extr; - vloat->getWidget()->getExtremes (&extr); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: %d / %d", - vloat->getWidget (), vloat->generatingBlock, - extr.minWidth, extr.maxWidth); - - // TODO: Or zero (instead of rightDiff) for right floats? - *minWidth = - max (*minWidth, - extr.minWidth + (side == LEFT ? leftDiff : rightDiff)); - *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff); - - DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth); - } else - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: not allocated", - vloat->getWidget (), vloat->generatingBlock); - } - - DBG_OBJ_LEAVE (); -} - -// Returns "false" when borders cannot yet determined; *leftDiff and -// *rightDiff are undefined in this case. -bool OutOfFlowMgr::getFloatDiffToCB (Float *vloat, int *leftDiff, - int *rightDiff) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB", - "float %p [generated by %p], ...", - vloat->getWidget (), vloat->generatingBlock); - - bool result; - - if (vloat->generatingBlock == containingBlock) { - *leftDiff = vloat->generatingBlock->getStyle()->boxOffsetX(); - *rightDiff = vloat->generatingBlock->getStyle()->boxRestWidth(); - result = true; - DBG_OBJ_MSGF ("resize.oofm", 1, - "GB == CB => leftDiff = %d, rightDiff = %d", - *leftDiff, *rightDiff); - } else if (wasAllocated (vloat->generatingBlock)) { - Allocation *gba = getAllocation(vloat->generatingBlock); - *leftDiff = gba->x - containingBlockAllocation.x - + vloat->generatingBlock->getStyle()->boxOffsetX(); - *rightDiff = - (containingBlockAllocation.x + containingBlockAllocation.width) - - (gba->x + gba->width) - + vloat->generatingBlock->getStyle()->boxRestWidth(); - result = true; - DBG_OBJ_MSGF ("resize.oofm", 1, - "GB != CB => leftDiff = %d - %d + %d = %d, " - "rightDiff = (%d + %d) - (%d + %d) + %d = %d", - gba->x, containingBlockAllocation.x, - vloat->generatingBlock->getStyle()->boxOffsetX(), - *leftDiff, containingBlockAllocation.x, - containingBlockAllocation.width, gba->x, gba->width, - vloat->generatingBlock->getStyle()->boxRestWidth(), - *rightDiff); - } else { - DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated"); - result = false; - } - - DBG_OBJ_LEAVE (); - return result; -} - -OutOfFlowMgr::TBInfo *OutOfFlowMgr::getTextblock (Textblock *textblock) -{ - TypedPointer<Textblock> key (textblock); - TBInfo *tbInfo = tbInfosByTextblock->get (&key); - assert (tbInfo); - return tbInfo; -} - -/** - * Get the left border for the vertical position of *y*, for a height - * of *h", based on floats; relative to the allocation of the calling - * textblock. - * - * The border includes marging/border/padding of the calling textblock - * but is 0 if there is no float, so a caller should also consider - * other borders. - */ -int OutOfFlowMgr::getLeftBorder (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d", - textblock, y, h, lastGB, lastExtIndex, b); - return b; -} - -/** - * Get the right border for the vertical position of *y*, for a height - * of *h*, based on floats. - * - * See also getLeftBorder(int, int); - */ -int OutOfFlowMgr::getRightBorder (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d", - textblock, y, h, lastGB, lastExtIndex, b); - return b; -} - -int OutOfFlowMgr::getBorder (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int last; - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last); - - DBG_OBJ_MSGF ("border", 1, "first = %d", first); - - if (first == -1) { - // No float. - DBG_OBJ_LEAVE (); - return 0; - } else { - // It is not sufficient to find the first float, since a line - // (with height h) may cover the region of multiple float, of - // which the widest has to be choosen. - int border = 0; - bool covers = true; - - // We are not searching until the end of the list, but until the - // float defined by lastGB and lastExtIndex. - for (int i = first; covers && i <= last; i++) { - Float *vloat = list->get(i); - covers = vloat->covers (textblock, y, h); - DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.", - i, vloat->getWidget(), covers ? "<b>yes</b>" : "no"); - - if (covers) { - int thisBorder; - if (vloat->generatingBlock == textblock) { - int borderIn = side == LEFT ? - vloat->generatingBlock->getStyle()->boxOffsetX() : - vloat->generatingBlock->getStyle()->boxRestWidth(); - thisBorder = vloat->size.width + borderIn; - DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d", - vloat->size.width, borderIn, thisBorder); - } else { - assert (wasAllocated (vloat->generatingBlock)); - assert (vloat->getWidget()->wasAllocated ()); - - Allocation *tba = getAllocation(textblock), - *fla = vloat->getWidget()->getAllocation (); - if (side == LEFT) { - thisBorder = fla->x + fla->width - tba->x; - DBG_OBJ_MSGF ("border", 1, - "not GB: thisBorder = %d + %d - %d = %d", - fla->x, fla->width, tba->x, thisBorder); - } else { - // See also calcFloatX. - thisBorder = - tba->x + textblock->getLineBreakWidth () - fla->x; - DBG_OBJ_MSGF ("border", 1, - "not GB: thisBorder = %d + %d - %d " - "= %d", - tba->x, textblock->getLineBreakWidth (), fla->x, - thisBorder); - } - } - - border = max (border, thisBorder); - DBG_OBJ_MSGF ("border", 1, "=> border = %d", border); - } - } - - DBG_OBJ_LEAVE (); - return border; - } -} - - -OutOfFlowMgr::SortedFloatsVector *OutOfFlowMgr::getFloatsListForTextblock - (Textblock *textblock, Side side) -{ - DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForTextblock", "%p, %s", - textblock, side == LEFT ? "LEFT" : "RIGHT"); - - OutOfFlowMgr::SortedFloatsVector *list; - - if (wasAllocated (textblock)) { - DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list"); - list = side == LEFT ? leftFloatsCB : rightFloatsCB; - } else { - DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list"); - TBInfo *tbInfo = getTextblock (textblock); - list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; - } - - DBG_OBJ_LEAVE (); - return list; -} - - -bool OutOfFlowMgr::hasFloatLeft (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s", - textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); - return b; -} - -bool OutOfFlowMgr::hasFloatRight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s", - textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); - return b; -} - -bool OutOfFlowMgr::hasFloat (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); - - DBG_OBJ_MSGF ("border", 1, "first = %d", first); - DBG_OBJ_LEAVE (); - return first != -1; -} - -int OutOfFlowMgr::getLeftFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex); -} - -int OutOfFlowMgr::getRightFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex); -} - -// Calculate height from the position *y*. -int OutOfFlowMgr::getFloatHeight (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); - assert (first != -1); /* This method must not be called when there is no - float on the respective side. */ - - Float *vloat = list->get(first); - int yRelToFloat; - - if (vloat->generatingBlock == textblock) { - yRelToFloat = y - vloat->yReal; - DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d", - y, vloat->yReal, yRelToFloat); - } else { - // The respective widgets are allocated; otherwise, hasFloat() would have - // returned false. - assert (wasAllocated (textblock)); - assert (vloat->getWidget()->wasAllocated ()); - - Allocation *tba = getAllocation(textblock), - *fla = vloat->getWidget()->getAllocation (); - yRelToFloat = 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 (); -} - -void OutOfFlowMgr::getAbsolutelyPositionedSize (Requisition *cbReq, int *width, - int *height) -{ - // TODO - *width = *height = 0; -} - -void OutOfFlowMgr::getAbsolutelyPositionedExtremes (Extremes *cbExtr, - int *minWidth, - int *maxWidth) -{ - // TODO - *minWidth = *maxWidth = 0; -} - -void OutOfFlowMgr::ensureAbsolutelyPositionedSizeAndPosition - (AbsolutelyPositioned *abspos) -{ - // TODO - assertNotReached (); -} - -int OutOfFlowMgr::calcValueForAbsolutelyPositioned - (AbsolutelyPositioned *abspos, Length styleLen, int refLen) -{ - assert (styleLen != LENGTH_AUTO); - if (isAbsLength (styleLen)) - return absLengthVal (styleLen); - else if (isPerLength (styleLen)) - return multiplyWithPerLength (refLen, styleLen); - else { - assertNotReached (); - return 0; // compiler happiness - } -} - -void OutOfFlowMgr::sizeAllocateAbsolutelyPositioned () -{ - for (int i = 0; i < absolutelyPositioned->size(); i++) { - Allocation *cbAllocation = getAllocation (containingBlock); - AbsolutelyPositioned *abspos = absolutelyPositioned->get (i); - ensureAbsolutelyPositionedSizeAndPosition (abspos); - - Allocation childAllocation; - childAllocation.x = cbAllocation->x + abspos->xCB; - childAllocation.y = cbAllocation->y + abspos->yCB; - childAllocation.width = abspos->width; - childAllocation.ascent = abspos->height; - childAllocation.descent = 0; // TODO - - abspos->widget->sizeAllocate (&childAllocation); - - printf ("[%p] allocating child %p at: (%d, %d), %d x (%d + %d)\n", - containingBlock, abspos->widget, childAllocation.x, - childAllocation.y, childAllocation.width, childAllocation.ascent, - childAllocation.descent); - } -} +} // namespace oof } // namespace dw diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh index b7283815..5b03562d 100644 --- a/dw/outofflowmgr.hh +++ b/dw/outofflowmgr.hh @@ -5,466 +5,81 @@ namespace dw { -class Textblock; +/** + * \brief Out Of Flow. See \ref dw-out-of-flow. + */ +namespace oof { + +class OOFAwareWidget; /** - * \brief Represents additional data for containing blocks. + * \brief Represents additional data for OOF containers. */ class OutOfFlowMgr { - friend class WidgetInfo; - -private: - enum Side { LEFT, RIGHT }; - enum SFVType { GB, CB }; - - Textblock *containingBlock; - - // These two values are redundant to TBInfo::wasAllocated and - // TBInfo::allocation, for some special cases. - bool containingBlockWasAllocated; - core::Allocation containingBlockAllocation; - - class WidgetInfo: public lout::object::Object - { - private: - bool wasAllocated; - int xCB, yCB; // relative to the containing block - int width, height; - - OutOfFlowMgr *oofm; - core::Widget *widget; - - protected: - OutOfFlowMgr *getOutOfFlowMgr () { return oofm; } - - public: - WidgetInfo (OutOfFlowMgr *oofm, core::Widget *widget); - - inline bool wasThenAllocated () { return wasAllocated; } - inline int getOldXCB () { return xCB; } - inline int getOldYCB () { return yCB; } - inline int getOldWidth () { return width; } - inline int getOldHeight () { return height; } - - - void update (bool wasAllocated, int xCB, int yCB, int width, int height); - - inline core::Widget *getWidget () { return widget; } - }; - - class Float: public WidgetInfo - { - public: - class ComparePosition: public lout::object::Comparator - { - private: - OutOfFlowMgr *oofm; - Textblock *refTB; - SFVType type; // actually only used for debugging - - public: - ComparePosition (OutOfFlowMgr *oofm, Textblock *refTB, SFVType type) - { this->oofm = oofm; this->refTB = refTB; this->type = type; } - int compare(Object *o1, Object *o2); - }; - - class CompareSideSpanningIndex: public lout::object::Comparator - { - public: - int compare(Object *o1, Object *o2); - }; - - class CompareGBAndExtIndex: public lout::object::Comparator - { - private: - OutOfFlowMgr *oofm; - SFVType type; // actually only used for debugging - - public: - CompareGBAndExtIndex (OutOfFlowMgr *oofm, SFVType type) - { this->oofm = oofm; this->type = type; } - int compare(Object *o1, Object *o2); - }; - - Textblock *generatingBlock; - int externalIndex; - int yReq, yReal; // relative to generator, not container - int indexGBList; /* Refers to TBInfo::leftFloatsGB or - TBInfo::rightFloatsGB, respectively. -1 - initially. */ - int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB, - respectively. -1 initially. */ - int sideSpanningIndex, mark; - core::Requisition size; - int cbLineBreakWidth; /* On which the calculation of relative sizes - is based. Height not yet used, and probably - not added before size redesign. */ - bool dirty, sizeChangedSinceLastAllocation; - - Float (OutOfFlowMgr *oofm, core::Widget *widget, - Textblock *generatingBlock, int externalIndex); - - inline bool isNowAllocated () { return getWidget()->wasAllocated (); } - inline int getNewXCB () { return getWidget()->getAllocation()->x - - getOutOfFlowMgr()->containingBlockAllocation.x; } - inline int getNewYCB () { return getWidget()->getAllocation()->y - - getOutOfFlowMgr()->containingBlockAllocation.y; } - inline int getNewWidth () { return getWidget()->getAllocation()->width; } - inline int getNewHeight () { return getWidget()->getAllocation()->ascent + - getWidget()->getAllocation()->descent; } - void updateAllocation (); - - inline int *getIndexRef (SFVType type) { - return type == GB ? &indexGBList : &indexCBList; } - inline int getIndex (SFVType type) { return *(getIndexRef (type)); } - inline void setIndex (SFVType type, int value) { - *(getIndexRef (type)) = value; } - - void intoStringBuffer(lout::misc::StringBuffer *sb); - - bool covers (Textblock *textblock, int y, int h); - }; - - /** - * This list is kept sorted. - * - * To prevent accessing methods of the base class in an - * uncontrolled way, the inheritance is private, not public; this - * means that all methods must be delegated (see iterator(), size() - * etc. below.) - * - * TODO Update comment: still sorted, but ... - * - * More: add() and change() may check order again. - */ - class SortedFloatsVector: private lout::container::typed::Vector<Float> - { - public: - SFVType type; - - private: - OutOfFlowMgr *oofm; - Side side; - - public: - inline SortedFloatsVector (OutOfFlowMgr *oofm, Side side, SFVType type) : - lout::container::typed::Vector<Float> (1, false) - { this->oofm = oofm; this->side = side; this->type = type; } - - int findFloatIndex (Textblock *lastGB, int lastExtIndex); - int find (Textblock *textblock, int y, int start, int end); - int findFirst (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex, int *lastReturn); - int findLastBeforeSideSpanningIndex (int sideSpanningIndex); - void put (Float *vloat); - - inline lout::container::typed::Iterator<Float> iterator() - { return lout::container::typed::Vector<Float>::iterator (); } - inline int size () - { return lout::container::typed::Vector<Float>::size (); } - inline Float *get (int pos) - { return lout::container::typed::Vector<Float>::get (pos); } - inline void clear () - { lout::container::typed::Vector<Float>::clear (); } - }; - - class TBInfo: public WidgetInfo - { - public: - int lineBreakWidth; - int index; // position within "tbInfos" - - TBInfo *parent; - int parentExtIndex; - - // These two values are set by sizeAllocateStart(), and they are - // accessable also within sizeAllocateEnd() for the same - // textblock, for which allocation and WAS_ALLOCATED is set - // *after* sizeAllocateEnd(). See the two functions - // wasAllocated(Widget*) and getAllocation(Widget*) (further - // down) for usage. - bool wasAllocated; - core::Allocation allocation; - - // These two lists store all floats generated by this textblock, - // as long as this textblock is not allocates. - SortedFloatsVector *leftFloatsGB, *rightFloatsGB; - - TBInfo (OutOfFlowMgr *oofm, Textblock *textblock, - TBInfo *parent, int parentExtIndex); - ~TBInfo (); - - inline bool isNowAllocated () { - return getOutOfFlowMgr()->wasAllocated (getTextblock ()); } - inline int getNewXCB () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->x - - getOutOfFlowMgr()->containingBlockAllocation.x; } - inline int getNewYCB () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->y - - getOutOfFlowMgr()->containingBlockAllocation.y; } - inline int getNewWidth () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->width; } - inline int getNewHeight () { - core::Allocation *allocation = - getOutOfFlowMgr()->getAllocation (getTextblock ()); - return allocation->ascent + allocation->descent; } - void updateAllocation (); - - inline Textblock *getTextblock () { return (Textblock*)getWidget (); } - }; - - class AbsolutelyPositioned: public lout::object::Object - { - public: - core::Widget *widget; - int xCB, yCB; // relative to the containing block - int width, height; - bool dirty; - - AbsolutelyPositioned (OutOfFlowMgr *oofm, core::Widget *widget, - Textblock *generatingBlock, int externalIndex); - }; - - // These two lists store all floats, in the order in which they are - // defined. Only used for iterators. - lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll; - - // These two lists store all floats whose generators are already - // allocated. - SortedFloatsVector *leftFloatsCB, *rightFloatsCB; - - // These two attributes are used in the size allocation process; - // see sizeAllocateStart and sizeAllocateEnd. - int lastAllocatedLeftFloat, lastAllocatedRightFloat; - - lout::container::typed::HashTable<lout::object::TypedPointer - <dw::core::Widget>, Float> *floatsByWidget; - - lout::container::typed::Vector<TBInfo> *tbInfos; - lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>, - TBInfo> *tbInfosByTextblock; - - lout::container::typed::Vector<AbsolutelyPositioned> *absolutelyPositioned; - - int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark; - - /** - * Variant of Widget::wasAllocated(), which can also be used within - * OOFM::sizeAllocateEnd(). - */ - inline bool wasAllocated (Textblock *textblock) { - return getTextblock(textblock)->wasAllocated; - } - - /** - * Variant of Widget::getAllocation(), which can also be used - * within OOFM::sizeAllocateEnd(). - */ - inline core::Allocation *getAllocation (Textblock *textblock) { - return &(getTextblock(textblock)->allocation); - } - - void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex, - int diff); - Float *findFloatByWidget (core::Widget *widget); - - void moveFromGBToCB (Side side); - void sizeAllocateFloats (Side side, int newLastAllocatedFloat); - int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, - int gbLineBreakWidth); - - bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos, - core::Widget **minFloat); - bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos, - core::Widget **minFloat); - bool hasRelationChanged (bool oldTBAlloc, - int oldTBx, int oldTBy, int oldTBw, int oldTBh, - int newTBx, int newTBy, int newTBw, int newTBh, - bool oldFlAlloc, - int oldFlx, int oldFly, int oldFlw, int oldFlh, - int newFlx, int newFly, int newFlw, int newFlh, - Side side, int *floatPos); - - void checkAllocatedFloatCollisions (Side side); - - bool doFloatsExceedCB (Side side); - bool haveExtremesChanged (Side side); - - void drawFloats (SortedFloatsVector *list, core::View *view, - core::Rectangle *area); - void drawAbsolutelyPositioned (core::View *view, core::Rectangle *area); - core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, - int level); - core::Widget *getAbsolutelyPositionedWidgetAtPoint (int x, int y, int level); - - bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal); - bool collidesH (Float *vloat, Float *other, SFVType type); - - void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame, - SortedFloatsVector **listOpp, Side *side); - - void getFloatsSize (core::Requisition *cbReq, Side side, int *width, - int *height); - void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth, - int *maxWidth); - bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff); - - TBInfo *getTextblock (Textblock *textblock); - int getBorder (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - SortedFloatsVector *getFloatsListForTextblock (Textblock *textblock, - Side side); - bool hasFloat (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - - int getFloatHeight (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - - int 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 ensureAbsolutelyPositionedSizeAndPosition (AbsolutelyPositioned - *abspos); - int calcValueForAbsolutelyPositioned (AbsolutelyPositioned *abspos, - core::style::Length styleLen, - int refLen); - void sizeAllocateAbsolutelyPositioned (); - - static inline bool isWidgetFloat (core::Widget *widget) - { return widget->getStyle()->vloat != core::style::FLOAT_NONE; } - static inline bool isWidgetAbsolutelyPositioned (core::Widget *widget) - { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; } - - /* - * Format for parent ref (see also below for isRefOutOfFlow, - * createRefNormalFlow, and getLineNoFromRef. - * - * Widget in flow: - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | line number | 0 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * So, anything with the least signifant bit set to 1 is out of flow. - * - * Floats: - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | left float index | 0 | 0 | 1 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | right float index | 1 | 0 | 1 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * Absolutely positioned blocks: - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | index | 1 | 1 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - */ - - inline static bool isRefFloat (int ref) - { return ref != -1 && (ref & 3) == 1; } - inline static bool isRefLeftFloat (int ref) - { return ref != -1 && (ref & 7) == 1; } - inline static bool isRefRightFloat (int ref) - { return ref != -1 && (ref & 7) == 5; } - inline static bool isRefAbsolutelyPositioned (int ref) - { return ref != -1 && (ref & 3) == 3; } - - inline static int createRefLeftFloat (int index) - { return (index << 3) | 1; } - inline static int createRefRightFloat (int index) - { return (index << 3) | 5; } - inline static int createRefAbsolutelyPositioned (int index) - { return (index << 2) | 3; } - - inline static int getFloatIndexFromRef (int ref) - { return ref == -1 ? ref : (ref >> 3); } - inline static int getAbsolutelyPositionedIndexFromRef (int ref) - { return ref == -1 ? ref : (ref >> 2); } - public: - OutOfFlowMgr (Textblock *containingBlock); - ~OutOfFlowMgr (); - - void sizeAllocateStart (Textblock *caller, core::Allocation *allocation); - void sizeAllocateEnd (Textblock *caller); - void containerSizeChangedForChildren (); - void draw (core::View *view, core::Rectangle *area); - - void markSizeChange (int ref); - void markExtremesChange (int ref); - core::Widget *getWidgetAtPoint (int x, int y, int level); - - static bool isWidgetOutOfFlow (core::Widget *widget); - static bool isWidgetHandledByOOFM (core::Widget *widget); - void addWidgetInFlow (Textblock *textblock, Textblock *parentBlock, - int externalIndex); - void addWidgetOOF (core::Widget *widget, Textblock *generatingBlock, - int externalIndex); - void moveExternalIndices (Textblock *generatingBlock, int oldStartIndex, - int diff); - - void tellPosition (core::Widget *widget, int yReq); - - void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight); - void getExtremes (core::Extremes *cbExtr, - int *oofMinWidth, int *oofMaxWidth); - - int getLeftBorder (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex); - int getRightBorder (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex); - - bool hasFloatLeft (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex); - bool hasFloatRight (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex); - - int getLeftFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex); - int getRightFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex); - - int getClearPosition (Textblock *tb); - - inline static bool isRefOutOfFlow (int ref) - { return ref != -1 && (ref & 1) != 0; } - inline static int createRefNormalFlow (int lineNo) { return lineNo << 1; } - inline static int getLineNoFromRef (int ref) - { return ref == -1 ? ref : (ref >> 1); } - + OutOfFlowMgr (); + virtual ~OutOfFlowMgr (); + + virtual void sizeAllocateStart (OOFAwareWidget *caller, + core::Allocation *allocation) = 0; + virtual void sizeAllocateEnd (OOFAwareWidget *caller) = 0; + virtual void containerSizeChangedForChildren () = 0; + virtual void draw (core::View *view, core::Rectangle *area) = 0; + + virtual void markSizeChange (int ref) = 0; + virtual void markExtremesChange (int ref) = 0; + virtual core::Widget *getWidgetAtPoint (int x, int y, int level) = 0; + + virtual void addWidgetInFlow (OOFAwareWidget *widget, + OOFAwareWidget *parent, int externalIndex) = 0; + virtual int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator, + int externalIndex) = 0; + virtual void moveExternalIndices (OOFAwareWidget *generator, + int oldStartIndex, int diff) = 0; + + virtual void tellPosition (core::Widget *widget, int x, int y) = 0; + + virtual void getSize (core::Requisition *containerReq, int *oofWidth, + int *oofHeight) = 0; + virtual void getExtremes (core::Extremes *containerExtr, int *oofMinWidth, + int *oofMaxWidth) = 0; + + + virtual int getLeftBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + virtual int getRightBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + + virtual bool hasFloatLeft (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + virtual bool hasFloatRight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + + virtual int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) + = 0; + virtual int getRightFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) + = 0; + + virtual bool affectsLeftBorder (core::Widget *widget) = 0; + virtual bool affectsRightBorder (core::Widget *widget) = 0; + virtual bool mayAffectBordersAtAll () = 0; + + virtual int getClearPosition (OOFAwareWidget *widget) = 0; + + virtual bool dealingWithSizeOfChild (core::Widget *child) = 0; + virtual int getAvailWidthOfChild (core::Widget *child, bool forceValue) = 0; + virtual int getAvailHeightOfChild (core::Widget *child, bool forceValue) = 0; + // for iterators - inline int getNumWidgets () { - return leftFloatsAll->size() + rightFloatsAll->size() + - absolutelyPositioned->size(); } - - inline core::Widget *getWidget (int i) { - if (i < leftFloatsAll->size()) - return leftFloatsAll->get(i)->getWidget (); - else if (i < leftFloatsAll->size() + rightFloatsAll->size()) - return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget (); - else - return absolutelyPositioned->get(i - (leftFloatsAll->size() + - rightFloatsAll->size()))->widget; - } - - inline bool affectsLeftBorder (core::Widget *widget) { - return widget->getStyle()->vloat == core::style::FLOAT_LEFT; } - inline bool affectsRightBorder (core::Widget *widget) { - return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; } + virtual int getNumWidgets () = 0; + virtual core::Widget *getWidget (int i) = 0; }; +} // namespace oof + } // namespace dw #endif // __DW_OUTOFFLOWMGR_HH__ diff --git a/dw/ruler.cc b/dw/ruler.cc index 3fdbfb6d..fc2c5bca 100644 --- a/dw/ruler.cc +++ b/dw/ruler.cc @@ -32,15 +32,14 @@ Ruler::Ruler () void Ruler::sizeRequestImpl (core::Requisition *requisition) { - requisition->width = - lout::misc::max (getAvailWidth (true), getStyle()->boxDiffWidth ()); - requisition->ascent = getStyle()->boxOffsetY (); - requisition->descent = getStyle()->boxRestHeight (); + requisition->width = lout::misc::max (getAvailWidth (true), boxDiffWidth ()); + requisition->ascent = boxOffsetY (); + requisition->descent = boxRestHeight (); } void Ruler::getExtremesImpl (core::Extremes *extremes) { - extremes->minWidth = extremes->maxWidth = getStyle()->boxDiffWidth (); + extremes->minWidth = extremes->maxWidth = boxDiffWidth (); extremes->minWidthIntrinsic = extremes->minWidth; extremes->maxWidthIntrinsic = extremes->maxWidth; correctExtremes (extremes); diff --git a/dw/simpletablecell.cc b/dw/simpletablecell.cc index 02f92db6..62b4a0a4 100644 --- a/dw/simpletablecell.cc +++ b/dw/simpletablecell.cc @@ -119,4 +119,9 @@ int SimpleTableCell::applyPerHeight (int containerHeight, return tablecell::applyPerHeight (this, containerHeight, perHeight); } +bool SimpleTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +} + } // namespace dw diff --git a/dw/simpletablecell.hh b/dw/simpletablecell.hh index 4c18b454..c90fc040 100644 --- a/dw/simpletablecell.hh +++ b/dw/simpletablecell.hh @@ -18,6 +18,8 @@ protected: bool getAdjustMinWidth (); + bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); + public: static int CLASS_ID; diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc new file mode 100644 index 00000000..333f0707 --- /dev/null +++ b/dw/stackingcontextmgr.cc @@ -0,0 +1,107 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.hh" +#include "../lout/debug.hh" + +using namespace lout::misc; +using namespace lout::container::typed; + +namespace dw { + +namespace core { + +StackingContextMgr::StackingContextMgr (Widget *widget) +{ + DBG_OBJ_CREATE ("dw::core::StackingContextMgr"); + scWidgets = new Vector<Widget> (1, false); + DBG_OBJ_SET_NUM ("scWidgets.size", scWidgets->size()); + + minZIndex = maxZIndex = 0; // Just to have some defined values. +} + +StackingContextMgr::~StackingContextMgr () +{ + delete scWidgets; + DBG_OBJ_DELETE (); +} + +void StackingContextMgr::addChildSCWidget (Widget *widget) +{ + if (scWidgets->size () == 0) + minZIndex = maxZIndex = widget->getStyle()->zIndex; + else { + minZIndex = min (minZIndex, widget->getStyle()->zIndex); + maxZIndex = max (maxZIndex, widget->getStyle()->zIndex); + } + + scWidgets->put (widget); + DBG_OBJ_SET_NUM ("scWidgets.size", scWidgets->size()); + DBG_OBJ_ARRSET_PTR ("scWidgets", scWidgets->size() - 1, widget); +} + +void StackingContextMgr::drawBottom (View *view, Rectangle *area) +{ + DBG_OBJ_ENTER ("draw", 0, "drawBottom", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + draw (view, area, INT_MIN, -1); + DBG_OBJ_LEAVE (); +} + +void StackingContextMgr::drawTop (View *view, Rectangle *area) +{ + DBG_OBJ_ENTER ("draw", 0, "drawBottom", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + draw (view, area, 0, INT_MAX); + DBG_OBJ_LEAVE (); +} + +void StackingContextMgr::draw (View *view, Rectangle *area, int startZIndex, + int endZIndex) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "[%d, %d, %d * %d], %d, %d", + area->x, area->y, area->width, area->height, startZIndex, + endZIndex); + + for (int zIndex = max (minZIndex, startZIndex); + zIndex <= min (maxZIndex, endZIndex); zIndex++) { + DBG_OBJ_MSGF ("draw", 1, "drawing zIndex = %d", zIndex); + DBG_OBJ_MSG_START (); + + for (int i = 0; i < scWidgets->size (); i++) { + Widget *child = scWidgets->get (i); + DBG_OBJ_MSGF ("draw", 2, "widget %p has zIndex = %d", + child, child->getStyle()->zIndex); + Rectangle childArea; + if (child->getStyle()->zIndex == zIndex && + child->intersects (area, &childArea)) + child->draw (view, &childArea); + } + + DBG_OBJ_MSG_END (); + } + + DBG_OBJ_LEAVE (); +} + + +} // namespace core + +} // namespace dw diff --git a/dw/stackingcontextmgr.hh b/dw/stackingcontextmgr.hh new file mode 100644 index 00000000..17219436 --- /dev/null +++ b/dw/stackingcontextmgr.hh @@ -0,0 +1,48 @@ +#ifndef __DW_STACKINGCONTEXTMGR_HH__ +#define __DW_STACKINGCONTEXTMGR_HH__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +#include "../lout/container.hh" + +#include <limits.h> + +namespace dw { + +namespace core { + +class OOFAwareWidget; + +/** + * \brief ... + */ +class StackingContextMgr +{ +private: + lout::container::typed::Vector<Widget> *scWidgets; + int minZIndex, maxZIndex; + + void draw (View *view, Rectangle *area, int startZIndex, int endZIndex); + +public: + StackingContextMgr (Widget *widget); + ~StackingContextMgr (); + + inline static bool isEstablishingStackingContext (Widget *widget) { + return widget->getStyle()->position != style::POSITION_STATIC && + widget->getStyle()->zIndex != style::Z_INDEX_AUTO; + } + + void addChildSCWidget (Widget *widget); + + void drawBottom (View *view, Rectangle *area); + void drawTop (View *view, Rectangle *area); +}; + +} // namespace core + +} // namespace dw + +#endif // __DW_STACKINGCONTEXTMGR_HH__ diff --git a/dw/style.cc b/dw/style.cc index d548d209..1c2978b4 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -92,6 +92,7 @@ void StyleAttrs::initValues () display = DISPLAY_INLINE; whiteSpace = WHITE_SPACE_NORMAL; cursor = CURSOR_DEFAULT; + zIndex = Z_INDEX_AUTO; } /** @@ -200,6 +201,7 @@ bool StyleAttrs::equals (object::Object *other) { listStylePosition == otherAttrs->listStylePosition && listStyleType == otherAttrs->listStyleType && cursor == otherAttrs->cursor && + zIndex == otherAttrs->zIndex && x_link == otherAttrs->x_link && x_lang[0] == otherAttrs->x_lang[0] && x_lang[1] == otherAttrs->x_lang[1] && @@ -256,6 +258,7 @@ int StyleAttrs::hashValue () { listStylePosition + listStyleType + cursor + + zIndex + x_link + x_lang[0] + x_lang[1] + x_img + @@ -376,6 +379,7 @@ void Style::copyAttrs (StyleAttrs *attrs) listStylePosition = attrs->listStylePosition; listStyleType = attrs->listStyleType; cursor = attrs->cursor; + zIndex = attrs->zIndex; x_link = attrs->x_link; x_lang[0] = attrs->x_lang[0]; x_lang[1] = attrs->x_lang[1]; diff --git a/dw/style.hh b/dw/style.hh index bda567ce..9c6bedf1 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -7,6 +7,8 @@ # error Do not include this file directly, use "core.hh" instead. #endif +#include <limits.h> + #include "../lout/signal.hh" #include "../lout/debug.hh" @@ -367,6 +369,17 @@ enum ClearType { CLEAR_NONE }; +enum { + /** + * \brief 'z-index' is stored as int; use this for the value 'auto'. + * + * Only some random value, which has to be checked explicitly; do + * not compare this (less or greater) to integer values of + * 'z-index'. + */ + Z_INDEX_AUTO = INT_MAX +}; + /** * \brief Type for representing all lengths within dw::core::style. * @@ -544,6 +557,7 @@ public: ListStylePosition listStylePosition; ListStyleType listStyleType; Cursor cursor; + int zIndex; int x_link; int x_img; diff --git a/dw/table.cc b/dw/table.cc index 746856c7..d443327b 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -112,18 +112,20 @@ void Table::sizeRequestImpl (core::Requisition *requisition) /** * \bug Baselines are not regarded here. */ - requisition->width = getStyle()->boxDiffWidth () - + (numCols + 1) * getStyle()->hBorderSpacing; + requisition->width = + boxDiffWidth () + (numCols + 1) * getStyle()->hBorderSpacing; for (int col = 0; col < numCols; col++) requisition->width += colWidths->get (col); requisition->ascent = - getStyle()->boxDiffHeight () + cumHeight->get (numRows) - + getStyle()->vBorderSpacing; + boxDiffHeight () + cumHeight->get (numRows) + getStyle()->vBorderSpacing; requisition->descent = 0; correctRequisition (requisition, core::splitHeightPreserveDescent); + // For the order, see similar reasoning for dw::Textblock. + correctRequisitionByOOF (requisition, core::splitHeightPreserveDescent); + DBG_OBJ_LEAVE (); } @@ -152,6 +154,9 @@ void Table::getExtremesImpl (core::Extremes *extremes) correctExtremes (extremes); + // For the order, see similar reasoning for dw::Textblock. + correctExtremesByOOF (extremes); + DBG_OBJ_LEAVE (); } @@ -161,16 +166,16 @@ void Table::sizeAllocateImpl (core::Allocation *allocation) allocation->x, allocation->y, allocation->width, allocation->ascent, allocation->descent); + sizeAllocateStart (allocation); + calcCellSizes (true); /** * \bug Baselines are not regarded here. */ - int offy = - allocation->y + getStyle()->boxOffsetY () + getStyle()->vBorderSpacing; - int x = - allocation->x + getStyle()->boxOffsetX () + getStyle()->hBorderSpacing; + int offy = allocation->y + boxOffsetY () + getStyle()->vBorderSpacing; + int x = allocation->x + boxOffsetX () + getStyle()->hBorderSpacing; for (int col = 0; col < numCols; col++) { for (int row = 0; row < numRows; row++) { @@ -201,6 +206,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation) x += colWidths->get (col) + getStyle()->hBorderSpacing; } + sizeAllocateEnd (); + DBG_OBJ_LEAVE (); } @@ -218,16 +225,22 @@ int Table::getAvailWidthOfChild (Widget *child, bool forceValue) child, forceValue ? "true" : "false"); int width; + oof::OutOfFlowMgr *oofm; - // Unlike other containers, the table widget sometimes narrows - // columns to a width less than specified by CSS (see - // forceCalcCellSizes). For this reason, the column widths have to - // be calculated in all cases. - if (forceValue) { - calcCellSizes (false); - width = calcAvailWidthForDescendant (child); - } else - width = -1; + if (isWidgetOOF(child) && (oofm = getWidgetOutOfFlowMgr(child)) && + oofm->dealingWithSizeOfChild (child)) + width = oofm->getAvailWidthOfChild (child, forceValue); + else { + // Unlike other containers, the table widget sometimes narrows + // columns to a width less than specified by CSS (see + // forceCalcCellSizes). For this reason, the column widths have to + // be calculated in all cases. + if (forceValue) { + calcCellSizes (false); + width = calcAvailWidthForDescendant (child); + } else + width = -1; + } DBG_OBJ_MSGF ("resize", 1, "=> %d", width); DBG_OBJ_LEAVE (); @@ -306,6 +319,8 @@ void Table::containerSizeChangedForChildren () } } + containerSizeChangedForChildrenOOF (); + DBG_OBJ_LEAVE (); } @@ -371,6 +386,8 @@ void Table::draw (core::View *view, core::Rectangle *area) child->draw (view, &childArea); } } + + drawOOF (view, area); } void Table::removeChild (Widget *child) @@ -465,6 +482,8 @@ void Table::addCell (Widget *widget, int colspan, int rowspan) curCol += colspanEff; + widget->parentRef = makeParentRefInFlow (0); + widget->setParent (this); if (rowStyle->get (curRow)) widget->setBgColor (rowStyle->get(curRow)->backgroundColor); diff --git a/dw/table.hh b/dw/table.hh index a8823ca0..c47ff465 100644 --- a/dw/table.hh +++ b/dw/table.hh @@ -1,7 +1,7 @@ #ifndef __DW_TABLE_HH__ #define __DW_TABLE_HH__ -#include "core.hh" +#include "oofawarewidget.hh" #include "alignedtablecell.hh" #include "../lout/misc.hh" @@ -319,7 +319,7 @@ namespace dw { * Here, \em foo-bar refers to the attribute \em bar of the tag \em foo foo. * Look at the HTML parser for more details. */ -class Table: public core::Widget +class Table: public oof::OOFAwareWidget { private: struct Child @@ -339,20 +339,17 @@ private: }; }; - class TableIterator: public core::Iterator + class TableIterator: public OOFAwareWidgetIterator { - private: - int index; + protected: + int numContentsInFlow (); + void getContentInFlow (int index, core::Content *content); public: TableIterator (Table *table, core::Content::Type mask, bool atEnd); - TableIterator (Table *table, core::Content::Type mask, int index); lout::object::Object *clone(); - int compareTo(lout::object::Comparable *other); - bool next (); - bool prev (); void highlight (int start, int end, core::HighlightLayer layer); void unhighlight (int direction, core::HighlightLayer layer); void getAllocation (int start, int end, core::Allocation *allocation); diff --git a/dw/table_iterator.cc b/dw/table_iterator.cc index 4da0ef4f..9ba61619 100644 --- a/dw/table_iterator.cc +++ b/dw/table_iterator.cc @@ -28,107 +28,62 @@ namespace dw { Table::TableIterator::TableIterator (Table *table, core::Content::Type mask, bool atEnd): - core::Iterator (table, mask, atEnd) + OOFAwareWidgetIterator (table, mask, atEnd, table->children->size ()) { - index = atEnd ? table->children->size () : -1; - content.type = atEnd ? core::Content::END : core::Content::START; -} - -Table::TableIterator::TableIterator (Table *table, - core::Content::Type mask, int index): - core::Iterator (table, mask, false) -{ - this->index = index; - - if (index < 0) - content.type = core::Content::START; - else if (index >= table->children->size ()) - content.type = core::Content::END; - else { - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - } } object::Object *Table::TableIterator::clone() { - return new TableIterator ((Table*)getWidget(), getMask(), index); -} - -int Table::TableIterator::compareTo(object::Comparable *other) -{ - return index - ((TableIterator*)other)->index; + TableIterator *tIt = + new TableIterator ((Table*)getWidget(), getMask(), false); + cloneValues (tIt); + return tIt; } -bool Table::TableIterator::next () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::END) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::END; - return false; - } - - do { - index++; - if (index >= table->children->size ()) { - content.type = core::Content::END; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} - -bool Table::TableIterator::prev () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::START) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::START; - return false; - } - - do { - index--; - if (index < 0) { - content.type = core::Content::START; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} void Table::TableIterator::highlight (int start, int end, core::HighlightLayer layer) { - /** todo Needs this an implementation? */ + if (inFlow ()) { + /** todo Needs this an implementation? */ + } else + highlightOOF (start, end, layer); } void Table::TableIterator::unhighlight (int direction, core::HighlightLayer layer) { + if (inFlow ()) { + // ??? + } else + unhighlightOOF (direction, layer); } void Table::TableIterator::getAllocation (int start, int end, core::Allocation *allocation) { - /** \bug Not implemented. */ + if (inFlow ()) { + /** \bug Not implemented. */ + } else + getAllocationOOF (start, end, allocation); +} + +int Table::TableIterator::numContentsInFlow () +{ + return ((Table*)getWidget())->children->size (); +} + +void Table::TableIterator::getContentInFlow (int index, + core::Content *content) +{ + Table *table = (Table*)getWidget(); + + if (table->children->get(index) != NULL && + table->children->get(index)->type == Child::CELL) { + content->type = core::Content::WIDGET_IN_FLOW; + content->widget = table->children->get(index)->cell.widget; + } else + content->type = core::Content::INVALID; } } // namespace dw diff --git a/dw/tablecell.hh b/dw/tablecell.hh index 2e26c8e8..f7936203 100644 --- a/dw/tablecell.hh +++ b/dw/tablecell.hh @@ -28,6 +28,8 @@ int applyPerWidth (core::Widget *widget, int containerWidth, int applyPerHeight (core::Widget *widget, int containerHeight, core::style::Length perHeight); +inline bool adjustExtraSpaceWhenCorrectingRequisitionByOOF () { return false; } + } // namespace dw } // namespace dw diff --git a/dw/textblock.cc b/dw/textblock.cc index a72b2ad1..9bff14d7 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -227,7 +227,6 @@ Textblock::Textblock (bool limitTextWidth) registerName ("dw::Textblock", &CLASS_ID); setButtonSensitive(true); - containingBlock = NULL; hasListitemValue = false; leftInnerPadding = 0; line1Offset = 0; @@ -252,7 +251,6 @@ Textblock::Textblock (bool limitTextWidth) nonTemporaryLines = 0; words = new misc::NotSoSimpleVector <Word> (1); anchors = new misc::SimpleVector <Anchor> (1); - outOfFlowMgr = NULL; wrapRefLines = wrapRefParagraphs = -1; @@ -267,8 +265,8 @@ Textblock::Textblock (bool limitTextWidth) lineBreakWidth = -1; DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth); - verticalOffset = 0; - DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset); + clearPosition = 0; + DBG_OBJ_SET_NUM ("clearPosition", clearPosition); this->limitTextWidth = limitTextWidth; @@ -285,8 +283,6 @@ Textblock::Textblock (bool limitTextWidth) Textblock::~Textblock () { - _MSG("Textblock::~Textblock\n"); - /* make sure not to call a free'd tooltip (very fast overkill) */ hoverTooltip = NULL; @@ -304,16 +300,6 @@ Textblock::~Textblock () delete words; delete anchors; - if(outOfFlowMgr) { - // I feel more comfortable by letting the textblock delete these - // widgets, instead of doing this in ~OutOfFlowMgr. - - for (int i = 0; i < outOfFlowMgr->getNumWidgets (); i++) - delete outOfFlowMgr->getWidget (i); - - delete outOfFlowMgr; - } - /* Make sure we don't own widgets anymore. Necessary before call of parent class destructor. (???) */ words = NULL; @@ -370,11 +356,11 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) } DBG_OBJ_MSGF ("resize", 1, "left inner padding = %d, boxDiffWidth = %d", - leftInnerPadding, getStyle()->boxDiffWidth ()); + leftInnerPadding, boxDiffWidth ()); - requisition->width += leftInnerPadding + getStyle()->boxDiffWidth (); - requisition->ascent += verticalOffset + getStyle()->boxOffsetY (); - requisition->descent += getStyle()->boxRestHeight (); + requisition->width += leftInnerPadding + boxDiffWidth (); + requisition->ascent += boxOffsetY (); + requisition->descent += boxRestHeight (); if (mustBeWidenedToAvailWidth ()) { DBG_OBJ_MSGF ("resize", 1, @@ -406,25 +392,7 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) // Is this really what we want? An alternative could be that // OutOfFlowMgr::getSize honours CSS attributes an corrected sizes. - DBG_OBJ_MSGF ("resize", 1, "before considering OOF widgets: %d * (%d + %d)", - requisition->width, requisition->ascent, requisition->descent); - - if (outOfFlowMgr) { - int oofWidth, oofHeight; - outOfFlowMgr->getSize (requisition, &oofWidth, &oofHeight); - - // Floats must be within the *content* area, not the *margin* - // area (which is equivalent to the requisition / - // allocation). For this reason, boxRestWidth() and - // boxRestHeight() must be considered. - - if (oofWidth + boxRestWidth () > requisition->width) - requisition->width = oofWidth + boxRestWidth (); - if (oofHeight + boxRestHeight () - > requisition->ascent + requisition->descent) - requisition->descent = - oofHeight + boxRestHeight () - requisition->ascent; - } + correctRequisitionByOOF (requisition, core::splitHeightPreserveAscent); DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)", requisition->width, requisition->ascent, requisition->descent); @@ -487,7 +455,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) extremes->minWidth, extremes->minWidthIntrinsic, extremes->maxWidth, extremes->maxWidthIntrinsic); - int diff = leftInnerPadding + getStyle()->boxDiffWidth (); + int diff = leftInnerPadding + boxDiffWidth (); extremes->minWidth += diff; extremes->minWidthIntrinsic += diff; extremes->maxWidth += diff; @@ -505,20 +473,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) extremes->minWidth, extremes->minWidthIntrinsic, extremes->maxWidth, extremes->maxWidthIntrinsic); - if (outOfFlowMgr) { - int oofMinWidth, oofMaxWidth; - outOfFlowMgr->getExtremes (extremes, &oofMinWidth, &oofMaxWidth); - - DBG_OBJ_MSGF ("resize", 1, "OOFM correction: %d / %d", - oofMinWidth, oofMaxWidth); - - extremes->minWidth = misc::max (extremes->minWidth, oofMinWidth); - extremes->minWidthIntrinsic = - misc::max (extremes->minWidthIntrinsic, oofMinWidth); - extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth); - extremes->maxWidthIntrinsic = - misc::max (extremes->maxWidthIntrinsic, oofMinWidth); - } + correctExtremesByOOF (extremes); DBG_OBJ_MSGF ("resize", 0, "finally, after considering OOFM: %d (%d) / %d (%d)", @@ -568,7 +523,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) // Reconstruct the initial size; see // Textblock::sizeRequestImpl. (lines->size () > 0 ? lines->getRef(0)->boxAscent : 0) - + verticalOffset + getStyle()->boxOffsetY ()); + + boxOffsetY ()); childBaseAllocation.descent = allocation->ascent + allocation->descent - childBaseAllocation.ascent; @@ -578,8 +533,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) DBG_OBJ_SET_NUM ("childBaseAllocation.ascent", childBaseAllocation.ascent); DBG_OBJ_SET_NUM ("childBaseAllocation.descent", childBaseAllocation.descent); - if (containingBlock->outOfFlowMgr) - containingBlock->outOfFlowMgr->sizeAllocateStart (this, allocation); + sizeAllocateStart (allocation); int lineIndex, wordIndex; Line *line; @@ -707,9 +661,8 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) DBG_OBJ_MSG_END (); - if (containingBlock->outOfFlowMgr) - containingBlock->outOfFlowMgr->sizeAllocateEnd (this); - + sizeAllocateEnd (); + for (int i = 0; i < anchors->size(); i++) { Anchor *anchor = anchors->getRef(i); int y; @@ -729,6 +682,12 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) DBG_OBJ_LEAVE (); } +void Textblock::calcExtraSpaceImpl () +{ + OOFAwareWidget::calcExtraSpaceImpl (); + extraSpace.top = misc::max (extraSpace.top, clearPosition); +} + int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue) { DBG_OBJ_ENTER ("resize", 0, "Textblock/getAvailWidthOfChild", "%p, %s", @@ -736,25 +695,31 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue) int width; - if (child->getStyle()->width == core::style::LENGTH_AUTO) { - // No width specified: similar to standard implementation (see - // there), but "leftInnerPadding" has to be considered, too. - DBG_OBJ_MSG ("resize", 1, "no specification"); - if (forceValue) - width = misc::max (getAvailWidth (true) - boxDiffWidth () - - leftInnerPadding, - 0); - else - width = -1; - } else - width = Widget::getAvailWidthOfChild (child, forceValue); - - if (forceValue && this == child->getContainer () && - !mustBeWidenedToAvailWidth ()) { - core::Extremes extremes; - getExtremes (&extremes); - if (width > extremes.maxWidth) - width = extremes.maxWidth; + if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)) + width = + getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue); + else { + if (child->getStyle()->width == core::style::LENGTH_AUTO) { + // No width specified: similar to standard implementation (see + // there), but "leftInnerPadding" has to be considered, too. + DBG_OBJ_MSG ("resize", 1, "no specification"); + if (forceValue) + width = misc::max (getAvailWidth (true) - boxDiffWidth () + - leftInnerPadding, + 0); + else + width = -1; + } else + width = Widget::getAvailWidthOfChild (child, forceValue); + + if (forceValue && this == child->getContainer () && + !mustBeWidenedToAvailWidth ()) { + core::Extremes extremes; + getExtremes (&extremes); + if (width > extremes.maxWidth) + width = extremes.maxWidth; + } } DBG_OBJ_MSGF ("resize", 1, "=> %d", width); @@ -762,7 +727,15 @@ int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue) return width; } - +int Textblock::getAvailHeightOfChild (core::Widget *child, bool forceValue) +{ + if (isWidgetOOF(child) && getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)) + return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child, + forceValue); + else + return Widget::getAvailHeightOfChild (child, forceValue); +} void Textblock::containerSizeChangedForChildren () { @@ -774,9 +747,8 @@ void Textblock::containerSizeChangedForChildren () word->content.widget->containerSizeChanged (); } - if (outOfFlowMgr) - outOfFlowMgr->containerSizeChangedForChildren (); - + containerSizeChangedForChildrenOOF (); + DBG_OBJ_LEAVE (); } @@ -785,7 +757,7 @@ bool Textblock::affectsSizeChangeContainerChild (Widget *child) DBG_OBJ_ENTER ("resize", 0, "Textblock/affectsSizeChangeContainerChild", "%p", child); - // See Textblock::getAvailWidthForChild() and Textblock::oofSizeChanged(): + // See Textblock::getAvailWidthOfChild() and Textblock::oofSizeChanged(): // Extremes changes affect the size of the child, too: bool ret; if (!mustBeWidenedToAvailWidth () && @@ -828,13 +800,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 @@ -842,10 +811,10 @@ void Textblock::markSizeChange (int ref) now, but addLine(...) will do everything necessary. */ if (ref != -1) { if (wrapRefLines == -1) - wrapRefLines = OutOfFlowMgr::getLineNoFromRef (ref); + wrapRefLines = getParentRefInFlowSubRef (ref); else wrapRefLines = misc::min (wrapRefLines, - OutOfFlowMgr::getLineNoFromRef (ref)); + getParentRefInFlowSubRef (ref)); } DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines); @@ -865,13 +834,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 @@ -879,11 +845,10 @@ void Textblock::markExtremesChange (int ref) now, but addLine(...) will do everything necessary. */ if (ref != -1) { if (wrapRefParagraphs == -1) - wrapRefParagraphs = OutOfFlowMgr::getLineNoFromRef (ref); + wrapRefParagraphs = getParentRefInFlowSubRef (ref); else wrapRefParagraphs = - misc::min (wrapRefParagraphs, - OutOfFlowMgr::getLineNoFromRef (ref)); + misc::min (wrapRefParagraphs, getParentRefInFlowSubRef (ref)); } DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs); @@ -892,58 +857,6 @@ void Textblock::markExtremesChange (int ref) DBG_OBJ_LEAVE (); } -void Textblock::notifySetAsTopLevel() -{ - PRINTF ("%p becomes toplevel\n", this); - containingBlock = this; - PRINTF ("-> %p is its own containing block\n", this); -} - -bool Textblock::isContainingBlock (Widget *widget) -{ - return - // Of course, only textblocks are considered as containing - // blocks. - widget->instanceOf (Textblock::CLASS_ID) && - // The second condition: that this block is "out of flow", in a - // wider sense. - (// The toplevel widget is "out of flow", since there is no - // parent, and so no context. - widget->getParent() == NULL || - // A similar reasoning applies to a widget with another parent - // than a textblock (typical example: a table cell (this is - // also a text block) within a table widget). - !widget->getParent()->instanceOf (Textblock::CLASS_ID) || - // Inline blocks are containing blocks, too. - widget->getStyle()->display == core::style::DISPLAY_INLINE_BLOCK || - // Finally, "out of flow" in a narrower sense: floats and - // absolute positions. - OutOfFlowMgr::isWidgetOutOfFlow (widget)); -} - -void Textblock::notifySetParent () -{ - PRINTF ("%p becomes a child of %p\n", this, getParent()); - - // Search for containing Box. - containingBlock = NULL; - - for (Widget *widget = this; widget != NULL && containingBlock == NULL; - widget = widget->getParent()) - if (isContainingBlock (widget)) { - containingBlock = (Textblock*)widget; - - if (containingBlock == this) { - PRINTF ("-> %p is its own containing block\n", this); - } else { - PRINTF ("-> %p becomes containing block of %p\n", - containingBlock, this); - } - } - - assert (containingBlock != NULL); -} - bool Textblock::isBlockLevel () { return true; @@ -1162,8 +1075,8 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, } } - it = new TextblockIterator (this, core::Content::maskForSelection (true), - false, wordIndex); + it = TextblockIterator::createWordIndexIterator + (this, core::Content::maskForSelection (true), wordIndex); r = selectionHandleEvent (eventType, it, charPos, link, event); it->unref (); return r; @@ -1591,9 +1504,7 @@ int Textblock::findLineIndexWhenNotAllocated (int y) if (lines->size() == 0) return -1; else - return findLineIndex (y, - lines->getRef(0)->boxAscent + verticalOffset + - getStyle()->boxOffsetY()); + return findLineIndex (y, lines->getRef(0)->boxAscent + boxOffsetY()); } int Textblock::findLineIndexWhenAllocated (int y) @@ -1745,15 +1656,10 @@ void Textblock::draw (core::View *view, core::Rectangle *area) int lineIndex; Line *line; - // Instead of drawWidgetBox, use drawBox to include verticalOffset. - if (getParent() == NULL) { - // The toplevel (parent == NULL) widget is a special case, which - // we leave to drawWidgetBox; verticalOffset will here always 0. - assert (verticalOffset == 0); - drawWidgetBox (view, area, false); - } else - drawBox (view, getStyle(), area, 0, verticalOffset, allocation.width, - getHeight() - verticalOffset, false); + drawWidgetBox (view, area, false); + + if (stackingContextMgr) + stackingContextMgr->drawBottom (view, area); lineIndex = findLineIndexWhenAllocated (area->y); @@ -1766,8 +1672,10 @@ void Textblock::draw (core::View *view, core::Rectangle *area) drawLine (line, view, area); } - if(outOfFlowMgr) - outOfFlowMgr->draw(view, area); + drawOOF (view, area); + + if (stackingContextMgr) + stackingContextMgr->drawTop (view, area); DBG_OBJ_LEAVE (); } @@ -2328,21 +2236,31 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) widget->setStyle (style); - PRINTF ("adding the %s %p to %p (word %d) ...\n", - widget->getClassName(), widget, this, words->size()); + initOutOfFlowMgrs (); - if (containingBlock->outOfFlowMgr == NULL) { - containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock); - DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr); - } - - if (OutOfFlowMgr::isWidgetHandledByOOFM (widget)) { - PRINTF (" -> out of flow.\n"); + if (testWidgetOutOfFlow (widget)) { + int oofmIndex = -1; + if (testWidgetFloat (widget)) + oofmIndex = OOFM_FLOATS; + else if (testWidgetAbsolutelyPositioned (widget)) + oofmIndex = OOFM_ABSOLUTE; + else if (testWidgetFixedlyPositioned (widget)) + oofmIndex = OOFM_FIXED; + else + lout::misc::assertNotReached (); - widget->setParent (containingBlock); + widget->setParent (oofContainer[oofmIndex]); widget->setGenerator (this); - containingBlock->outOfFlowMgr->addWidgetOOF (widget, this, - words->size ()); + int oofmSubRef = + searchOutOfFlowMgr(oofmIndex)->addWidgetOOF (widget, this, + words->size ()); + widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef); + + DBG_OBJ_MSGF ("construct.word", 1, + "ouf of flow: oofmIndex = %d, oofmSubRef = %d => " + "parentRef = %d", + oofmIndex, oofmSubRef, widget->parentRef); + Word *word = addWord (0, 0, 0, 0, style); word->content.type = core::Content::WIDGET_OOF_REF; word->content.widget = widget; @@ -2351,14 +2269,16 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) // problems with breaking near float definitions.) setBreakOption (word, style, 0, 0, false); } else { - PRINTF (" -> within flow.\n"); + DBG_OBJ_MSG ("construct.word", 1, "in flow"); widget->setParent (this); // TODO Replace (perhaps) later "textblock" by "OOF aware widget". - if (widget->instanceOf (Textblock::CLASS_ID)) - containingBlock->outOfFlowMgr->addWidgetInFlow ((Textblock*)widget, - this, words->size ()); + if (widget->instanceOf (Textblock::CLASS_ID)) { + for (int i = 0; i < NUM_OOFM; i++) + searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this, + words->size ()); + } core::Requisition size; calcWidgetSize (widget, &size); @@ -2596,7 +2516,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; @@ -2607,7 +2527,7 @@ void Textblock::addParbreak (int space, core::style::Style *style) if (!isfirst) { /* The text block we searched for has been found. */ Word *word2; - int lineno = OutOfFlowMgr::getLineNoFromRef (widget->parentRef); + int lineno = getWidgetInFlowSubRef (widget); if (lineno > 0 && (word2 = @@ -2616,8 +2536,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; } } @@ -2722,7 +2641,7 @@ void Textblock::breakAdded () * This is an optimized version of the general * dw::core::Widget::getWidgetAtPoint method. */ -core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level) +core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level) { //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n", // 3 * level, "", getClassName (), this, allocation.x, allocation.y, @@ -2741,8 +2660,7 @@ 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; + Widget *oofWidget = getWidgetOOFAtPoint (x, y, level); if (oofWidget) return oofWidget; @@ -2896,13 +2814,13 @@ void Textblock::queueDrawRange (int index1, int index2) } } -void Textblock::setVerticalOffset (int verticalOffset) +void Textblock::setClearPosition (int clearPosition) { - DBG_OBJ_ENTER ("resize", 0, "setVerticalOffset", "%d", verticalOffset); + DBG_OBJ_ENTER ("resize", 0, "setClearPosition", "%d", clearPosition); - if (this->verticalOffset != verticalOffset) { - this->verticalOffset = verticalOffset; - DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset); + if (this->clearPosition != clearPosition) { + this->clearPosition = clearPosition; + DBG_OBJ_SET_NUM ("clearPosition", clearPosition); mustQueueResize = true; queueDraw (); // Could perhaps be optimized. } @@ -2911,7 +2829,7 @@ void Textblock::setVerticalOffset (int verticalOffset) } /** - * Called by dw::OutOfFlowMgr when the border has changed due to a + * Called by dw::OOFFloatsMgr when the border has changed due to a * float (or some floats). * * "y", which given in widget coordinates, denotes the minimal @@ -3040,7 +2958,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) @@ -3067,7 +2985,7 @@ void Textblock::oofSizeChanged (bool extremesChanged) extremesChanged ? "true" : "false"); queueResize (-1, extremesChanged); - // See Textblock::getAvailWidthForChild(): Extremes changes may become also + // See Textblock::getAvailWidthOfChild(): Extremes changes may become also // relevant for the children, under certain conditions: if (extremesChanged && !mustBeWidenedToAvailWidth ()) containerSizeChanged (); @@ -3075,6 +2993,21 @@ void Textblock::oofSizeChanged (bool extremesChanged) DBG_OBJ_LEAVE (); } +int Textblock::getLineBreakWidth () +{ + return lineBreakWidth; +} + +bool Textblock::isPossibleContainer (int oofmIndex) +{ + return true; +} + +bool Textblock::isPossibleContainerParent (int oofmIndex) +{ + return true; +} + Textblock *Textblock::getTextblockForLine (Line *line) { return getTextblockForLine (line->firstWord, line->lastWord); @@ -3128,19 +3061,16 @@ int Textblock::yOffsetOfPossiblyMissingLine (int lineNo) int result; if (lineNo == 0) { - result = verticalOffset + getStyle()->boxOffsetY(); - DBG_OBJ_MSGF ("line.yoffset", 1, "first line: %d + %d = %d", - verticalOffset, getStyle()->boxOffsetY(), result); + result = boxOffsetY(); + DBG_OBJ_MSGF ("line.yoffset", 1, "first line: %d", result); } else { Line *prevLine = lines->getRef (lineNo - 1); - result = verticalOffset + getStyle()->boxOffsetY() + - prevLine->top + prevLine->boxAscent + prevLine->boxDescent + - prevLine->breakSpace; + result = boxOffsetY() + prevLine->top + prevLine->boxAscent + + prevLine->boxDescent + prevLine->breakSpace; DBG_OBJ_MSGF ("line.yoffset", 1, - "other line: %d + %d + %d + (%d + %d) + %d = %d", - verticalOffset, getStyle()->boxOffsetY(), - prevLine->top, prevLine->boxAscent, prevLine->boxDescent, - prevLine->breakSpace, result); + "other line: %d + %d + (%d + %d) + %d = %d", + boxOffsetY(), prevLine->top, prevLine->boxAscent, + prevLine->boxDescent, prevLine->breakSpace, result); } DBG_OBJ_LEAVE (); diff --git a/dw/textblock.hh b/dw/textblock.hh index e7ff5c63..d376ba48 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -3,8 +3,7 @@ #include <limits.h> -#include "core.hh" -#include "outofflowmgr.hh" +#include "oofawarewidget.hh" #include "../lout/misc.hh" // These were used when improved line breaking and hyphenation were implemented. @@ -124,7 +123,7 @@ namespace dw { * * dw::Textblock makes use of incremental resizing as described in \ref * dw-widget-sizes. The parentRef is, for children of a dw::Textblock, simply - * the number of the line. + * the number of the line. [<b>Update:</b> Incorrect; see \ref dw-out-of-flow.] * * Generally, there are three cases which may change the size of the * widget: @@ -152,7 +151,7 @@ namespace dw { * necessary, or otherwise the line from which a rewrap is necessary. * */ -class Textblock: public core::Widget +class Textblock: public oof::OOFAwareWidget { private: /** @@ -246,10 +245,8 @@ private: static const char *hyphenDrawChar; - Textblock *containingBlock; - OutOfFlowMgr *outOfFlowMgr; - protected: + /** * \brief Implementation used for words. */ @@ -450,27 +447,24 @@ protected: int wordIndex; }; - class TextblockIterator: public core::Iterator + class TextblockIterator: public OOFAwareWidgetIterator { - private: - bool oofm; - int index; + protected: + int numContentsInFlow (); + void getContentInFlow (int index, core::Content *content); public: TextblockIterator (Textblock *textblock, core::Content::Type mask, bool atEnd); - TextblockIterator (Textblock *textblock, core::Content::Type mask, - bool oofm, int index); + + static TextblockIterator *createWordIndexIterator + (Textblock *textblock, core::Content::Type mask, int wordIndex); lout::object::Object *clone(); - int compareTo(lout::object::Comparable *other); - bool next (); - bool prev (); void highlight (int start, int end, core::HighlightLayer layer); void unhighlight (int direction, core::HighlightLayer layer); void getAllocation (int start, int end, core::Allocation *allocation); - void print (); }; friend class TextblockIterator; @@ -528,8 +522,9 @@ protected: /* This value is (currently) set by setAscent(). */ int lineBreakWidth; - // Additional vertical offset, used for the "clear" attribute. - int verticalOffset; + // Vertical offset at the top, used for the "clear" attribute. Goes + // into "extraSpace". + int clearPosition; int wrapRefLines, wrapRefParagraphs; /* 0-based. Important: Both are the line numbers, not @@ -578,7 +573,7 @@ protected: void calcBorders (int lastOofRef, int height); void showMissingLines (); void removeTemporaryLines (); - void setVerticalOffset (int verticalOffset); + void setClearPosition (int clearPosition); void decorateText (core::View *view, core::style::Style *style, core::style::Color::Shading shading, @@ -716,6 +711,7 @@ protected: void processWord (int wordIndex); virtual int wordWrap (int wordIndex, bool wrapAll); int wrapWordInFlow (int wordIndex, bool wrapAll); + int wrapWordOofRef (int wordIndex, bool wrapAll); void balanceBreakPosAndHeight (int wordIndex, int firstIndex, int *searchUntil, bool tempNewLine, int penaltyIndex, bool borderIsCalculated, @@ -753,7 +749,12 @@ protected: void sizeRequestImpl (core::Requisition *requisition); void getExtremesImpl (core::Extremes *extremes); void sizeAllocateImpl (core::Allocation *allocation); - int getAvailWidthOfChild (Widget *child, bool forceValue); + + void calcExtraSpaceImpl (); + + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + void containerSizeChangedForChildren (); bool affectsSizeChangeContainerChild (Widget *child); bool usesAvailWidth (); @@ -762,9 +763,6 @@ protected: void markSizeChange (int ref); void markExtremesChange (int ref); - void notifySetAsTopLevel(); - void notifySetParent(); - bool isBlockLevel (); void draw (core::View *view, core::Rectangle *area); @@ -783,17 +781,23 @@ protected: core::style::Style *style, int numBreaks, int *breakPos, core::Requisition *wordSize); - static bool isContainingBlock (Widget *widget); inline bool mustBeWidenedToAvailWidth () { DBG_OBJ_ENTER0 ("resize", 0, "mustBeWidenedToAvailWidth"); bool toplevel = getParent () == NULL, block = getStyle()->display == core::style::DISPLAY_BLOCK, - vloat = getStyle()->vloat != core::style::FLOAT_NONE, - result = toplevel || (block && !vloat); - DBG_OBJ_MSGF ("resize", 0, "=> %s (toplevel: %s, block: %s, float: %s)", + vloat = testWidgetFloat (this), + abspos = testWidgetAbsolutelyPositioned (this), + fixpos = testWidgetFixedlyPositioned (this), + // In detail, this depends on what the respective OOFM does + // with the child widget: + result = toplevel || (block && !(vloat || abspos || fixpos)); + DBG_OBJ_MSGF ("resize", 0, + "=> %s (toplevel: %s, block: %s, float: %s, abspos: %s, " + "fixpos: %s)", result ? "true" : "false", toplevel ? "true" : "false", - block ? "true" : "false", vloat ? "true" : "false"); + block ? "true" : "false", vloat ? "true" : "false", + abspos ? "true" : "false", fixpos ? "true" : "false"); DBG_OBJ_LEAVE (); return result; } @@ -808,8 +812,8 @@ public: static void setPenaltyEmDashRight2 (int penaltyRightEmDash2); static void setStretchabilityFactor (int stretchabilityFactor); - Textblock(bool limitTextWidth); - ~Textblock(); + Textblock (bool limitTextWidth); + ~Textblock (); core::Iterator *iterator (core::Content::Type mask, bool atEnd); @@ -835,7 +839,9 @@ public: void borderChanged (int y, core::Widget *vloat); void oofSizeChanged (bool extremesChanged); - inline int getLineBreakWidth () { return lineBreakWidth; } + int getLineBreakWidth (); + bool isPossibleContainer (int oofmIndex); + bool isPossibleContainerParent (int oofmIndex); }; #define DBG_SET_WORD_PENALTY(n, i, is) \ diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc index c09d9a75..34a76c08 100644 --- a/dw/textblock_iterator.cc +++ b/dw/textblock_iterator.cc @@ -33,173 +33,35 @@ namespace dw { Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, core::Content::Type mask, bool atEnd): - core::Iterator (textblock, mask, atEnd) + OOFAwareWidgetIterator (textblock, mask, atEnd, textblock->words->size ()) { - if (atEnd) { - if (textblock->outOfFlowMgr) { - oofm = true; - index = textblock->outOfFlowMgr->getNumWidgets(); - } else { - oofm = false; - index = textblock->words->size(); - } - } else { - oofm = false; - index = -1; - } - - content.type = atEnd ? core::Content::END : core::Content::START; } -Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, - core::Content::Type mask, - bool oofm, int index): - core::Iterator (textblock, mask, false) +Textblock::TextblockIterator + *Textblock::TextblockIterator::createWordIndexIterator (Textblock *textblock, + core::Content::Type + mask, + int wordIndex) { - this->oofm = oofm; - this->index = index; - - // TODO To be completely exact, oofm should be considered here. - if (index < 0) - content.type = core::Content::START; - else if (index >= textblock->words->size()) - content.type = core::Content::END; - else - content = textblock->words->getRef(index)->content; + TextblockIterator *tbIt = new TextblockIterator (textblock, mask, false); + tbIt->setValues (0, wordIndex); + return tbIt; } object::Object *Textblock::TextblockIterator::clone() { - return - new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index); -} - -int Textblock::TextblockIterator::compareTo(object::Comparable *other) -{ - TextblockIterator *otherTI = (TextblockIterator*)other; - - if (oofm && !otherTI->oofm) - return +1; - else if (!oofm && otherTI->oofm) - return -1; - else - return index - otherTI->index; -} - -bool Textblock::TextblockIterator::next () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::END) - return false; - - short type; - - do { - index++; - - if (oofm) { - // Iterating over OOFM. - if (index >= textblock->outOfFlowMgr->getNumWidgets()) { - // End of OOFM list reached. - content.type = core::Content::END; - return false; - } - type = core::Content::WIDGET_OOF_CONT; - } else { - // Iterating over words list. - if (index < textblock->words->size ()) - // Still words left. - type = textblock->words->getRef(index)->content.type; - else { - // End of words list reached. - if (textblock->outOfFlowMgr) { - oofm = true; - index = 0; - if (textblock->outOfFlowMgr->getNumWidgets() > 0) - // Start with OOFM widgets. - type = core::Content::WIDGET_OOF_CONT; - else { - // No OOFM widgets (number is 0). - content.type = core::Content::END; - return false; - } - } else { - // No OOFM widgets (no OOFM agt all). - content.type = core::Content::END; - return false; - } - } - } - } while ((type & getMask()) == 0); - - if (oofm) { - content.type = core::Content::WIDGET_OOF_CONT; - content.widget = textblock->outOfFlowMgr->getWidget (index); - } else - content = textblock->words->getRef(index)->content; - - return true; -} - -bool Textblock::TextblockIterator::prev () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::START) - return false; - - short type; - - do { - index--; - - if (oofm) { - // Iterating over OOFM. - if (index >= 0) - // Still widgets left. - type = core::Content::WIDGET_OOF_CONT; - else { - // Beginning of OOFM list reached. Continue with words. - oofm = false; - index = textblock->words->size() - 1; - if (index < 0) { - // There are no words. (Actually, this case should not - // happen: When there are OOF widgets, ther must be OOF - // references, or widgets in flow, which contain - // references. - content.type = core::Content::END; - return false; - } - type = textblock->words->getRef(index)->content.type; - } - } else { - // Iterating over words list. - if (index < 0) { - // Beginning of words list reached. - content.type = core::Content::START; - return false; - } - type = textblock->words->getRef(index)->content.type; - } - } while ((type & getMask()) == 0); - - if (oofm) { - content.type = core::Content::WIDGET_OOF_CONT; - content.type = false; - content.widget = textblock->outOfFlowMgr->getWidget (index); - } else - content = textblock->words->getRef(index)->content; - - return true; + TextblockIterator *tbIt = + new TextblockIterator ((Textblock*)getWidget(), getMask(), false); + cloneValues (tbIt); + return tbIt; } void Textblock::TextblockIterator::highlight (int start, int end, core::HighlightLayer layer) { - if (!oofm) { + if (inFlow ()) { Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; + int index = getInFlowIndex (), index1 = index, index2 = index; int oldStartIndex = textblock->hlStart[layer].index; int oldStartChar = textblock->hlStart[layer].nChar; @@ -229,17 +91,16 @@ void Textblock::TextblockIterator::highlight (int start, int end, oldEndIndex != textblock->hlEnd[layer].index || oldEndChar != textblock->hlEnd[layer].nChar) textblock->queueDrawRange (index1, index2); - } - - // TODO What about OOF widgets? + } else + highlightOOF (start, end, layer); } void Textblock::TextblockIterator::unhighlight (int direction, core::HighlightLayer layer) { - if (!oofm) { + if (inFlow ()) { Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; + int index = getInFlowIndex (), index1 = index, index2 = index; if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) return; @@ -269,22 +130,17 @@ void Textblock::TextblockIterator::unhighlight (int direction, oldEndIndex != textblock->hlEnd[layer].index || oldEndChar != textblock->hlEnd[layer].nChar) textblock->queueDrawRange (index1, index2); - } - - // TODO What about OOF widgets? + } else + unhighlightOOF (direction, layer); } void Textblock::TextblockIterator::getAllocation (int start, int end, core::Allocation *allocation) { - Textblock *textblock = (Textblock*)getWidget(); - - if (oofm) { - // TODO Consider start and end? - *allocation = - *(textblock->outOfFlowMgr->getWidget(index)->getAllocation()); - } else { - int lineIndex = textblock->findLineOfWord (index); + if (inFlow ()) { + Textblock *textblock = (Textblock*)getWidget(); + int index = getInFlowIndex (), + lineIndex = textblock->findLineOfWord (index); Line *line = textblock->lines->getRef (lineIndex); Word *word = textblock->words->getRef (index); @@ -323,14 +179,19 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, } allocation->ascent = word->size.ascent; allocation->descent = word->size.descent; - } + } else + getAllocationOOF (start, end, allocation); } -void Textblock::TextblockIterator::print () +int Textblock::TextblockIterator::numContentsInFlow () { - Iterator::print (); - printf (", oofm = %s, index = %d", oofm ? "true" : "false", index); + return ((Textblock*)getWidget())->words->size (); +} +void Textblock::TextblockIterator::getContentInFlow (int index, + core::Content *content) +{ + *content = ((Textblock*)getWidget())->words->getRef(index)->content; } } // namespace dw diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index c507cb68..af8fd33d 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -570,7 +570,7 @@ int Textblock::wordWrap (int wordIndex, bool wrapAll) int n; if (word->content.type == core::Content::WIDGET_OOF_REF) - n = 0; + n = wrapWordOofRef (wordIndex, wrapAll); else n = wrapWordInFlow (wordIndex, wrapAll); @@ -733,14 +733,15 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll) startSearch, breakPos); for (int i = startSearch; newFloatPos == -1 && i <= breakPos; i++) { core::Content *content = &(words->getRef(i)->content); - if (content->type == core::Content::WIDGET_OOF_REF && - // Later, absolutepositioned elements (which do not affect - // borders) can be ignored at this point. - (containingBlock->outOfFlowMgr->affectsLeftBorder - (content->widget) || - containingBlock->outOfFlowMgr->affectsRightBorder - (content->widget))) - newFloatPos = i; + if (content->type == core::Content::WIDGET_OOF_REF) { + for (int j = 0; newFloatPos == -1 && j < NUM_OOFM; j++) { + if ((searchOutOfFlowMgr(j)->affectsLeftBorder(content + ->widget) || + searchOutOfFlowMgr(j)->affectsRightBorder (content + ->widget))) + newFloatPos = i; + } + } } DBG_OBJ_MSGF ("construct.word", 2, "newFloatPos = %d", newFloatPos); @@ -751,10 +752,17 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll) floatHandled = true; // Step 2: position the float and re-calculate the line. - lastFloatPos = newFloatPos; - containingBlock->outOfFlowMgr->tellPosition - (words->getRef(lastFloatPos)->content.widget, yNewLine); + // TODO "x" is not quite correct, but this does not matter + // (currently?). + + lastFloatPos = newFloatPos; + + Widget *widget = words->getRef(lastFloatPos)->content.widget; + oof::OutOfFlowMgr *oofm = + searchOutOfFlowMgr (getWidgetOOFIndex (widget)); + if (oofm && oofm->mayAffectBordersAtAll ()) + oofm->tellPosition (widget, boxOffsetX (), yNewLine); balanceBreakPosAndHeight (wordIndex, firstIndex, &searchUntil, tempNewLine, penaltyIndex, false, @@ -820,8 +828,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll) firstWordWithoutLine = lines->getLastRef()->lastWord + 1; if (wordIndex >= firstWordWithoutLine) { - word->content.widget->parentRef = - OutOfFlowMgr::createRefNormalFlow (lines->size ()); + word->content.widget->parentRef = makeParentRefInFlow (lines->size ()); PRINTF ("The %s %p is assigned parentRef = %d.\n", word->content.widget->getClassName(), word->content.widget, word->content.widget->parentRef); @@ -833,6 +840,29 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll) return diffWords; } +int Textblock::wrapWordOofRef (int wordIndex, bool wrapAll) +{ + DBG_OBJ_ENTER ("construct.word", 0, "wrapWordOofRef", "%d, %s", + wordIndex, wrapAll ? "true" : "false"); + + Word *word = words->getRef (wordIndex); + Widget *widget = word->content.widget; + int yNewLine = yOffsetOfPossiblyMissingLine (lines->size ()); + + // Floats, which affect either border, are handled in wrapWordInFlow; this + // is rather for positioned elements. + oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (getWidgetOOFIndex (widget)); + DBG_OBJ_MSGF ("construct.word", 1, "parentRef = %d, oofm = %p", + widget->parentRef, oofm); + if (oofm && !oofm->mayAffectBordersAtAll ()) + // TODO Again, "x" is not correct (see above). + oofm->tellPosition (widget, boxOffsetX (), yNewLine); + + DBG_OBJ_LEAVE (); + + return 0; // Words list not changed. +} + // *height must be initialized, but not *breakPos. // *wordIndexEnd must be initialized (initially to wordIndex) void Textblock::balanceBreakPosAndHeight (int wordIndex, int firstIndex, @@ -1414,8 +1444,9 @@ void Textblock::moveWordIndices (int wordIndex, int num, int *addIndex1) DBG_OBJ_ENTER ("construct.word", 0, "moveWordIndices", "%d, %d", wordIndex, num); - if (containingBlock->outOfFlowMgr) - containingBlock->outOfFlowMgr->moveExternalIndices (this, wordIndex, num); + for (int i = 0; i < NUM_OOFM; i++) + if (searchOutOfFlowMgr(i)) + searchOutOfFlowMgr(i)->moveExternalIndices (this, wordIndex, num); for (int i = lines->size () - 1; i >= 0; i--) { Line *line = lines->getRef (i); @@ -1503,8 +1534,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex) + word->content.widget->getStyle()->margin.top - collapseMarginTop); - word->content.widget->parentRef = - OutOfFlowMgr::createRefNormalFlow (lineIndex); + word->content.widget->parentRef = makeParentRefInFlow (lineIndex); } else { line->marginDescent = misc::max (line->marginDescent, line->boxDescent); @@ -1618,8 +1648,7 @@ int Textblock::calcLineBreakWidth (int lineIndex) if (limitTextWidth && layout->getUsesViewport () && // margin/border/padding will be subtracted later, via OOFM. - lineBreakWidth - getStyle()->boxDiffWidth() - > layout->getWidthViewport () - 10) + lineBreakWidth - boxDiffWidth() > layout->getWidthViewport () - 10) lineBreakWidth = layout->getWidthViewport () - 10; if (lineIndex == 0) lineBreakWidth -= line1OffsetEff; @@ -1631,8 +1660,8 @@ int Textblock::calcLineBreakWidth (int lineIndex) } else leftBorder = rightBorder = 0; - leftBorder = misc::max (leftBorder, getStyle()->boxOffsetX()); - rightBorder = misc::max (rightBorder, getStyle()->boxRestWidth()); + leftBorder = misc::max (leftBorder, boxOffsetX()); + rightBorder = misc::max (rightBorder, boxRestWidth()); lineBreakWidth -= (leftBorder + rightBorder); @@ -1909,12 +1938,16 @@ void Textblock::initNewLine () // At the very beginning, in Textblock::Textblock, where this // method is called, containingBlock is not yet defined. - if (containingBlock && containingBlock->outOfFlowMgr) { - if (lines->size () == 0) { - int clearPosition = - containingBlock->outOfFlowMgr->getClearPosition (this); - setVerticalOffset (misc::max (clearPosition, 0)); - } + if (lines->size () == 0) { + int clearPosition = 0; + + for (int i = 0; i < NUM_OOFM; i++) + if (searchOutOfFlowMgr(i)) + clearPosition = + misc::max (clearPosition, + searchOutOfFlowMgr(i)->getClearPosition (this)); + + setClearPosition (misc::max (clearPosition, 0)); } calcBorders (lines->size() > 0 ? @@ -1934,81 +1967,97 @@ void Textblock::calcBorders (int lastOofRef, int height) DBG_OBJ_ENTER ("construct.line", 0, "calcBorders", "%d, %d", lastOofRef, height); - if (containingBlock && containingBlock->outOfFlowMgr) { - // Consider the example: - // - // <div> - // Some text A ... - // <p> Some text B ... <img style="float:right" ...> </p> - // Some more text C ... - // </div> - // - // If the image is large enough, it should float around the last - // paragraph, "Some more text C ...": - // - // Some more text A ... - // - // Some more ,---------. - // text B ... | | - // | <img> | - // Some more | | <---- Consider this line! - // text C ... '---------' - // - // Since this float is generated in the <p> element, not in the- - // <div> element, and since they are represented by different - // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine, - // and so lastOofRef, is -1 for the line marked with an arrow; - // this would result in ignoring the float, because -1 is - // equivalent to the very beginning of the <div> element ("Some - // more text A ..."), which is not affected by the float. - // - // On the other hand, the only relevant values of - // Line::lastOofRefPositionedBeforeThisLine are those greater - // than the first word of the new line, so a solution is to use - // the maximum of both. + newLineHasFloatLeft = newLineHasFloatRight = false; + newLineLeftBorder = newLineRightBorder = 0; + newLineLeftFloatHeight = newLineRightFloatHeight = 0; + bool oofmDefined = false; + for (int i = 0; i < NUM_OOFM && !oofmDefined; i++) + if (searchOutOfFlowMgr(i)) + oofmDefined = true; - int firstWordOfLine = lines->size() > 0 ? - lines->getLastRef()->lastWord + 1 : 0; + if (oofmDefined) { + int firstWordOfLine = + lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0; int effOofRef = misc::max (lastOofRef, firstWordOfLine - 1); - int y = yOffsetOfPossiblyMissingLine (lines->size ()); - - newLineHasFloatLeft = - containingBlock->outOfFlowMgr->hasFloatLeft (this, y, height, this, - effOofRef); - newLineHasFloatRight = - containingBlock->outOfFlowMgr->hasFloatRight (this, y, height, this, - effOofRef); - newLineLeftBorder = - containingBlock->outOfFlowMgr->getLeftBorder (this, y, height, this, - effOofRef); - newLineRightBorder = - containingBlock->outOfFlowMgr->getRightBorder (this, y, height, this, - effOofRef); - newLineLeftFloatHeight = newLineHasFloatLeft ? - containingBlock->outOfFlowMgr->getLeftFloatHeight (this, y, height, - this, effOofRef) : - 0; - newLineRightFloatHeight = newLineHasFloatRight ? - containingBlock->outOfFlowMgr->getRightFloatHeight (this, y, height, - this, effOofRef) : - 0; - - DBG_OBJ_MSGF ("construct.line", 1, - "%d * %d (%s) / %d * %d (%s), at %d (%d), until %d = " - "max (%d, %d - 1)", - newLineLeftBorder, newLineLeftFloatHeight, - newLineHasFloatLeft ? "true" : "false", - newLineRightBorder, newLineRightFloatHeight, - newLineHasFloatRight ? "true" : "false", - y, height, effOofRef, lastOofRef, firstWordOfLine); - } else { - newLineHasFloatLeft = newLineHasFloatRight = false; - newLineLeftBorder = newLineRightBorder = 0; - newLineLeftFloatHeight = newLineRightFloatHeight = 0; - - DBG_OBJ_MSG ("construct.line", 0, "<i>no CB of OOFM</i>"); + + for (int i = 0; i < NUM_OOFM; i++) { + oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr(i); + if (oofm) { + // Consider the example: + // + // <div> + // Some text A ... + // <p> Some text B ... <img style="float:right" ...> </p> + // Some more text C ... + // </div> + // + // If the image is large enough, it should float around the last + // paragraph, "Some more text C ...": + // + // Some more text A ... + // + // Some more ,---------. + // text B ... | | + // | <img> | + // Some more | | <---- Consider this line! + // text C ... '---------' + // + // Since this float is generated in the <p> element, not in the- + // <div> element, and since they are represented by different + // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine, + // and so lastOofRef, is -1 for the line marked with an arrow; + // this would result in ignoring the float, because -1 is + // equivalent to the very beginning of the <div> element ("Some + // more text A ..."), which is not affected by the float. + // + // On the other hand, the only relevant values of + // Line::lastOofRefPositionedBeforeThisLine are those greater + // than the first word of the new line, so a solution is to use + // the maximum of both. + + bool thisHasLeft, thisHasRight; + + thisHasLeft = oofm->hasFloatLeft (this, y, height, this, effOofRef); + newLineHasFloatLeft = newLineHasFloatLeft || thisHasLeft; + thisHasRight = oofm->hasFloatRight (this, y, height, this, + effOofRef); + newLineHasFloatRight = newLineHasFloatRight || thisHasRight; + + newLineLeftBorder = + misc::max (newLineLeftBorder, + oofm->getLeftBorder (this, y, height, this, + effOofRef)); + newLineRightBorder = + misc::max (newLineRightBorder, + oofm->getRightBorder (this, y, height, this, + effOofRef)); + + // TODO "max" is not really correct for the heights. (Does + // not matter, since only one, the float manager, returns + // meaningful values.) + if (thisHasLeft) + newLineLeftFloatHeight = + misc::max (newLineLeftFloatHeight, + oofm->getLeftFloatHeight (this, y, height, this, + effOofRef)); + if (thisHasRight) + newLineRightFloatHeight = + misc::max (newLineRightFloatHeight, + oofm->getRightFloatHeight (this, y, height, this, + effOofRef)); + + DBG_OBJ_MSGF ("construct.line", 1, + "OOFM #%d: %d * %d (%s) / %d * %d (%s), at %d (%d), " + "until %d = max (%d, %d - 1)", + i, newLineLeftBorder, newLineLeftFloatHeight, + newLineHasFloatLeft ? "true" : "false", + newLineRightBorder, newLineRightFloatHeight, + newLineHasFloatRight ? "true" : "false", + y, height, effOofRef, lastOofRef, firstWordOfLine); + } + } } DBG_OBJ_SET_BOOL ("newLineHasFloatLeft", newLineHasFloatLeft); diff --git a/dw/types.hh b/dw/types.hh index 36d6caa1..081b8db4 100644 --- a/dw/types.hh +++ b/dw/types.hh @@ -207,6 +207,10 @@ struct Content WIDGET_OOF_REF = 1 << 5, BREAK = 1 << 6, + /** \brief can be used internally, but should never be exposed, + e. g. by iterators */ + INVALID = 1 << 7, + ALL = 0xff, REAL_CONTENT = 0xff ^ (START | END), SELECTION_CONTENT = TEXT | BREAK, // WIDGET_* must be set additionally diff --git a/dw/widget.cc b/dw/widget.cc index f740df00..993c4f9c 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -91,6 +91,8 @@ Widget::Widget () deleteCallbackFunc = NULL; widgetImgRenderer = NULL; + + stackingContextMgr = NULL; } Widget::~Widget () @@ -104,6 +106,9 @@ Widget::~Widget () delete widgetImgRenderer; } + if (stackingContextMgr) + delete stackingContextMgr; + if (style) style->unref (); @@ -170,6 +175,17 @@ void Widget::setParent (Widget *parent) // Textblock. DBG_OBJ_SET_PTR ("container", container); + // If at all, stackingContextMgr should have set *before*, see also + // Widget::setStyle() and Layout::addWidget(). + if (stackingContextMgr) { + Widget *stackingContextWidget = parent; + while (stackingContextWidget && + stackingContextWidget->stackingContextMgr == NULL) + stackingContextWidget = stackingContextWidget->parent; + assert (stackingContextWidget); + stackingContextWidget->stackingContextMgr->addChildSCWidget (this); + } + notifySetParent(); } @@ -496,6 +512,7 @@ void Widget::sizeRequest (Requisition *requisition) } if (needsResize ()) { + calcExtraSpace (); /** \todo Check requisition == &(this->requisition) and do what? */ sizeRequestImpl (requisition); this->requisition = *requisition; @@ -625,7 +642,7 @@ int Widget::getAvailHeight (bool forceValue) } else if (style::isPerLength (getStyle()->height)) { DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%", 100 * style::perLengthVal_useThisOnlyForDebugging - (getStyle()->height)); + (getStyle()->height)); // Notice that here -- unlike getAvailWidth() -- // layout->hScrollbarThickness is not considered here; // something like canvasWidthGreater (analogue to @@ -906,6 +923,8 @@ void Widget::getExtremes (Extremes *extremes) } if (extremesChanged ()) { + calcExtraSpace (); + // For backward compatibility (part 1/2): extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1; @@ -935,6 +954,24 @@ void Widget::getExtremes (Extremes *extremes) } /** + * \brief Calculates dw::core::Widget::extraSpace. + * + * Delegated to dw::core::Widget::calcExtraSpaceImpl. Called both from + * dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes. + */ +void Widget::calcExtraSpace () +{ + extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0; + calcExtraSpaceImpl (); + + DBG_OBJ_SET_NUM ("extraSpace.top", extraSpace.top); + DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom); + DBG_OBJ_SET_NUM ("extraSpace.left", extraSpace.left); + DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right); + +} + +/** * \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when * needed. */ @@ -1078,6 +1115,15 @@ void Widget::setStyle (style::Style *style) layout->updateCursor (); } + // After Layout::addWidget() (as toplevel widget) or Widget::setParent() + // (which also sets layout), changes of the style cannot be considered + // anymore. (Should print a warning?) + if (layout == NULL && + StackingContextMgr::isEstablishingStackingContext (this)) { + stackingContextMgr = new StackingContextMgr (this); + DBG_OBJ_ASSOC_CHILD (stackingContextMgr); + } + if (sizeChanged) queueResize (0, true); else @@ -1211,8 +1257,10 @@ void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse) canvasArea.width = area->width; canvasArea.height = area->height; - style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y, - allocation.width, getHeight (), style, inverse); + int xMar, yMar, widthMar, heightMar; + getMarginArea (&xMar, &yMar, &widthMar, &heightMar); + style::drawBorder (view, layout, &canvasArea, xMar, yMar, widthMar, + heightMar, style, inverse); int xPad, yPad, widthPad, heightPad; getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); @@ -1386,6 +1434,24 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos, x + allocation.x, y + allocation.y, width, height); } +void Widget::getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar) +{ + *xMar = allocation.x + extraSpace.left; + *yMar = allocation.y + extraSpace.top; + *widthMar = allocation.width - (extraSpace.left + extraSpace.right); + *heightMar = getHeight () - (extraSpace.top + extraSpace.bottom); +} + +void Widget::getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor) +{ + getMarginArea (xBor, yBor, widthBor, heightBor); + + *xBor += style->margin.left; + *yBor += style->margin.top; + *widthBor -= style->margin.left + style->margin.right; + *heightBor -= style->margin.top + style->margin.bottom; +} + /** * \brief Return the padding area (content plus padding). * @@ -1395,18 +1461,31 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos, void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad) { - *xPad = allocation.x + style->margin.left + style->borderWidth.left; - *yPad = allocation.y + style->margin.top + style->borderWidth.top; - *widthPad = allocation.width - style->margin.left - style->borderWidth.left - - style->margin.right - style->borderWidth.right; - *heightPad = getHeight () - style->margin.top - style->borderWidth.top - - style->margin.bottom - style->borderWidth.bottom; + getBorderArea (xPad, yPad, widthPad, heightPad); + + *xPad += style->borderWidth.left; + *yPad += style->borderWidth.top; + *widthPad -= style->borderWidth.left + style->borderWidth.right; + *heightPad -= style->borderWidth.top + style->borderWidth.bottom; } void Widget::sizeAllocateImpl (Allocation *allocation) { } +/** + * \brief The actual implementation for calculating + * dw::core::Widget::extraSpace. + * + * The implementation gets a clean value of + * dw::core::Widget::extraSpace, which is only corrected. To make sure + * all possible influences are considered, the implementation of the + * base class should be called, too. + */ +void Widget::calcExtraSpaceImpl () +{ +} + void Widget::markSizeChange (int ref) { } diff --git a/dw/widget.hh b/dw/widget.hh index 0f3e2d37..ca98308e 100644 --- a/dw/widget.hh +++ b/dw/widget.hh @@ -180,19 +180,27 @@ protected: Allocation allocation; inline int getHeight () { return allocation.ascent + allocation.descent; } - inline int getContentWidth() { return allocation.width - - style->boxDiffWidth (); } - inline int getContentHeight() { return getHeight () - - style->boxDiffHeight (); } + inline int getContentWidth() { return allocation.width - boxDiffWidth (); } + inline int getContentHeight() { return getHeight () - boxDiffHeight (); } Layout *layout; /** * \brief Space around the margin box. Allocation is extraSpace + - * margin + border + padding + contents; + * margin + border + padding + contents. + * + * See also dw::core::Widget::calcExtraSpace and + * dw::core::Widget::calcExtraSpaceImpl. Also, it is feasible to + * correct this value within dw::core::Widget::sizeRequestImpl. */ style::Box extraSpace; + /** + * \brief Set iff this widget constitutes a stacking context, as + * defined by CSS. + */ + StackingContextMgr *stackingContextMgr; + /*inline void printFlags () { DBG_IF_RTFL { char buf[10 * 3 - 1 + 1]; @@ -271,6 +279,8 @@ protected: */ virtual void getExtremesImpl (Extremes *extremes) = 0; + virtual void calcExtraSpaceImpl (); + /** * \brief See \ref dw-widget-sizes. */ @@ -292,8 +302,6 @@ protected: */ virtual void markExtremesChange (int ref); - int getMinWidth (Extremes *extremes, bool forceValue); - virtual int getAvailWidthOfChild (Widget *child, bool forceValue); virtual int getAvailHeightOfChild (Widget *child, bool forceValue); virtual void correctRequisitionOfChild (Widget *child, @@ -425,6 +433,8 @@ public: void getExtremes (Extremes *extremes); void sizeAllocate (Allocation *allocation); + void calcExtraSpace (); + int getAvailWidth (bool forceValue); int getAvailHeight (bool forceValue); virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; } @@ -441,6 +451,8 @@ public: virtual int applyPerWidth (int containerWidth, style::Length perWidth); virtual int applyPerHeight (int containerHeight, style::Length perHeight); + int getMinWidth (Extremes *extremes, bool forceValue); + virtual bool isBlockLevel (); virtual bool isPossibleContainer (); @@ -485,6 +497,8 @@ public: void scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height); + void getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar); + void getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor); void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad); /** diff --git a/src/cssparser.cc b/src/cssparser.cc index a8de027a..c400a8e6 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -218,7 +218,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"font-weight", {CSS_TYPE_ENUM, CSS_TYPE_FONT_WEIGHT, CSS_TYPE_UNUSED}, Css_font_weight_enum_vals}, {"height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, - {"left", {CSS_TYPE_UNUSED}, NULL}, + {"left", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, {"letter-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, Css_letter_spacing_enum_vals}, {"line-height", @@ -273,7 +273,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, {"word-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, Css_word_spacing_enum_vals}, - {"z-index", {CSS_TYPE_UNUSED}, NULL}, + {"z-index", {CSS_TYPE_INTEGER, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, /* These are extensions, for internal used, and never parsed. */ {"x-link", {CSS_TYPE_INTEGER, CSS_TYPE_UNUSED}, NULL}, @@ -789,9 +789,12 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type) return true; break; - case CSS_TYPE_UNUSED: case CSS_TYPE_INTEGER: - /* Not used for parser values. */ + if (ttype == CSS_TK_DECINT) + return true; + break; + + case CSS_TYPE_UNUSED: default: assert(false); break; @@ -1170,12 +1173,18 @@ bool CssParser::parseValue(CssPropertyName prop, } break; + case CSS_TYPE_INTEGER: + if (ttype == CSS_TK_DECINT) { + val->intVal = strtol(tval, NULL, 10); + ret = true; + nextToken(); + } + break; + case CSS_TYPE_UNUSED: /* nothing */ break; - case CSS_TYPE_INTEGER: - /* Not used for parser values. */ default: assert(false); /* not reached */ } diff --git a/src/styleengine.cc b/src/styleengine.cc index 1c90b7b7..8a90751e 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -725,6 +725,12 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, case CSS_PROPERTY_MAX_HEIGHT: computeLength (&attrs->maxHeight, p->value.intVal, attrs->font); break; + case CSS_PROPERTY_Z_INDEX: + if (p->type == CSS_LENGTH_TYPE_AUTO) + attrs->zIndex = dw::core::style::Z_INDEX_AUTO; + else + attrs->zIndex = p->value.intVal; + break; case PROPERTY_X_LINK: attrs->x_link = p->value.intVal; break; diff --git a/test/Makefile.am b/test/Makefile.am index 3b474466..fd3252dc 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,6 +25,7 @@ noinst_PROGRAMS = \ dw-resource-test \ dw-ui-test \ containers \ + identity \ shapes \ cookies \ liang \ @@ -191,6 +192,9 @@ shapes_LDADD = \ containers_SOURCES = containers.cc containers_LDADD = $(top_builddir)/lout/liblout.a +identity_SOURCES = identity.cc +identity_LDADD = $(top_builddir)/lout/liblout.a + cookies_SOURCES = cookies.c cookies_LDADD = \ $(top_builddir)/dpip/libDpip.a \ diff --git a/test/identity.cc b/test/identity.cc new file mode 100644 index 00000000..a1a136eb --- /dev/null +++ b/test/identity.cc @@ -0,0 +1,55 @@ +/* + * This small program tests how IdentifiableObject works with multiple + * inheritance ("diamond" inheritance, more precisely, since all + * classes have there root in IdentifiableObject.) + * + * Current status: With virtual superclasses, you get a class + * hierarchie "root -> A -> B -> C", so that the first part of this + * example works actually (C is a subclass of A and of B), but the + * second fails (it should print "false", but it is erroneously + * assumed that B is a subclass of A.) + */ + +#include "../lout/identity.hh" + +using namespace lout::identity; + +class A: virtual public IdentifiableObject +{ +public: + static int CLASS_ID; + inline A () { registerName ("A", &CLASS_ID); } +}; + +class B: virtual public IdentifiableObject +{ +public: + static int CLASS_ID; + inline B () { registerName ("B", &CLASS_ID); } +}; + +class C: public A, public B +{ +public: + static int CLASS_ID; + inline C () { registerName ("C", &CLASS_ID); } +}; + +int A::CLASS_ID = -1, B::CLASS_ID = -1, C::CLASS_ID = -1; + +int main (int argc, char *argv[]) +{ + printf ("A: %d, B: %d, C: %d\n", A::CLASS_ID, B::CLASS_ID, C::CLASS_ID); + + C x; + assert (x.instanceOf (A::CLASS_ID)); + assert (x.instanceOf (B::CLASS_ID)); + assert (x.instanceOf (C::CLASS_ID)); + printf ("x: %d\n", x.getClassId ()); + + B y; + printf ("y: %d; instance of A: %s\n", + y.getClassId (), y.instanceOf (B::CLASS_ID) ? "true" : "false"); + + return 0; +} |