diff options
61 files changed, 7526 insertions, 4069 deletions
@@ -41,6 +41,7 @@ ^test/dw-table$ ^test/dw-table-aligned$ ^test/dw-ui-test$ +^test/identity$ ^test/liang$ ^test/notsosimplevector$ ^test/shapes$ @@ -6,6 +6,15 @@ Here we list changes that are relatively significant and/or visible to the user. For a history of changes in full detail, see our Mercurial repository at http://hg.dillo.org/dillo +dillo_grows repository [to be merged] + ++- Absolutely positioned elements. + - Fixedly positioned elements (incomplete: referring to the canvas instead to + the viewport). + - "Z-index", stacking contexts. + Patches: Sebastian Geerken + +----------------------------------------------------------------------------- dillo-3.1 [not released yet] diff --git a/doc/Makefile.am b/doc/Makefile.am index 8ade3d15..7f627d09 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -13,6 +13,7 @@ EXTRA_DIST = \ dw-images-and-backgrounds.doc \ dw-dw-out-of-flow.doc \ dw-dw-out-of-flow-2.doc \ + dw-stacking-context.doc \ fltk-problems.doc \ rounding-errors.doc \ uml-legend.doc \ diff --git a/doc/dw-out-of-flow.doc b/doc/dw-out-of-flow.doc index ea4a52bc..b7ebee40 100644 --- a/doc/dw-out-of-flow.doc +++ b/doc/dw-out-of-flow.doc @@ -1,10 +1,35 @@ /** \page dw-out-of-flow Handling Elements Out Of Flow - <div style="border: 2px solid #ffff00; margin-bottom: 0.5em; padding: 0.5em 1em; background-color: #ffffe0"><b>Info:</b> Should be incorporated into dw::Textblock.</div> +<div style="border: 2px solid #ff4040; margin-bottom: 0.5em; +padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b> +Not up to date; incorporate these two changes: (i) there are different +containing blocks for floats and absolutely (furthermore also fixedly) +positioned elements; (ii) dw::OutOfFlowMgr is now only the base class: +floats and absolutely positioned elements are seperated: +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", dir="both"]; + fontname=Helvetica; fontsize=8; + + OutOfFlowMgr [URL="\ref dw::OutOfFlowMgr"]; + OOFFloatsMgr [URL="\ref dw::OOFFloatsMgr"]; + OOFPositionedMgr [URL="\ref dw::OOFPositionedMgr"]; + OOFPosAbsMgr [URL="\ref dw::OOFPosAbsMgr"]; + OOFPosFixedMgr [URL="\ref dw::OOFPosFixedMgr"]; + + OutOfFlowMgr -> OOFFloatsMgr; + OutOfFlowMgr -> OOFPositionedMgr; + OOFPositionedMgr -> OOFPosAbsMgr; + OOFPositionedMgr -> OOFPosFixedMgr; +} +\enddot +</div> + Introduction ============ @@ -209,6 +234,6 @@ Integration of line breaking and floats Absolute and fixed positiones ============================= -See <http://flpsed.org/hgweb/dillo_grows>. +To be documented. */
\ No newline at end of file diff --git a/doc/dw-stacking-context.doc b/doc/dw-stacking-context.doc new file mode 100644 index 00000000..6138ca5d --- /dev/null +++ b/doc/dw-stacking-context.doc @@ -0,0 +1,114 @@ +/** \page dw-stacking-context Handling stacking contexts + +Stacking Context and dw::core::StackingContextMgr +================================================= + +For the definition of stacking contexts, see CSS 2.1 specification, + +- <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section + 9.9.1: Specifying the stack level: the 'z-index' property</a> and +- <a href="http://www.w3.org/TR/CSS2/zindex.html">appendix E</a>. + +A widget establishes a stacking context when it is positioned and its +style value of *z-index* is different from *auto* (see +dw::core::StackingContextMgr::isEstablishingStackingContext). In this +case, it is assigned an instance of dw::core::StackingContextMgr, +which has also access to the widgets establishing the child contexts. + + +Stacking Order +============== + +The stacking order influences + +1. the order in which child widgets are drawn (dw::core::Widget::draw), + and +2. the order in which mouse events are dispatched to child widgets + (dw::core::Widget::getWidgetAtPoint). + +The first is done from bottom to top, the latter from top to bottom. + +I'm here referring to the simplified description in +<a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section +9.9.1</a>. The table shows a recommended order for the implementations +of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint +(for the latter, read from bottom to top): + +<table> +<tr> +<th> CSS specification <th> Drawing <th> Mouse events +<tr> +<td> *1. the background and borders of the element forming the + stacking context.* +<td> dw::core::Widget::drawBox +<td> Nothing necessary. +<tr> +<td> *2. the child stacking contexts with negative stack levels (most + negative first).* +<td> dw::core::StackingContextMgr::drawBottom (when defined) +<td> dw::core::StackingContextMgr::getBottomWidgetAtPoint (when defined) +<tr> +<td> *3. the in-flow, non-inline-level, non-positioned descendants.* + +<td rowspan="4"> When (i) widget specific content is drawn, then (ii) + dw::oof::OOFAwareWidget::drawOOF is called, this will + have this effect: + + 1. all in-flow elements are drawn, + 2. floats are drawn and + 3. positioned elements with *z-index: auto* are drawn + (latter two done by + dw::oof::OOFAwareWidget::drawOOF, in this order). + + This order differs from the specified order, but + since floats and in-flow elements do not overlap, + this difference has no effect. + + Drawing in-line elements, floats and positioned + elements with *z-index: auto* and should avoid + duplicate calls: Widgets drawn by + dw::core::StackingContextMgr::drawBottom and by + dw::core::StackingContextMgr::drawTop should be + excluded here. This can be tested with + dw::core::StackingContextMgr::handledByStackingContextMgr. + +<td rowspan="4"> Likewise, the implementation should (i) test + dw::oof::OOFAwareWidget::getWidgetOOFAtPoint, and + (ii) search through the chilren. Also, duplicate + calls should be avoided using + dw::core::StackingContextMgr::handledByStackingContextMgr. + + There are already the implementations + dw::core::Widget::getWidgetAtPoint (ignoring + dw::oof::OutOfFlowMgr) and + dw::oof::OOFAwareWidget::getWidgetAtPoint (including + dw::oof::OutOfFlowMgr). + +<tr> +<td> *4. the non-positioned floats.* +<tr> +<td> *5. the in-flow, inline-level, non-positioned descendants, + including inline tables and inline blocks.* +<tr> +<td> (What about positioned elements with *z-index: auto*? Seems to be + missing in + <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section + 9.9.1</a>, but mentioned in + <a href="http://www.w3.org/TR/CSS2/zindex.html">appendix E</a>, + item 8. +<tr> +<td> *6. the child stacking contexts with stack level 0 and the + positioned descendants with stack level 0.* +<td rowspan="2"> dw::core::StackingContextMgr::drawTop (when defined) +<td rowspan="2"> dw::core::StackingContextMgr::getTopWidgetAtPoint + (when defined) +<tr> +<td> *7. the child stacking contexts with positive stack levels (least + positive first).* +</table> + +Note: This is not quite in conformance with the specification: this +description refers to any widget, not only widgets establishing a +stacking context. Does this make a difference? + +*/
\ No newline at end of file diff --git a/dw/Makefile.am b/dw/Makefile.am index 0b4b7bb4..15055ad8 100644 --- a/dw/Makefile.am +++ b/dw/Makefile.am @@ -23,6 +23,8 @@ libDw_core_a_SOURCES = \ platform.hh \ selection.hh \ selection.cc \ + stackingcontextmgr.hh \ + stackingcontextmgr.cc \ style.cc \ style.hh \ types.cc \ @@ -69,6 +71,17 @@ libDw_widgets_a_SOURCES = \ image.hh \ listitem.cc \ listitem.hh \ + oofawarewidget.cc \ + oofawarewidget_iterator.cc \ + oofawarewidget.hh \ + ooffloatsmgr.cc \ + ooffloatsmgr.hh \ + oofposabsmgr.cc \ + oofposabsmgr.hh \ + oofposfixedmgr.cc \ + oofposfixedmgr.hh \ + oofpositionedmgr.cc \ + oofpositionedmgr.hh \ outofflowmgr.cc \ outofflowmgr.hh \ ruler.cc \ diff --git a/dw/alignedtablecell.cc b/dw/alignedtablecell.cc index 633c4e68..e7ab2741 100644 --- a/dw/alignedtablecell.cc +++ b/dw/alignedtablecell.cc @@ -129,6 +129,11 @@ int AlignedTableCell::applyPerHeight (int containerHeight, return tablecell::applyPerHeight (this, containerHeight, perHeight); } +bool AlignedTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +} + int AlignedTableCell::wordWrap(int wordIndex, bool wrapAll) { Textblock::Word *word; @@ -191,7 +196,7 @@ int AlignedTableCell::getValue () void AlignedTableCell::setMaxValue (int maxValue, int value) { line1Offset = maxValue - value; - queueResize (OutOfFlowMgr::createRefNormalFlow (0), true); + queueResize (makeParentRefInFlow (0), true); } } // namespace dw diff --git a/dw/alignedtablecell.hh b/dw/alignedtablecell.hh index 5ea606d7..5325ba63 100644 --- a/dw/alignedtablecell.hh +++ b/dw/alignedtablecell.hh @@ -22,6 +22,8 @@ protected: bool getAdjustMinWidth (); + bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); + int wordWrap (int wordIndex, bool wrapAll); int getValue (); diff --git a/dw/bullet.cc b/dw/bullet.cc index acaf81cc..0b4b5983 100644 --- a/dw/bullet.cc +++ b/dw/bullet.cc @@ -57,7 +57,9 @@ void Bullet::containerSizeChangedForChildren () DBG_OBJ_LEAVE (); } -void Bullet::draw (core::View *view, core::Rectangle *area) +void Bullet::draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { int x, y, l; bool filled = true; diff --git a/dw/bullet.hh b/dw/bullet.hh index 004187cd..7703a64b 100644 --- a/dw/bullet.hh +++ b/dw/bullet.hh @@ -17,7 +17,9 @@ protected: void sizeRequestImpl (core::Requisition *requisition); void getExtremesImpl (core::Extremes *extremes); void containerSizeChangedForChildren (); - void draw (core::View *view, core::Rectangle *area); + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); core::Iterator *iterator (core::Content::Type mask, bool atEnd); public: @@ -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..11d2e97f 100644 --- a/dw/image.cc +++ b/dw/image.cc @@ -334,7 +334,7 @@ void Image::leaveNotifyImpl (core::EventCrossing *event) */ int Image::contentX (core::MousePositionEvent *event) { - int ret = event->xWidget - getStyle()->boxOffsetX(); + int ret = event->xWidget - boxOffsetX(); ret = misc::min(getContentWidth(), misc::max(ret, 0)); return ret; @@ -342,7 +342,7 @@ int Image::contentX (core::MousePositionEvent *event) int Image::contentY (core::MousePositionEvent *event) { - int ret = event->yWidget - getStyle()->boxOffsetY(); + int ret = event->yWidget - boxOffsetY(); ret = misc::min(getContentHeight(), misc::max(ret, 0)); return ret; @@ -404,7 +404,9 @@ bool Image::buttonReleaseImpl (core::EventButton *event) return false; } -void Image::draw (core::View *view, core::Rectangle *area) +void Image::draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { int dx, dy; core::Rectangle content, intersection; @@ -412,8 +414,8 @@ void Image::draw (core::View *view, core::Rectangle *area) drawWidgetBox (view, area, false); if (buffer) { - dx = getStyle()->boxOffsetX (); - dy = getStyle()->boxOffsetY (); + dx = boxOffsetX (); + dy = boxOffsetY (); content.x = dx; content.y = dy; content.width = getContentWidth (); @@ -440,31 +442,29 @@ void Image::draw (core::View *view, core::Rectangle *area) (getContentHeight() < getStyle()->font->ascent + getStyle()->font->descent)) { clippingView = usedView = - view->getClippingView (allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY (), + view->getClippingView (allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight()); } usedView->drawSimpleWrappedText (getStyle()->font, getStyle()->color, core::style::Color::SHADING_NORMAL, - allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY (), + allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight(), altText); if (clippingView) view->mergeClippingView (clippingView); } if (mapKey) { - clippingView = view->getClippingView (allocation.x + - getStyle()->boxOffsetX (), - allocation.y + - getStyle()->boxOffsetY (), + clippingView = view->getClippingView (allocation.x + boxOffsetX (), + allocation.y + boxOffsetY (), getContentWidth(), getContentHeight()); mapList->drawMap(mapKey, clippingView, getStyle(), - allocation.x + getStyle()->boxOffsetX (), - allocation.y + getStyle()->boxOffsetY ()); + allocation.x + boxOffsetX (), + allocation.y + boxOffsetY ()); view->mergeClippingView (clippingView); } } @@ -515,9 +515,8 @@ void Image::drawRow (int row) buffer->getRowArea (row, &area); if (area.width && area.height) - queueDrawArea (area.x + getStyle()->boxOffsetX (), - area.y + getStyle()->boxOffsetY (), - area.width, area.height); + queueDrawArea (area.x + boxOffsetX (), area.y + boxOffsetY (), area.width, + area.height); } void Image::finish () diff --git a/dw/image.hh b/dw/image.hh index 9adf7806..85776db5 100644 --- a/dw/image.hh +++ b/dw/image.hh @@ -134,8 +134,10 @@ protected: void getExtremesImpl (core::Extremes *extremes); void sizeAllocateImpl (core::Allocation *allocation); void containerSizeChangedForChildren (); - - void draw (core::View *view, core::Rectangle *area); + + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); bool buttonPressImpl (core::EventButton *event); bool buttonReleaseImpl (core::EventButton *event); diff --git a/dw/iterator.cc b/dw/iterator.cc index 0edb580b..fccd4c1a 100644 --- a/dw/iterator.cc +++ b/dw/iterator.cc @@ -204,14 +204,6 @@ void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end, } } - -void Iterator::print () -{ - misc::StringBuffer sb; - intoStringBuffer (&sb); - printf ("%s", sb.getChars ()); -} - // ------------------- // EmptyIterator // ------------------- @@ -906,5 +898,68 @@ void CharIterator::unhighlight (CharIterator *it1, CharIterator *it2, } } +// --------------------------- +// StackingIteratorStack +// --------------------------- + +StackingIteratorStack::StackingIteratorStack () +{ + vector = new lout::container::untyped::Vector (1, true); + topPos = -1; +} + +StackingIteratorStack::~StackingIteratorStack () +{ + delete vector; +} + +void StackingIteratorStack::intoStringBuffer(lout::misc::StringBuffer *sb) +{ + sb->append ("[ "); + + for (int i = 0; i < vector->size (); i++) { + if (i != 0) + sb->append (" "); + if (i == topPos) + sb->append ("<b>"); + vector->get(i)->intoStringBuffer (sb); + if (i == topPos) + sb->append ("</b>"); + } + + sb->append (" ]"); +} + +void StackingIteratorStack::push (lout::object::Object *object) +{ + assert (atRealTop ()); + vector->put (object); + topPos++; +} + +void StackingIteratorStack::pop () +{ + assert (atRealTop ()); + vector->remove (vector->size () - 1); + topPos--; +} + +void StackingIteratorStack::forward () +{ + assert (!atRealTop ()); + topPos++; +} + +void StackingIteratorStack::backward () +{ + topPos--; +} + +void StackingIteratorStack::cleanup () +{ + while (!atRealTop ()) + vector->remove (vector->size () - 1); +} + } // namespace core } // namespace dw diff --git a/dw/iterator.hh b/dw/iterator.hh index abf31d0b..acef26da 100644 --- a/dw/iterator.hh +++ b/dw/iterator.hh @@ -86,8 +86,6 @@ public: static void scrollTo (Iterator *it1, Iterator *it2, int start, int end, HPosition hpos, VPosition vpos); - - virtual void print (); }; @@ -265,6 +263,31 @@ public: hpos, vpos); } }; +/** + * \brief Some completely different kind of iterator: ... + */ +class StackingIteratorStack +{ +private: + lout::container::untyped::Vector *vector; + int topPos; + +public: + StackingIteratorStack (); + ~StackingIteratorStack (); + + void intoStringBuffer(lout::misc::StringBuffer *sb); + + inline bool atRealTop () { return topPos == vector->size () - 1; } + inline lout::object::Object *getTop () { return vector->get (topPos); } + + void push (lout::object::Object *object); + void pop (); + void forward (); + void backward (); + void cleanup (); +}; + } // namespace core } // namespace dw diff --git a/dw/layout.cc b/dw/layout.cc index 2845a8e9..df22bb75 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -374,6 +374,14 @@ void Layout::addWidget (Widget *widget) return; } + // The toplevel widget always establishes a stacking context. It could + // already be set in Widget::setStyle(). + if (widget->stackingContextMgr == NULL) { + widget->stackingContextMgr = new StackingContextMgr (widget); + DBG_OBJ_ASSOC (widget, widget->stackingContextMgr); + widget->stackingContextWidget = widget; + } + topLevel = widget; widget->layout = this; widget->container = NULL; @@ -654,6 +662,9 @@ bool Layout::calcScrollInto (int requestedValue, int requestedSize, void Layout::draw (View *view, Rectangle *area) { + DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + Rectangle widgetArea, intersection, widgetDrawArea; // First of all, draw background image. (Unlike background *color*, @@ -693,11 +704,13 @@ void Layout::draw (View *view, Rectangle *area) widgetDrawArea.width = intersection.width; widgetDrawArea.height = intersection.height; - topLevel->draw (view, &widgetDrawArea); + topLevel->drawToplevel (view, &widgetDrawArea); view->finishDrawing (&intersection); } } + + DBG_OBJ_LEAVE (); } int Layout::currHScrollbarThickness() @@ -1093,12 +1106,17 @@ void Layout::leaveNotify (View *view, ButtonState state) */ Widget *Layout::getWidgetAtPoint (int x, int y) { - _MSG ("------------------------------------------------------------\n"); - _MSG ("widget at (%d, %d)\n", x, y); + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + Widget *widget; + if (topLevel && topLevel->wasAllocated ()) - return topLevel->getWidgetAtPoint (x, y, 0); + widget = topLevel->getWidgetAtPointToplevel (x, y); else - return NULL; + widget = NULL; + + DBG_OBJ_MSGF ("events", 0, "=> %p", widget); + DBG_OBJ_LEAVE (); + return widget; } @@ -1108,12 +1126,16 @@ Widget *Layout::getWidgetAtPoint (int x, int y) */ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state) { + DBG_OBJ_ENTER ("events", 0, "moveToWidget", "%p, %d", + newWidgetAtPoint, state); + Widget *ancestor, *w; Widget **track; int trackLen, i, i_a; EventCrossing crossingEvent; - _MSG("moveToWidget: wap=%p nwap=%p\n",widgetAtPoint,newWidgetAtPoint); + DBG_OBJ_MSGF ("events", 1, "(old) widgetAtPoint = %p", widgetAtPoint); + if (newWidgetAtPoint != widgetAtPoint) { // The mouse pointer has been moved into another widget. if (newWidgetAtPoint && widgetAtPoint) @@ -1183,6 +1205,8 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state) widgetAtPoint = newWidgetAtPoint; updateCursor (); } + + DBG_OBJ_LEAVE (); } /** diff --git a/dw/layout.hh b/dw/layout.hh index 63c3ed04..efead388 100644 --- a/dw/layout.hh +++ b/dw/layout.hh @@ -314,7 +314,12 @@ public: /* View */ - inline void expose (View *view, Rectangle *area) { draw (view, area); } + inline void expose (View *view, Rectangle *area) { + DBG_OBJ_ENTER ("draw", 0, "expose", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + draw (view, area); + DBG_OBJ_LEAVE (); + } /** * \brief This function is called by a view, to delegate a button press diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc new file mode 100644 index 00000000..2c7afd1f --- /dev/null +++ b/dw/oofawarewidget.cc @@ -0,0 +1,823 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofawarewidget.hh" +#include "ooffloatsmgr.hh" +#include "oofposabsmgr.hh" +#include "oofposfixedmgr.hh" + +using namespace dw; +using namespace dw::core; +using namespace dw::core::style; +using namespace lout::object; +using namespace lout::misc; +using namespace lout::container::typed; + +namespace dw { + +namespace oof { + +OOFAwareWidget::OOFStackingIterator::OOFStackingIterator + (OOFAwareWidget *widget, bool atEnd) +{ + if (atEnd) { + majorLevel = OOFStackingIterator::END - 1; + minorLevel = widget->getLastMinorLevel (majorLevel); + index = widget->getLastLevelIndex (majorLevel, minorLevel); + } else { + majorLevel = OOFStackingIterator::START + 1; + minorLevel = index = 0; + } + + widgetsDrawnAfterInterruption = NULL; +} + +OOFAwareWidget::OOFStackingIterator::~OOFStackingIterator () +{ + if (widgetsDrawnAfterInterruption) + delete widgetsDrawnAfterInterruption; +} + +void OOFAwareWidget::OOFStackingIterator::registerWidgetDrawnAfterInterruption + (Widget *widget) +{ + if (widgetsDrawnAfterInterruption == NULL) + widgetsDrawnAfterInterruption = new HashSet<TypedPointer<Widget> > (true); + + TypedPointer<Widget> *p = new TypedPointer<Widget> (widget); + assert (!widgetsDrawnAfterInterruption->contains (p)); + widgetsDrawnAfterInterruption->put (p); +} + +bool OOFAwareWidget::OOFStackingIterator::hasWidgetBeenDrawnAfterInterruption + (Widget *widget) +{ + if (widgetsDrawnAfterInterruption) { + TypedPointer<Widget> p (widget); + return widgetsDrawnAfterInterruption->contains (&p); + } else + return false; +} + +const char *OOFAwareWidget::OOFStackingIterator::majorLevelText (int majorLevel) +{ + switch (majorLevel) { + case START: return "START"; + case BACKGROUND: return "BACKGROUND"; + case SC_BOTTOM: return "SC_BOTTOM"; + case IN_FLOW: return "IN_FLOW"; + case OOF_REF: return "OOF_REF"; + case OOF_CONT: return "OOF_CONT"; + case SC_TOP: return "SC_TOP"; + case END: return "END"; + default: return "???"; + } +} + +void OOFAwareWidget::OOFStackingIterator::intoStringBuffer(StringBuffer *sb) +{ + sb->append ("("); + sb->append (majorLevelText (majorLevel)); + sb->append (", "); + sb->appendInt (minorLevel); + sb->append (", "); + sb->appendInt (index); + sb->append (")"); +} + +int OOFAwareWidget::CLASS_ID = -1; + +OOFAwareWidget::OOFAwareWidget () +{ + DBG_OBJ_CREATE ("dw::oof::OOFAwareWidget"); + registerName ("dw::oof::OOFAwareWidget", &CLASS_ID); + + for (int i = 0; i < NUM_OOFM; i++) { + oofContainer[i] = NULL; + 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::getOOFMIndex (Widget *widget) +{ + if (testWidgetFloat (widget)) + return OOFM_FLOATS; + else if (testWidgetAbsolutelyPositioned (widget)) + return OOFM_ABSOLUTE; + else if (testWidgetFixedlyPositioned (widget)) + return OOFM_FIXED; + else { + lout::misc::assertNotReached (); + return -1; + } +} + +bool OOFAwareWidget::isOOFContainer (Widget *widget, int oofmIndex) +{ + // TODO The methods isPossibleContainer() and isPossibleContainerParent() + // are only used in few cases. Does not matter currently, however. + + switch (oofmIndex) { + case OOFM_FLOATS: + return widget->instanceOf (OOFAwareWidget::CLASS_ID) && + (// For floats, only some OOF aware widgets are considered as + // containers. + ((OOFAwareWidget*)widget)->isPossibleContainer (OOFM_FLOATS) && + // The second condition: that this block is "out of flow", in a + // wider sense. + (// The toplevel widget is "out of flow", since there is no + // parent, and so no context. + widget->getParent() == NULL || + // A similar reasoning applies to a widget with an + // unsuitable parent (typical example: a table cell (this + // is also a text block, so possible float container) + // within a table widget, which is not a suitable float + // container parent). + !(widget->getParent()->instanceOf (OOFAwareWidget::CLASS_ID) && + ((OOFAwareWidget*)widget->getParent()) + ->isPossibleContainerParent (OOFM_FLOATS)) || + // Inline blocks are containing blocks, too. + widget->getStyle()->display == DISPLAY_INLINE_BLOCK || + // Same for blocks with 'overview' set to another value than + // (the default value) 'visible'. + widget->getStyle()->overflow != OVERFLOW_VISIBLE || + // Finally, "out of flow" in a narrower sense: floats; + // absolutely and fixedly positioned elements. (No + // relatively positioned elements; since the latters + // constitute a stacking context, drawing of floats gets + // somewhat more complicated; see "interrupting the drawing + // process" in "dw-stacking-context.doc". + testWidgetOutOfFlow (widget))); + + case OOFM_ABSOLUTE: + // Only the toplevel widget (as for all) as well as absolutely, + // relatively, and fixedly positioned elements constitute the + // containing block for absolutely positioned elements, but + // neither floats nor other elements like table cells, or + // elements with 'overview' set to another value than 'visible'. + return widget->instanceOf (OOFAwareWidget::CLASS_ID) && + (widget->getParent() == NULL || testWidgetPositioned (widget)); + + case OOFM_FIXED: + // The single container for fixedly positioned elements is the + // toplevel (canvas; actually the viewport). (The toplevel + // widget should always be a textblock; at least this is the + // case in dillo.) + return widget->getParent() == NULL; + + default: + // compiler happiness + lout::misc::assertNotReached (); + return false; + } +} + +void OOFAwareWidget::notifySetParent () +{ + // Search for containing blocks. + for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) { + oofContainer[oofmIndex] = NULL; + + for (Widget *widget = this; + widget != NULL && oofContainer[oofmIndex] == NULL; + widget = widget->getParent ()) + if (isOOFContainer (widget, oofmIndex)) { + assert (widget->instanceOf (OOFAwareWidget::CLASS_ID)); + oofContainer[oofmIndex] = (OOFAwareWidget*)widget; + } + + DBG_OBJ_ARRSET_PTR ("oofContainer", oofmIndex, oofContainer[oofmIndex]); + + assert (oofContainer[oofmIndex] != NULL); + } +} + +void OOFAwareWidget::initOutOfFlowMgrs () +{ + if (oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] == NULL) { + oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS] = + new OOFFloatsMgr (oofContainer[OOFM_FLOATS]); + DBG_OBJ_ASSOC (oofContainer[OOFM_FLOATS], + oofContainer[OOFM_FLOATS]->outOfFlowMgr[OOFM_FLOATS]); + } + + if (oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] == NULL) { + oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE] = + new OOFPosAbsMgr (oofContainer[OOFM_ABSOLUTE]); + DBG_OBJ_ASSOC (oofContainer[OOFM_ABSOLUTE], + oofContainer[OOFM_ABSOLUTE]->outOfFlowMgr[OOFM_ABSOLUTE]); + } + + if (oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] == NULL) { + oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED] = + new OOFPosFixedMgr (oofContainer[OOFM_FIXED]); + DBG_OBJ_ASSOC (oofContainer[OOFM_FIXED], + oofContainer[OOFM_FIXED]->outOfFlowMgr[OOFM_FIXED]); + } +} + +void OOFAwareWidget::correctRequisitionByOOF (Requisition *requisition, + void (*splitHeightFun) (int, int*, + int*)) +{ + 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 (outOfFlowMgr[i]->containerMustAdjustExtraSpace () && + adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) { + extraSpace.right = max (extraSpace.right, + oofWidth - requisition->width); + DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right); + } + + requisition->width = oofWidth; + } + + if (oofHeight > requisition->ascent + requisition->descent) { + if (outOfFlowMgr[i]->containerMustAdjustExtraSpace () && + adjustExtraSpaceWhenCorrectingRequisitionByOOF ()) { + extraSpace.bottom = max (extraSpace.bottom, + oofHeight - (requisition->ascent + + requisition->descent)); + DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom); + } + + splitHeightFun (oofHeight, + &requisition->ascent, &requisition->descent); + } + } + } +} + +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 (Allocation *allocation) +{ + + for (int i = 0; i < NUM_OOFM; i++) + if (oofContainer[i]->outOfFlowMgr[i]) + oofContainer[i]->outOfFlowMgr[i]->sizeAllocateStart (this, allocation); +} + +void OOFAwareWidget::sizeAllocateEnd () +{ + for (int i = 0; i < NUM_OOFM; i++) + if (oofContainer[i]->outOfFlowMgr[i]) + oofContainer[i]->outOfFlowMgr[i]->sizeAllocateEnd (this); +} + +void OOFAwareWidget::containerSizeChangedForChildrenOOF () +{ + for (int i = 0; i < NUM_OOFM; i++) + if (outOfFlowMgr[i]) + outOfFlowMgr[i]->containerSizeChangedForChildren (); +} + +bool OOFAwareWidget::doesWidgetOOFInterruptDrawing (Widget *widget) +{ + DBG_OBJ_ENTER ("draw", 0, "doesWidgetOOFInterruptDrawing", "%p", widget); + + // This is the generator of the widget. + int oofmIndex = getOOFMIndex (widget); + DBG_OBJ_MSGF ("draw", 1, "oofmIndex = %d", oofmIndex); + + int cl = oofContainer[oofmIndex]->stackingContextWidget->getLevel (), + gl = stackingContextWidget->getLevel (); + + DBG_OBJ_MSGF_O ("draw", 1, (void*)NULL, "%d < %d => %s", + cl, gl, cl < gl ? "true" : "false"); + + DBG_OBJ_LEAVE (); + return cl < gl; +} + +void OOFAwareWidget::draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + + while (*interruptedWidget == NULL && + ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel + < OOFStackingIterator::END) { + drawLevel (view, area, iteratorStack, interruptedWidget, + ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel); + + if (*interruptedWidget) { + if ((*interruptedWidget)->getParent () == this) { + DBG_OBJ_MSGF ("draw", 1, "interrupted at %p, drawing seperately", + *interruptedWidget); + DBG_IF_RTFL { + StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "iteratorStack: %s", sb.getChars ()); + } + + core::Rectangle interruptedWidgetArea; + if ((*interruptedWidget)->intersects (area, + &interruptedWidgetArea)) { + // Similar to Widget::drawToplevel. Nested interruptions are not + // allowed. + StackingIteratorStack iteratorStack2; + Widget *interruptedWidget2 = NULL; + (*interruptedWidget)->drawTotal (view, &interruptedWidgetArea, + &iteratorStack2, + &interruptedWidget2); + assert (interruptedWidget2 == NULL); + } + + ((OOFStackingIterator*)iteratorStack->getTop()) + ->registerWidgetDrawnAfterInterruption (*interruptedWidget); + + // Continue with the current state of "iterator". + *interruptedWidget = NULL; + DBG_OBJ_MSG ("draw", 1, "done with interruption"); + } + } else { + OOFStackingIterator* osi = + (OOFStackingIterator*)iteratorStack->getTop(); + osi->majorLevel++; + osi->minorLevel = osi->index = 0; + } + } + + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +void OOFAwareWidget::drawLevel (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel) +{ + DBG_OBJ_ENTER ("draw", 0, "OOFAwareWidget/drawLevel", + "(%d, %d, %d * %d), %s", + area->x, area->y, area->width, area->height, + OOFStackingIterator::majorLevelText (majorLevel)); + + switch (majorLevel) { + case OOFStackingIterator::START: + break; + + case OOFStackingIterator::BACKGROUND: + drawWidgetBox (view, area, false); + break; + + case OOFStackingIterator::SC_BOTTOM: + if (stackingContextMgr) { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + stackingContextMgr->drawBottom (view, area, iteratorStack, + interruptedWidget, &osi->minorLevel, + &osi->index); + } + break; + + case OOFStackingIterator::IN_FLOW: + // Should be implemented in the sub class. + break; + + case OOFStackingIterator::OOF_REF: + // Should be implemented in the sub class (when references are hold). + break; + + case OOFStackingIterator::OOF_CONT: + drawOOF (view, area, iteratorStack, interruptedWidget); + break; + + case OOFStackingIterator::SC_TOP: + if (stackingContextMgr) { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + stackingContextMgr->drawTop (view, area, iteratorStack, + interruptedWidget, &osi->minorLevel, + &osi->index); + } + break; + + case OOFStackingIterator::END: + break; + } + + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +void OOFAwareWidget::drawOOF (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop (); + assert (osi->majorLevel == OOFStackingIterator::OOF_CONT); + + while (*interruptedWidget == NULL && osi->minorLevel < NUM_OOFM) { + if(outOfFlowMgr[osi->minorLevel]) + outOfFlowMgr[osi->minorLevel]->draw (view, area, iteratorStack, + interruptedWidget, &(osi->index)); + if (*interruptedWidget == NULL) { + osi->minorLevel++; + osi->index = 0; + } + } +} + +Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + Widget *widgetAtPoint = NULL; + + if (wasAllocated () && x >= allocation.x && y >= allocation.y && + x <= allocation.x + allocation.width && + y <= allocation.y + getHeight ()) { + while (widgetAtPoint == NULL && *interruptedWidget == NULL && + ((OOFStackingIterator*)iteratorStack->getTop())->majorLevel + > OOFStackingIterator::START) { + widgetAtPoint = + getWidgetAtPointLevel (x, y, iteratorStack, interruptedWidget, + ((OOFStackingIterator*)iteratorStack + ->getTop())->majorLevel); + + if (*interruptedWidget) { + assert (widgetAtPoint == NULL); // Not both set. + + if ((*interruptedWidget)->getParent () == this) { + DBG_OBJ_MSGF ("events", 1, + "interrupted at %p, searching widget seperately", + *interruptedWidget); + DBG_IF_RTFL { + StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "iteratorStack: %s", + sb.getChars ()); + } + + // Similar to Widget::getWidgetAtPointToplevel. Nested + // interruptions are not allowed. + StackingIteratorStack iteratorStack2; + Widget *interruptedWidget2 = NULL; + widgetAtPoint = (*interruptedWidget) + ->getWidgetAtPointTotal (x, y, &iteratorStack2, + &interruptedWidget2); + assert (interruptedWidget2 == NULL); + + ((OOFStackingIterator*)iteratorStack->getTop()) + ->registerWidgetDrawnAfterInterruption (*interruptedWidget); + + // Continue with the current state of "iterator". + *interruptedWidget = NULL; + DBG_OBJ_MSG ("events", 1, "done with interruption"); + + // The interrupted widget may have returned non-NULL. In this + // case, the stack must be cleaned up explicitly, which would + // otherwise be done implicitly during the further search. + // (Since drawing is never quit completely, this problem only + // applies to searching.) + if (widgetAtPoint) { + iteratorStack->cleanup (); + + DBG_IF_RTFL { + StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, + "iteratorStack after cleanup: %s", + sb.getChars ()); + } + } + + } + } else { + OOFStackingIterator* osi = + (OOFStackingIterator*)iteratorStack->getTop(); + osi->majorLevel--; + if (osi->majorLevel > OOFStackingIterator::START) { + osi->minorLevel = getLastMinorLevel (osi->majorLevel); + osi->index = + getLastLevelIndex (osi->majorLevel, osi->minorLevel); + } + } + } + } + + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + +Widget *OOFAwareWidget::getWidgetAtPointLevel (int x, int y, + StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int majorLevel) +{ + DBG_OBJ_ENTER ("events", 0, "OOFAwareWidget/getWidgetAtPointLevel", + "%d, %d, %s", x, y, + OOFStackingIterator::majorLevelText (majorLevel)); + + Widget *widgetAtPoint = NULL; + + switch (majorLevel) { + case OOFStackingIterator::BACKGROUND: + if (wasAllocated () && x >= allocation.x && y >= allocation.y && + x <= allocation.x + allocation.width && + y <= allocation.y + getHeight ()) + widgetAtPoint = this; + break; + + case OOFStackingIterator::SC_BOTTOM: + if (stackingContextMgr) { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + widgetAtPoint = + stackingContextMgr->getBottomWidgetAtPoint (x, y, iteratorStack, + interruptedWidget, + &osi->minorLevel, + &osi->index); + } + break; + + case OOFStackingIterator::IN_FLOW: + // Should be implemented in the sub class. + assertNotReached (); + break; + + case OOFStackingIterator::OOF_REF: + // Should be implemented in the sub class (when references are hold). + break; + + case OOFStackingIterator::OOF_CONT: + widgetAtPoint = + getWidgetOOFAtPoint (x, y, iteratorStack, interruptedWidget); + break; + + case OOFStackingIterator::SC_TOP: + if (stackingContextMgr) { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + widgetAtPoint = + stackingContextMgr->getTopWidgetAtPoint (x, y, iteratorStack, + interruptedWidget, + &osi->minorLevel, + &osi->index); + } + break; + + default: + assertNotReached (); + } + + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + +Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget) +{ + OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop (); + assert (osi->majorLevel == OOFStackingIterator::OOF_CONT); + + Widget *widgetAtPoint = NULL; + + while (*interruptedWidget == NULL && widgetAtPoint == NULL && + osi->minorLevel >= 0) { + if (outOfFlowMgr[osi->minorLevel]) + widgetAtPoint = + outOfFlowMgr[osi->minorLevel]->getWidgetAtPoint (x, y, + iteratorStack, + interruptedWidget, + &(osi->index)); + + if (*interruptedWidget == NULL) { + osi->minorLevel--; + if (osi->minorLevel > 0 && outOfFlowMgr[osi->minorLevel] != NULL) + osi->index = outOfFlowMgr[osi->minorLevel]->getNumWidgets () - 1; + } + } + + return widgetAtPoint; +} + +int OOFAwareWidget::getLastMinorLevel (int majorLevel) +{ + switch (majorLevel) { + case OOFStackingIterator::BACKGROUND: + return 0; + + case OOFStackingIterator::SC_BOTTOM: + if (stackingContextMgr) + // See StackingContextMgr: + // - startZIndexEff = max (minZIndex, INT_MIN) = minZIndex (<= 0) + // - endZIndexEff = min (maxZIndex, -1) = -1 + // So, zIndexOffset runs from 0 to endZIndexEff - startZIndexEff = + // - 1 - minZIndex. + return max (- stackingContextMgr->getMinZIndex () - 1, 0); + else + return 0; + + case OOFStackingIterator::IN_FLOW: + return 0; + + case OOFStackingIterator::OOF_REF: + case OOFStackingIterator::OOF_CONT: + return NUM_OOFM - 1; + + case OOFStackingIterator::SC_TOP: + // See StackingContextMgr: + // - startZIndexEff = max (minZIndex, 0) = 0 + // - endZIndexEff = min (maxZIndex, INT_MAX) = maxZIndex + if (stackingContextMgr) + return stackingContextMgr->getMaxZIndex (); + else + return 0; + + default: + assertNotReached (); + return 0; + } +} + +int OOFAwareWidget::getLastLevelIndex (int majorLevel, int minorLevel) +{ + switch (majorLevel) { + case OOFStackingIterator::BACKGROUND: + return 0; + + case OOFStackingIterator::SC_BOTTOM: + case OOFStackingIterator::SC_TOP: + if (stackingContextMgr) + return stackingContextMgr->getNumChildSCWidgets () - 1; + else + return 0; + + case OOFStackingIterator::IN_FLOW: + // Should be implemented in the sub class. + assertNotReached (); + + case OOFStackingIterator::OOF_REF: + // Should be implemented in the sub class (when references are hold). + return 0; + + case OOFStackingIterator::OOF_CONT: + if(outOfFlowMgr[minorLevel]) + return outOfFlowMgr[minorLevel]->getNumWidgets () - 1; + else + return 0; + + default: + assertNotReached (); + return 0; + } +} + +int OOFAwareWidget::getAvailWidthOfChild (Widget *child, bool forceValue) +{ + if (isWidgetOOF(child)) { + assert (getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)); + return getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child, + forceValue); + } else + return Widget::getAvailWidthOfChild (child, forceValue); +} + +int OOFAwareWidget::getAvailHeightOfChild (Widget *child, bool forceValue) +{ + if (isWidgetOOF(child)) { + assert (getWidgetOutOfFlowMgr(child) && + getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child)); + return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child, + forceValue); + } else + return Widget::getAvailWidthOfChild (child, forceValue); +} + +void OOFAwareWidget::removeChild (Widget *child) +{ + // Sub classes should implement this method (and Textblock and + // Table do so), so this point is only reached from + // ~OOFAwareWidget, which removes widgets out of flow. + assert (isWidgetOOF (child)); +} + +Object *OOFAwareWidget::stackingIterator (bool atEnd) +{ + return new OOFStackingIterator (this, atEnd); +} + +void OOFAwareWidget::borderChanged (int y, Widget *vloat) +{ + assertNotReached (); +} + +void OOFAwareWidget::clearPositionChanged () +{ + assertNotReached (); +} + +void OOFAwareWidget::oofSizeChanged (bool extremesChanged) +{ + DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s", + extremesChanged ? "true" : "false"); + queueResize (-1, extremesChanged); + + // Extremes changes may become also relevant for the children. + if (extremesChanged) + containerSizeChanged (); + + DBG_OBJ_LEAVE (); +} + +int OOFAwareWidget::getLineBreakWidth () +{ + assertNotReached (); + return 0; +} + +bool OOFAwareWidget::isPossibleContainer (int oofmIndex) +{ + return oofmIndex != OOFM_FLOATS; +} + +bool OOFAwareWidget::isPossibleContainerParent (int oofmIndex) +{ + return oofmIndex != OOFM_FLOATS; +} + +bool OOFAwareWidget::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return true; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh new file mode 100644 index 00000000..95af54a0 --- /dev/null +++ b/dw/oofawarewidget.hh @@ -0,0 +1,255 @@ +#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 int getInFlowIndex () { assert (inFlow ()); return index; } + void highlightOOF (int start, int end, core::HighlightLayer layer); + void unhighlightOOF (int direction, core::HighlightLayer layer); + void getAllocationOOF (int start, int end, core::Allocation *allocation); + + public: + OOFAwareWidgetIterator (OOFAwareWidget *widget, core::Content::Type mask, + bool atEnd, int numContentsInFlow); + + void intoStringBuffer(lout::misc::StringBuffer *sb); + int compareTo(lout::object::Comparable *other); + + bool next (); + bool prev (); + }; + + inline bool isParentRefOOF (int parentRef) + { return parentRef != -1 && (parentRef & PARENT_REF_OOFM_MASK); } + + inline int makeParentRefInFlow (int inFlowSubRef) + { return (inFlowSubRef << PARENT_REF_OOFM_BITS); } + inline int getParentRefInFlowSubRef (int parentRef) + { assert (!isParentRefOOF (parentRef)); + return parentRef >> PARENT_REF_OOFM_BITS; } + + inline int makeParentRefOOF (int oofmIndex, int oofmSubRef) + { return (oofmSubRef << PARENT_REF_OOFM_BITS) | (oofmIndex + 1); } + inline int getParentRefOOFSubRef (int parentRef) + { assert (isParentRefOOF (parentRef)); + return parentRef >> PARENT_REF_OOFM_BITS; } + inline int getParentRefOOFIndex (int parentRef) + { assert (isParentRefOOF (parentRef)); + return (parentRef & PARENT_REF_OOFM_MASK) - 1; } + inline oof::OutOfFlowMgr *getParentRefOutOfFlowMgr (int parentRef) + { return outOfFlowMgr[getParentRefOOFIndex (parentRef)]; } + + inline bool isWidgetOOF (Widget *widget) + { return isParentRefOOF (widget->parentRef); } + + inline int getWidgetInFlowSubRef (Widget *widget) + { return getParentRefInFlowSubRef (widget->parentRef); } + + inline int getWidgetOOFSubRef (Widget *widget) + { return getParentRefOOFSubRef (widget->parentRef); } + inline int getWidgetOOFIndex (Widget *widget) + { return getParentRefOOFIndex (widget->parentRef); } + inline oof::OutOfFlowMgr *getWidgetOutOfFlowMgr (Widget *widget) + { return getParentRefOutOfFlowMgr (widget->parentRef); } + + OOFAwareWidget *oofContainer[NUM_OOFM]; + OutOfFlowMgr *outOfFlowMgr[NUM_OOFM]; + + inline OutOfFlowMgr *searchOutOfFlowMgr (int oofmIndex) + { return oofContainer[oofmIndex] ? + oofContainer[oofmIndex]->outOfFlowMgr[oofmIndex] : NULL; } + + static 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 testWidgetPositioned (Widget *widget) + { return testWidgetAbsolutelyPositioned (widget) || + testWidgetRelativelyPositioned (widget) || + testWidgetFixedlyPositioned (widget); } + 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; } + + static bool getOOFMIndex (Widget *widget); + + void initOutOfFlowMgrs (); + void correctRequisitionByOOF (core::Requisition *requisition, + void (*splitHeightFun) (int, int*, int*)); + void correctExtremesByOOF (core::Extremes *extremes); + void sizeAllocateStart (core::Allocation *allocation); + void sizeAllocateEnd (); + void containerSizeChangedForChildrenOOF (); + + virtual void drawLevel (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel); + void drawOOF (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + + Widget *getWidgetAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + virtual Widget *getWidgetAtPointLevel (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int majorLevel); + Widget *getWidgetOOFAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + + virtual int getLastMinorLevel (int majorLevel); + virtual int getLastLevelIndex (int majorLevel, int minorLevel); + + static bool isOOFContainer (Widget *widget, int oofmIndex); + + void notifySetAsTopLevel(); + void notifySetParent(); + + int getAvailWidthOfChild (Widget *child, bool forceValue); + int getAvailHeightOfChild (Widget *child, bool forceValue); + + void removeChild (Widget *child); + + +public: + static int CLASS_ID; + + class OOFStackingIterator: public lout::object::Object + { + private: + lout::container::typed::HashSet<lout::object::TypedPointer<Widget> > + *widgetsDrawnAfterInterruption; + + public: + enum { START, BACKGROUND, SC_BOTTOM, IN_FLOW, OOF_REF, OOF_CONT, SC_TOP, + END } ; + int majorLevel, minorLevel, index; + + static const char *majorLevelText (int majorLevel); + + OOFStackingIterator (OOFAwareWidget *widget, bool atEnd); + ~OOFStackingIterator (); + + void intoStringBuffer(lout::misc::StringBuffer *sb); + + void registerWidgetDrawnAfterInterruption (Widget *widget); + bool hasWidgetBeenDrawnAfterInterruption (Widget *widget); + }; + + OOFAwareWidget (); + ~OOFAwareWidget (); + + bool doesWidgetOOFInterruptDrawing (Widget *widget); + + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + lout::object::Object *stackingIterator (bool atEnd); + + virtual void borderChanged (int y, core::Widget *vloat); + virtual void clearPositionChanged (); + virtual void oofSizeChanged (bool extremesChanged); + virtual int getLineBreakWidth (); // Should perhaps be renamed. + virtual bool isPossibleContainer (int oofmIndex); + virtual bool isPossibleContainerParent (int oofmIndex); + virtual bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFAWAREWIDGET_HH__ diff --git a/dw/oofawarewidget_iterator.cc b/dw/oofawarewidget_iterator.cc new file mode 100644 index 00000000..afafb5d5 --- /dev/null +++ b/dw/oofawarewidget_iterator.cc @@ -0,0 +1,261 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofawarewidget.hh" +#include "ooffloatsmgr.hh" +#include "oofposabsmgr.hh" +#include "oofposfixedmgr.hh" + +using namespace dw; +using namespace dw::core; +using namespace lout::misc; +using namespace lout::object; + +namespace dw { + +namespace oof { + +// "numContentsInFlow" is passed here to avoid indirectly callin the (virtual) +// method numContentsInFlow() from the constructor. +OOFAwareWidget::OOFAwareWidgetIterator::OOFAwareWidgetIterator + (OOFAwareWidget *widget, Content::Type mask, bool atEnd, + int numContentsInFlow) : + Iterator (widget, mask, atEnd) +{ + if (atEnd) { + sectionIndex = NUM_SECTIONS - 1; + while (sectionIndex >= 0 && + numParts (sectionIndex, numContentsInFlow) == 0) + sectionIndex--; + index = numParts (sectionIndex, numContentsInFlow); + } else { + sectionIndex = 0; + index = -1; + } + + content.type = atEnd ? core::Content::END : core::Content::START; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::setValues (int sectionIndex, + int index) +{ + this->sectionIndex = sectionIndex; + this->index = index; + + if (sectionIndex == 0 && index < 0) + content.type = core::Content::START; + else if (sectionIndex == NUM_SECTIONS - 1 && + index >= numParts (sectionIndex)) + content.type = core::Content::END; + else + getPart (sectionIndex, index, &content); +} + +int OOFAwareWidget::OOFAwareWidgetIterator::numParts (int sectionIndex, + int numContentsInFlow) +{ + DBG_OBJ_ENTER_O ("iterator", 0, getWidget(), "numParts", "%d, %d", + sectionIndex, numContentsInFlow); + + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + int result; + + if (sectionIndex == 0) + result = numContentsInFlow == -1 ? + this->numContentsInFlow () : numContentsInFlow; + else + result = widget->outOfFlowMgr[sectionIndex - 1] ? + widget->outOfFlowMgr[sectionIndex - 1]->getNumWidgets () : 0; + + DBG_OBJ_MSGF_O ("iterator", 1, getWidget(), "=> %d", result); + DBG_OBJ_LEAVE_O (getWidget()); + return result; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::getPart (int sectionIndex, + int index, + Content *content) +{ + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + + if (sectionIndex == 0) + getContentInFlow (index, content); + else { + content->type = Content::WIDGET_OOF_CONT; + content->widget = + widget->outOfFlowMgr[sectionIndex - 1]->getWidget (index); + } +} + +void OOFAwareWidget::OOFAwareWidgetIterator::intoStringBuffer (StringBuffer *sb) +{ + Iterator::intoStringBuffer (sb); + sb->append (", sectionIndex = "); + sb->appendInt (sectionIndex); + sb->append (", index = "); + sb->appendInt (index); +} + +int OOFAwareWidget::OOFAwareWidgetIterator::compareTo (Comparable *other) +{ + OOFAwareWidgetIterator *otherTI = (OOFAwareWidgetIterator*)other; + + if (sectionIndex != otherTI->sectionIndex) + return sectionIndex - otherTI->sectionIndex; + else + return index - otherTI->index; +} + +bool OOFAwareWidget::OOFAwareWidgetIterator::next () +{ + DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (), + "OOFAwareWidgetIterator/next"); + + DBG_IF_RTFL { + StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s", + sb.getChars ()); + } + + bool r; + + if (content.type == Content::END) + r = false; + else { + r = true; + bool cancel = false; + + do { + index++; + + if (index < numParts(sectionIndex)) + getPart (sectionIndex, index, &content); + else { + sectionIndex++; + while (sectionIndex < NUM_SECTIONS && numParts (sectionIndex) == 0) + sectionIndex++; + + if (sectionIndex == NUM_SECTIONS) { + content.type = Content::END; + r = false; + cancel = true; + } else { + index = 0; + getPart (sectionIndex, index, &content); + } + } + } while (!cancel && (content.type & getMask()) == 0); + } + + DBG_IF_RTFL { + StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s", + sb.getChars ()); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s", + r ? "true" : "false"); + } + + DBG_OBJ_LEAVE_O (getWidget ()); + return r; +} + +bool OOFAwareWidget::OOFAwareWidgetIterator::prev () +{ + DBG_OBJ_ENTER0_O ("iterator", 0, getWidget (), + "OOFAwareWidgetIterator/prev"); + + DBG_IF_RTFL { + StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "initial value: %s", + sb.getChars ()); + } + + bool r; + + if (content.type == Content::START) + r = false; + else { + r = true; + bool cancel = false; + + do { + index--; + + if (index >= 0) + getPart (sectionIndex, index, &content); + else { + sectionIndex--; + while (sectionIndex >= 0 && numParts (sectionIndex) == 0) + sectionIndex--; + + if (sectionIndex < 0) { + content.type = Content::START; + r = false; + cancel = true; + } else { + index = numParts (sectionIndex) - 1; + getPart (sectionIndex, index, &content); + } + } + } while (!cancel && (content.type & getMask()) == 0); + } + + DBG_IF_RTFL { + StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "final value: %s", + sb.getChars ()); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "return value: %s", + r ? "true" : "false"); + } + + DBG_OBJ_LEAVE_O (getWidget ()); + return r; +} + +void OOFAwareWidget::OOFAwareWidgetIterator::highlightOOF (int start, int end, + HighlightLayer layer) +{ + // TODO What about OOF widgets? +} + +void OOFAwareWidget::OOFAwareWidgetIterator::unhighlightOOF (int direction, + HighlightLayer + layer) +{ + // TODO What about OOF widgets? +} + +void OOFAwareWidget::OOFAwareWidgetIterator::getAllocationOOF (int start, + int end, + Allocation + *allocation) +{ + // TODO Consider start and end? + OOFAwareWidget *widget = (OOFAwareWidget*)getWidget(); + *allocation = *(widget->outOfFlowMgr[sectionIndex - 1] + ->getWidget(index)->getAllocation()); +} + +} // namespace oof + +} // namespace dw diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc new file mode 100644 index 00000000..a4cfed5a --- /dev/null +++ b/dw/ooffloatsmgr.cc @@ -0,0 +1,2359 @@ +/* + * Dillo Widget + * + * Copyright 2013-2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ooffloatsmgr.hh" +#include "oofawarewidget.hh" +#include "../lout/debug.hh" + +#include <limits.h> + +using namespace lout::object; +using namespace lout::container::typed; +using namespace lout::misc; +using namespace dw::core; +using namespace dw::core::style; + +namespace dw { + +namespace oof { + +OOFFloatsMgr::WidgetInfo::WidgetInfo (OOFFloatsMgr *oofm, Widget *widget) +{ + this->oofm = oofm; + this->widget = widget; + wasAllocated = false; + xCB = yCB = width = height = -1; +} + +void OOFFloatsMgr::WidgetInfo::update (bool wasAllocated, int xCB, int yCB, + int width, int height) +{ + DBG_OBJ_ENTER_O ("resize.oofm", 0, widget, "update", "%s, %d, %d, %d, %d", + wasAllocated ? "true" : "false", xCB, yCB, width, height); + + this->wasAllocated = wasAllocated; + this->xCB = xCB; + this->yCB = yCB; + this->width = width; + this->height = height; + + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.xCB", xCB); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.yCB", yCB); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.width", width); + DBG_OBJ_SET_NUM_O (widget, "<WidgetInfo>.height", height); + + DBG_OBJ_LEAVE_O (widget); +} + +// ---------------------------------------------------------------------- + +OOFFloatsMgr::Float::Float (OOFFloatsMgr *oofm, Widget *widget, + OOFAwareWidget *generatingBlock, int externalIndex) + : WidgetInfo (oofm, widget) +{ + this->generatingBlock = generatingBlock; + this->externalIndex = externalIndex; + + yReq = yReal = size.width = size.ascent = size.descent = 0; + dirty = sizeChangedSinceLastAllocation = true; + indexGBList = indexCBList = -1; + + // Sometimes a float with widget = NULL is created as a key; this + // is not interesting for RTFL. + if (widget) { + DBG_OBJ_SET_PTR_O (widget, "<Float>.generatingBlock", generatingBlock); + DBG_OBJ_SET_NUM_O (widget, "<Float>.externalIndex", externalIndex); + DBG_OBJ_SET_NUM_O (widget, "<Float>.yReq", yReq); + DBG_OBJ_SET_NUM_O (widget, "<Float>.yReal", yReal); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.width", size.width); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.ascent", size.ascent); + DBG_OBJ_SET_NUM_O (widget, "<Float>.size.descent", size.descent); + DBG_OBJ_SET_BOOL_O (widget, "<Float>.dirty", dirty); + DBG_OBJ_SET_BOOL_O (widget, "<Float>.sizeChangedSinceLastAllocation", + sizeChangedSinceLastAllocation); + } +} + +void OOFFloatsMgr::Float::updateAllocation () +{ + DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); + + update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), + getNewHeight ()); + + DBG_OBJ_LEAVE_O (getWidget ()); +} + +void OOFFloatsMgr::Float::intoStringBuffer(StringBuffer *sb) +{ + sb->append ("{ widget = "); + sb->appendPointer (getWidget ()); + + if (getWidget ()) { + sb->append (" ("); + sb->append (getWidget()->getClassName ()); + sb->append (")"); + } + + sb->append (", indexGBList = "); + sb->appendInt (indexGBList); + sb->append (", indexCBList = "); + sb->appendInt (indexCBList); + sb->append (", sideSpanningIndex = "); + sb->appendInt (sideSpanningIndex); + sb->append (", generatingBlock = "); + sb->appendPointer (generatingBlock); + sb->append (", yReq = "); + sb->appendInt (yReq); + sb->append (", yReal = "); + sb->appendInt (yReal); + sb->append (", size = { "); + sb->appendInt (size.width); + sb->append (" * "); + sb->appendInt (size.ascent); + sb->append (" + "); + sb->appendInt (size.descent); + sb->append (" }, dirty = "); + sb->appendBool (dirty); + sb->append (", sizeChangedSinceLastAllocation = "); + sb->appendBool (sizeChangedSinceLastAllocation); + sb->append (" }"); +} + +bool OOFFloatsMgr::Float::covers (OOFAwareWidget *textblock, int y, int h) +{ + DBG_OBJ_ENTER_O ("border", 0, getOOFFloatsMgr (), "covers", + "%p, %d, %d [vloat: %p]", + textblock, y, h, getWidget ()); + + bool b; + + if (textblock == generatingBlock) { + int reqyGB = y; + int flyGB = yReal; + getOOFFloatsMgr()->ensureFloatSize (this); + int flh = size.ascent + size.descent; + b = flyGB + flh > reqyGB && flyGB < reqyGB + h; + + DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (), + "for generator: reqyGB = %d, flyGB = %d, " + "flh = %d + %d = %d => %s", + reqyGB, flyGB, size.ascent, size.descent, flh, + b ? "true" : "false"); + } else { + // (If the textblock were not allocated, the GB list would have + // been choosen instead of the CB list, and so this else-branch + // would not have been not executed.) + assert (getOOFFloatsMgr()->wasAllocated (textblock)); + + if (!getWidget()->wasAllocated ()) { + DBG_OBJ_MSG_O ("border", 1, getOOFFloatsMgr (), + "not generator (not allocated) => false"); + b = false; + } else { + Allocation *tba = getOOFFloatsMgr()->getAllocation(textblock), + *fla = getWidget()->getAllocation (); + int reqyCanv = tba->y + y; + int flyCanv = fla->y; + int flh = fla->ascent + fla->descent; + b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h; + + DBG_OBJ_MSGF_O ("border", 1, getOOFFloatsMgr (), + "not generator (allocated): reqyCanv = %d + %d = %d, " + "flyCanv = %d, flh = %d + %d = %d => %s", + tba->y, y, reqyCanv, flyCanv, + fla->ascent, fla->descent, flh, b ? "true" : "false"); + } + } + + DBG_OBJ_LEAVE_O (getOOFFloatsMgr ()); + + return b; +} + +int OOFFloatsMgr::Float::ComparePosition::compare (Object *o1, Object *o2) +{ + Float *fl1 = (Float*)o1, *fl2 = (Float*)o2; + int r; + + DBG_OBJ_ENTER_O ("border", 1, oofm, + "ComparePosition/compare", "(#%d, #%d) [refTB = %p]", + fl1->getIndex (type), fl2->getIndex (type), refTB); + + if (refTB == fl1->generatingBlock && refTB == fl2->generatingBlock) { + DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is generating both floats"); + r = fl1->yReal - fl2->yReal; + } else { + DBG_OBJ_MSG_O ("border", 2, oofm, "refTB is not generating both floats"); + DBG_OBJ_MSG_START_O (oofm); + + DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p", + fl1->generatingBlock, fl2->generatingBlock); + + // (i) Floats may not yet been allocated. Non-allocated floats + // do not have an effect yet, they are considered "at the end" + // of the list. + + // (ii) Float::widget is NULL for the key used for binary + // search. In this case, Float::yReal is used instead (which is + // set in SortedFloatsVector::find, too). The generator is the + // textblock, and should be allocated. (If not, the GB list + // would have been choosen instead of the CB list, and so this + // else-branch would not have been not executed.) + + bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true; + bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true; + + DBG_OBJ_MSGF_O ("border", 2, oofm, + "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s", + fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (), + a2 ? "yes" : "no"); + + if (a1 && a2) { + int fly1, fly2; + + if (fl1->getWidget()) { + fly1 = fl1->getWidget()->getAllocation()->y; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1); + } else { + assert (oofm->wasAllocated (fl1->generatingBlock)); + fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d", + oofm->getAllocation(fl1->generatingBlock)->y, + fl1->yReal, fly1); + } + + if (fl2->getWidget()) { + fly2 = fl2->getWidget()->getAllocation()->y; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2); + } else { + assert (oofm->wasAllocated (fl2->generatingBlock)); + fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal; + DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d", + oofm->getAllocation(fl2->generatingBlock)->y, + fl2->yReal, fly2); + } + + r = fly1 - fly2; + + DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r); + } else if (a1 && !a2) + r = -1; + else if (!a1 && a2) + r = +1; + else // if (!a1 && !a2) + return 0; + + DBG_OBJ_MSG_END_O (oofm); + } + + DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::Float::CompareSideSpanningIndex::compare (Object *o1, + Object *o2) +{ + return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex; +} + +int OOFFloatsMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2) +{ + Float *f1 = (Float*)o1, *f2 = (Float*)o2; + int r = -123; // Compiler happiness: GCC 4.7 does not handle this?; + + DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare", + "#%d -> %p/%d, #%d -> %p/#%d", + f1->getIndex (type), f1->generatingBlock, f1->externalIndex, + f2->getIndex (type), f2->generatingBlock, + f2->externalIndex); + + if (f1->generatingBlock == f2->generatingBlock) { + r = f1->externalIndex - f2->externalIndex; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(a) generating blocks equal => %d - %d = %d", + f1->externalIndex, f2->externalIndex, r); + } else { + TBInfo *t1 = oofm->getOOFAwareWidget (f1->generatingBlock), + *t2 = oofm->getOOFAwareWidget (f2->generatingBlock); + bool rdef = false; + + for (TBInfo *t = t1; t != NULL; t = t->parent) + if (t->parent == t2) { + rdef = true; + r = t->parentExtIndex - f2->externalIndex; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(b) %p is an achestor of %p; direct child is " + "%p (%d) => %d - %d = %d\n", + t2->getOOFAwareWidget (), t1->getOOFAwareWidget (), + t->getOOFAwareWidget (), t->parentExtIndex, + t->parentExtIndex, f2->externalIndex, r); + } + + for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent) + if (t->parent == t1) { + r = f1->externalIndex - t->parentExtIndex; + rdef = true; + DBG_OBJ_MSGF_O ("border", 2, oofm, + "(c) %p is an achestor of %p; direct child is %p " + "(%d) => %d - %d = %d\n", + t1->getOOFAwareWidget (), t2->getOOFAwareWidget (), + t->getOOFAwareWidget (), t->parentExtIndex, + f1->externalIndex, t->parentExtIndex, r); + } + + if (!rdef) { + r = t1->index - t2->index; + DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d", + t1->index, t2->index, r); + } + } + + DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::SortedFloatsVector::findFloatIndex (OOFAwareWidget *lastGB, + int lastExtIndex) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d", + lastGB, lastExtIndex); + + Float key (oofm, NULL, lastGB, lastExtIndex); + key.setIndex (type, -1); // for debugging + Float::CompareGBAndExtIndex comparator (oofm, type); + int i = bsearch (&key, false, &comparator); + + // At position i is the next larger element, so element i should + // not included, but i - 1 returned; except if the exact element is + // found: then include it and so return i. + int r; + if (i == size()) + r = i - 1; + else { + Float *f = get (i); + if (comparator.compare (f, &key) == 0) + r = i; + else + r = i - 1; + } + + //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); " + // "in %s list %p on the %s side\n", + // oofm->container, lastGB, lastExtIndex, i, r, size (), + // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right"); + + //for (int i = 0; i < size (); i++) { + // Float *f = get(i); + // TBInfo *t = oofm->getOOFAwareWidget(f->generatingBlock); + // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock, + // t->index, t->parent ? t->parent->textblock : NULL, + // get(i)->externalIndex); + //} + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r); + DBG_OBJ_LEAVE_O (oofm); + return r; +} + +int OOFFloatsMgr::SortedFloatsVector::find (OOFAwareWidget *textblock, int y, + int start, int end) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d", + textblock, y, start, end); + + Float key (oofm, NULL, NULL, 0); + key.generatingBlock = textblock; + key.yReal = y; + key.setIndex (type, -1); // for debugging + Float::ComparePosition comparator (oofm, textblock, type); + int result = bsearch (&key, false, start, end, &comparator); + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); + DBG_OBJ_LEAVE_O (oofm); + return result; +} + +int OOFFloatsMgr::SortedFloatsVector::findFirst (OOFAwareWidget *textblock, + int y, int h, + OOFAwareWidget *lastGB, + int lastExtIndex, + int *lastReturn) +{ + DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d", + textblock, y, h, lastGB, lastExtIndex); + + DBG_IF_RTFL { + DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:"); + DBG_OBJ_MSG_START_O (oofm); + + for (int i = 0; i < size(); i++) { + DBG_OBJ_MSGF_O ("border", 2, oofm, + "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), " + "%s, %s, ext = %d, GB = %p); widget at (%d, %d)", + i, get(i)->getWidget (), get(i)->getIndex (type), + get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal, + get(i)->size.width, get(i)->size.ascent, + get(i)->size.descent, + get(i)->dirty ? "dirty" : "clean", + get(i)->sizeChangedSinceLastAllocation ? "scsla" + : "sNcsla", + get(i)->externalIndex, get(i)->generatingBlock, + get(i)->getWidget()->getAllocation()->x, + get(i)->getWidget()->getAllocation()->y); + } + + DBG_OBJ_MSG_END_O (oofm); + } + + int last = findFloatIndex (lastGB, lastExtIndex); + DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last); + assert (last < size()); + + // If the caller wants to reuse this value: + if (lastReturn) + *lastReturn = last; + + int i = find (textblock, y, 0, last), result; + DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i); + + // Note: The smallest value of "i" is 0, which means that "y" is before or + // equal to the first float. The largest value is "last + 1", which means + // that "y" is after the last float. In both cases, the first or last, + // respectively, float is a candidate. Generally, both floats, before and + // at the search position, are candidates. + + if (i > 0 && get(i - 1)->covers (textblock, y, h)) + result = i - 1; + else if (i <= last && get(i)->covers (textblock, y, h)) + result = i; + else + result = -1; + + DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); + DBG_OBJ_LEAVE_O (oofm); + return result; +} + +int OOFFloatsMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex + (int sideSpanningIndex) +{ + OOFFloatsMgr::Float::CompareSideSpanningIndex comparator; + Float key (NULL, NULL, NULL, 0); + key.sideSpanningIndex = sideSpanningIndex; + return bsearch (&key, false, &comparator) - 1; +} + +void OOFFloatsMgr::SortedFloatsVector::put (Float *vloat) +{ + lout::container::typed::Vector<Float>::put (vloat); + vloat->setIndex (type, size() - 1); +} + +OOFFloatsMgr::TBInfo::TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock, + TBInfo *parent, int parentExtIndex) : + WidgetInfo (oofm, textblock) +{ + this->parent = parent; + this->parentExtIndex = parentExtIndex; + + leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB); + rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB); + + wasAllocated = getWidget()->wasAllocated (); + allocation = *(getWidget()->getAllocation ()); + clearPosition = 0; +} + +OOFFloatsMgr::TBInfo::~TBInfo () +{ + delete leftFloatsGB; + delete rightFloatsGB; +} + +void OOFFloatsMgr::TBInfo::updateAllocation () +{ + DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); + + update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), + getNewHeight ()); + + DBG_OBJ_LEAVE_O (getWidget ()); +} + +OOFFloatsMgr::OOFFloatsMgr (OOFAwareWidget *container) +{ + DBG_OBJ_CREATE ("dw::OOFFloatsMgr"); + + this->container = (OOFAwareWidget*)container; + + leftFloatsCB = new SortedFloatsVector (this, LEFT, CB); + rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB); + + DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); + DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); + + leftFloatsAll = new Vector<Float> (1, true); + rightFloatsAll = new Vector<Float> (1, true); + + DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); + DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); + + floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false); + + tbInfos = new Vector<TBInfo> (1, false); + tbInfosByOOFAwareWidget = + new HashTable <TypedPointer <OOFAwareWidget>, TBInfo> (true, true); + + leftFloatsMark = rightFloatsMark = 0; + lastLeftTBIndex = lastRightTBIndex = 0; + + containerWasAllocated = container->wasAllocated (); + containerAllocation = *(container->getAllocation()); + + addWidgetInFlow (this->container, NULL, 0); +} + +OOFFloatsMgr::~OOFFloatsMgr () +{ + //printf ("OOFFloatsMgr::~OOFFloatsMgr\n"); + + delete leftFloatsCB; + delete rightFloatsCB; + + // Order is important: tbInfosByOOFAwareWidget is owner of the instances + // of TBInfo.tbInfosByOOFAwareWidget + delete tbInfos; + delete tbInfosByOOFAwareWidget; + + delete floatsByWidget; + + // Order is important, since the instances of Float are owned by + // leftFloatsAll and rightFloatsAll, so these should be deleted + // last. + delete leftFloatsAll; + delete rightFloatsAll; + + DBG_OBJ_DELETE (); +} + +void OOFFloatsMgr::sizeAllocateStart (OOFAwareWidget *caller, + Allocation *allocation) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart", + "%p, (%d, %d, %d * (%d + %d))", + caller, allocation->x, allocation->y, allocation->width, + allocation->ascent, allocation->descent); + + // Some callers are not registered, especially tables. (Where the + // floats manager is actually empty?) + TBInfo *oofAWInfo = getOOFAwareWidgetWhenRegistered (caller); + if (oofAWInfo) { + oofAWInfo->allocation = *allocation; + oofAWInfo->wasAllocated = true; + } + + if (caller == container) { + // In the size allocation process, the *first* OOFM method + // called is sizeAllocateStart, with the containing block as an + // argument. So this is the correct point to initialize size + // allocation. + + 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)); + } + + // The checks below do not cover "clear position" in all cases, + // so this is done here separately. This position is stored in + // TBInfo and calculated at this points; changes will be noticed + // to the textblock. + TBInfo *tbInfo = getOOFAwareWidget (caller); + int newClearPosition = calcClearPosition (caller); + if (newClearPosition != tbInfo->clearPosition) { + tbInfo->clearPosition = newClearPosition; + caller->clearPositionChanged (); + } + + if (caller == container) { + // In the size allocation process, the *last* OOFM method called + // is sizeAllocateEnd, with the containing block as an + // argument. So this is the correct point to finish size + // allocation. + + // Allocate all remaining floats. + sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1); + sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1); + + // Check changes of both textblocks and floats allocation. (All + // is checked by hasRelationChanged (...).) + for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> > + it = tbInfosByOOFAwareWidget->iterator (); + it.hasNext (); ) { + TypedPointer <OOFAwareWidget> *key = it.getNext (); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key); + OOFAwareWidget *tb = key->getTypedValue(); + + int minFloatPos; + Widget *minFloat; + if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat)) + tb->borderChanged (minFloatPos, minFloat); + } + + checkAllocatedFloatCollisions (LEFT); + checkAllocatedFloatCollisions (RIGHT); + + // Store some information for later use. + for (lout::container::typed::Iterator<TypedPointer <OOFAwareWidget> > + it = tbInfosByOOFAwareWidget->iterator (); + it.hasNext (); ) { + TypedPointer <OOFAwareWidget> *key = it.getNext (); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (key); + OOFAwareWidget *tb = key->getTypedValue(); + + tbInfo->updateAllocation (); + tbInfo->lineBreakWidth = tb->getLineBreakWidth (); + } + + // There are cases where some allocated floats (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, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *index) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d]", + area->x, area->y, area->width, area->height, *index); + + drawFloats (leftFloatsCB, view, area, iteratorStack, interruptedWidget, + index, 0); + if (*interruptedWidget == NULL) + drawFloats (rightFloatsCB, view, area, iteratorStack, interruptedWidget, + index, leftFloatsCB->size ()); + + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::drawFloats (SortedFloatsVector *list, View *view, + Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *index, + int startIndex) +{ + // This could be improved, since the list is sorted: search the + // first float fitting into the area, and iterate until one is + // found below the area. + + OOFAwareWidget::OOFStackingIterator *osi = + (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop (); + + while (*interruptedWidget == NULL && *index - startIndex < list->size()) { + Float *vloat = list->get(*index - startIndex); + Widget *childWidget = vloat->getWidget (); + + Rectangle childArea; + if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) && + !StackingContextMgr::handledByStackingContextMgr (childWidget) && + childWidget->intersects (area, &childArea)) + childWidget->drawTotal (view, &childArea, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)++; + } +} + +void OOFFloatsMgr::addWidgetInFlow (OOFAwareWidget *textblock, + OOFAwareWidget *parentBlock, + int externalIndex) +{ + //printf ("[%p] addWidgetInFlow (%p, %p, %d)\n", + // container, textblock, parentBlock, externalIndex); + + TBInfo *tbInfo = + new TBInfo (this, textblock, + parentBlock ? getOOFAwareWidget (parentBlock) : NULL, + externalIndex); + tbInfo->index = tbInfos->size(); + + tbInfos->put (tbInfo); + tbInfosByOOFAwareWidget->put (new TypedPointer<OOFAwareWidget> (textblock), + tbInfo); +} + +int OOFFloatsMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generatingBlock, + int externalIndex) +{ + DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d", + widget, generatingBlock, externalIndex); + + int subRef; + + TBInfo *tbInfo = getOOFAwareWidget (generatingBlock); + Float *vloat = new Float (this, widget, generatingBlock, externalIndex); + + // Note: Putting the float first in the GB list, and then, possibly + // into the CB list (in that order) will trigger setting + // Float::inCBList to the right value. + + switch (widget->getStyle()->vloat) { + case FLOAT_LEFT: + leftFloatsAll->put (vloat); + DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); + DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1, + "widget", vloat->getWidget ()); + + subRef = createSubRefLeftFloat (leftFloatsAll->size() - 1); + tbInfo->leftFloatsGB->put (vloat); + + if (wasAllocated (generatingBlock)) { + leftFloatsCB->put (vloat); + DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); + DBG_OBJ_ARRATTRSET_PTR ("leftFloatsCB", leftFloatsCB->size() - 1, + "widget", vloat->getWidget ()); + } else { + if (tbInfo->index < lastLeftTBIndex) + leftFloatsMark++; + + vloat->mark = leftFloatsMark; + lastLeftTBIndex = tbInfo->index; + } + break; + + case FLOAT_RIGHT: + rightFloatsAll->put (vloat); + DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); + DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1, + "widget", vloat->getWidget ()); + + subRef = createSubRefRightFloat (rightFloatsAll->size() - 1); + tbInfo->rightFloatsGB->put (vloat); + + if (wasAllocated (generatingBlock)) { + rightFloatsCB->put (vloat); + DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); + DBG_OBJ_ARRATTRSET_PTR ("rightFloatsCB", rightFloatsCB->size() - 1, + "widget", vloat->getWidget ()); + } else { + if (tbInfo->index < lastRightTBIndex) + rightFloatsMark++; + + vloat->mark = rightFloatsMark; + lastRightTBIndex = tbInfo->index; + } + + break; + + default: + assertNotReached(); + } + + // "sideSpanningIndex" is only compared, so this simple assignment + // is sufficient; differenciation between GB and CB lists is not + // neccessary. TODO: Can this also be applied to "index", to + // simplify the current code? Check: where is "index" used. + vloat->sideSpanningIndex = + leftFloatsAll->size() + rightFloatsAll->size() - 1; + + floatsByWidget->put (new TypedPointer<Widget> (widget), vloat); + + DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef); + DBG_OBJ_LEAVE (); + return subRef; +} + +void OOFFloatsMgr::moveExternalIndices (OOFAwareWidget *generatingBlock, + int oldStartIndex, int diff) +{ + TBInfo *tbInfo = getOOFAwareWidget (generatingBlock); + moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff); + moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff); +} + +void OOFFloatsMgr::moveExternalIndices (SortedFloatsVector *list, + int oldStartIndex, int diff) +{ + // Could be faster with binary search, but the GB (not CB!) lists + // should be rather small. + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + if (vloat->externalIndex >= oldStartIndex) { + vloat->externalIndex += diff; + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex", + vloat->externalIndex); + } + } +} + +OOFFloatsMgr::Float *OOFFloatsMgr::findFloatByWidget (Widget *widget) +{ + TypedPointer <Widget> key (widget); + Float *vloat = floatsByWidget->get (&key); + assert (vloat != NULL); + return vloat; +} + +void OOFFloatsMgr::markSizeChange (int ref) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref); + + Float *vloat; + + if (isSubRefLeftFloat (ref)) + vloat = leftFloatsAll->get (getFloatIndexFromSubRef (ref)); + else if (isSubRefRightFloat (ref)) + vloat = rightFloatsAll->get (getFloatIndexFromSubRef (ref)); + else { + assertNotReached(); + vloat = NULL; // compiler happiness + } + + vloat->dirty = vloat->sizeChangedSinceLastAllocation = true; + + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), + "<Float>.sizeChangedSinceLastAllocation", + vloat->sizeChangedSinceLastAllocation); + + // The generating block is told directly about this. (Others later, in + // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which + // differentiates many special cases), but the size is not known yet, + vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ()); + + DBG_OBJ_LEAVE (); +} + + +void OOFFloatsMgr::markExtremesChange (int ref) +{ + // Nothing to do here. +} + +Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y, + core::StackingIteratorStack + *iteratorStack, + core::Widget **interruptedWidget, + int *index) +{ + Widget *widgetAtPoint = NULL; + + widgetAtPoint = + getFloatWidgetAtPoint (rightFloatsCB, x, y, iteratorStack, + interruptedWidget, index, + leftFloatsCB->size ()); + if (widgetAtPoint == NULL && *interruptedWidget == NULL) + widgetAtPoint = + getFloatWidgetAtPoint (leftFloatsCB, x, y, iteratorStack, + interruptedWidget, index, 0); + return widgetAtPoint; +} + +Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x, + int y, + StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int *index, int startIndex) +{ + // Could use binary search to be faster (similar to drawing). + Widget *widgetAtPoint = NULL; + OOFAwareWidget::OOFStackingIterator *osi = + (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop (); + + while (widgetAtPoint == NULL && *interruptedWidget == NULL && + *index - startIndex >= 0) { + Widget *childWidget = list->get(*index)->getWidget (); + if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) && + !StackingContextMgr::handledByStackingContextMgr (childWidget)) + widgetAtPoint = + childWidget->getWidgetAtPointTotal (x, y, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)--; + } + + return widgetAtPoint; +} + +void OOFFloatsMgr::tellPosition (Widget *widget, int x, int y) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d, %d", + widget, x, y); + + assert (y >= 0); + + Float *vloat = findFloatByWidget(widget); + + SortedFloatsVector *listSame, *listOpp; + Side side; + getFloatsListsAndSide (vloat, &listSame, &listOpp, &side); + ensureFloatSize (vloat); + + // "yReal" may change due to collisions (see below). + vloat->yReq = vloat->yReal = y; + + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq); + DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); + + // Test collisions (on this side). Although there are (rare) cases + // where it could make sense, the horizontal dimensions are not + // tested; especially since searching and border calculation would + // be confused. For this reaspn, only the previous float is + // relevant. (Cf. below, collisions on the other side.) + int index = vloat->getIndex (listSame->type), yRealNew; + if (index >= 1 && + collidesV (vloat, listSame->get (index - 1), listSame->type, + &yRealNew)) { + 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 { + // If the other float is not allocated, there is no collision. The + // allocation of this float (vloat) is not used at all. + if (!other->getWidget()->wasAllocated ()) + result = false; + else { + assert (wasAllocated (vloat->generatingBlock)); + Allocation *gba = getAllocation (vloat->generatingBlock), + *flaOther = other->getWidget()->getAllocation (); + 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 { + // Again, if the other float is not allocated, there is no + // collision. Compare to collidesV. (But vloat->size is used + // here.) + if (!other->getWidget()->wasAllocated ()) + collidesH = false; + else { + assert (wasAllocated (vloat->generatingBlock)); + Allocation *gba = getAllocation (vloat->generatingBlock); + int vloatX = + calcFloatX (vloat, + vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ? + LEFT : RIGHT, + gba->x, gba->width, + vloat->generatingBlock->getLineBreakWidth ()); + + // Generally: right border of the left float > left border of + // the right float (all in canvas coordinates). + if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT) + // "vloat" is left, "other" is right + collidesH = vloatX + vloat->size.width + > other->getWidget()->getAllocation()->x; + else + // "other" is left, "vloat" is right + collidesH = other->getWidget()->getAllocation()->x + + other->getWidget()->getAllocation()->width + > vloatX; + } + } + + return collidesH; +} + +void OOFFloatsMgr::getFloatsListsAndSide (Float *vloat, + SortedFloatsVector **listSame, + SortedFloatsVector **listOpp, + Side *side) +{ + TBInfo *tbInfo = getOOFAwareWidget (vloat->generatingBlock); + + switch (vloat->getWidget()->getStyle()->vloat) { + case FLOAT_LEFT: + if (wasAllocated (vloat->generatingBlock)) { + if (listSame) *listSame = leftFloatsCB; + if (listOpp) *listOpp = rightFloatsCB; + } else { + if (listSame) *listSame = tbInfo->leftFloatsGB; + if (listOpp) *listOpp = tbInfo->rightFloatsGB; + } + if (side) *side = LEFT; + break; + + case FLOAT_RIGHT: + if (wasAllocated (vloat->generatingBlock)) { + if (listSame) *listSame = rightFloatsCB; + if (listOpp) *listOpp = leftFloatsCB; + } else { + if (listSame) *listSame = tbInfo->rightFloatsGB; + if (listOpp) *listOpp = tbInfo->leftFloatsGB; + } + if (side) *side = RIGHT; + break; + + default: + assertNotReached(); + } +} + +void OOFFloatsMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight) +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); + + int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight; + getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft); + getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight); + + // Floats must be within the *content* area of the containing + // block, not its *margin* area (which is equivalent to the + // requisition / allocation). For this reason, boxRestWidth() and + // boxRestHeight() are added here. + + *oofWidth = + max (oofWidthtLeft, oofWidthRight) + container->boxRestWidth (); + *oofHeight = + max (oofHeightLeft, oofHeightRight) + container->boxRestHeight (); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)", + oofWidthtLeft, oofWidthRight, *oofWidth, oofHeightLeft, + oofHeightRight, *oofHeight); + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::getFloatsSize (Requisition *cbReq, Side side, int *width, + int *height) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...", + cbReq->width, cbReq->ascent, cbReq->descent, + side == LEFT ? "LEFT" : "RIGHT"); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side); + + *width = *height = 0; + + DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size()); + + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + + if (vloat->generatingBlock == container || + wasAllocated (vloat->generatingBlock)) { + ensureFloatSize (vloat); + int x, y; + + if (vloat->generatingBlock == container) { + x = calcFloatX (vloat, side, 0, cbReq->width, + vloat->generatingBlock->getLineBreakWidth ()); + y = vloat->yReal; + } else { + Allocation *gba = getAllocation(vloat->generatingBlock); + x = calcFloatX (vloat, side, + gba->x - containerAllocation.x, gba->width, + vloat->generatingBlock->getLineBreakWidth ()); + y = gba->y - containerAllocation.y + vloat->yReal; + } + + *width = max (*width, x + vloat->size.width); + *height = max (*height, y + vloat->size.ascent + vloat->size.descent); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: (%d + %d) * " + "(%d + (%d + %d)) => %d * %d", + vloat->getWidget (), vloat->generatingBlock, + x, vloat->size.width, + y, vloat->size.ascent, vloat->size.descent, + *width, *height); + } else + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: not allocated", + vloat->getWidget (), vloat->generatingBlock); + } + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::containerMustAdjustExtraSpace () +{ + return false; +} + +void OOFFloatsMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth, + int *oofMaxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", + cbExtr->minWidth, cbExtr->maxWidth); + + int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight; + getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft); + getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight); + + *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight); + *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)", + oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth, + oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth); + DBG_OBJ_LEAVE (); +} + +void OOFFloatsMgr::getFloatsExtremes (Extremes *cbExtr, Side side, + int *minWidth, int *maxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...", + cbExtr->minWidth, cbExtr->maxWidth, + side == LEFT ? "LEFT" : "RIGHT"); + + *minWidth = *maxWidth = 0; + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (container, side); + DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size()); + + for (int i = 0; i < list->size(); i++) { + Float *vloat = list->get(i); + int leftDiff, rightDiff; + + if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) { + Extremes extr; + vloat->getWidget()->getExtremes (&extr); + + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: %d / %d", + vloat->getWidget (), vloat->generatingBlock, + extr.minWidth, extr.maxWidth); + + // TODO: Or zero (instead of rightDiff) for right floats? + *minWidth = + max (*minWidth, + extr.minWidth + (side == LEFT ? leftDiff : rightDiff)); + *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff); + + DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth); + } else + DBG_OBJ_MSGF ("resize.oofm", 1, + "considering float %p generated by %p: not allocated", + vloat->getWidget (), vloat->generatingBlock); + } + + DBG_OBJ_LEAVE (); +} + +// Returns "false" when borders cannot yet determined; *leftDiff and +// *rightDiff are undefined in this case. +bool OOFFloatsMgr::getFloatDiffToCB (Float *vloat, int *leftDiff, + int *rightDiff) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB", + "float %p [generated by %p], ...", + vloat->getWidget (), vloat->generatingBlock); + + bool result; + + if (vloat->generatingBlock == container) { + *leftDiff = vloat->generatingBlock->boxOffsetX(); + *rightDiff = vloat->generatingBlock->boxRestWidth(); + result = true; + DBG_OBJ_MSGF ("resize.oofm", 1, + "GB == CB => leftDiff = %d, rightDiff = %d", + *leftDiff, *rightDiff); + } else if (wasAllocated (vloat->generatingBlock)) { + Allocation *gba = getAllocation(vloat->generatingBlock); + *leftDiff = gba->x - containerAllocation.x + + vloat->generatingBlock->boxOffsetX(); + *rightDiff = + (containerAllocation.x + containerAllocation.width) + - (gba->x + gba->width) + + vloat->generatingBlock->boxRestWidth(); + result = true; + DBG_OBJ_MSGF ("resize.oofm", 1, + "GB != CB => leftDiff = %d - %d + %d = %d, " + "rightDiff = (%d + %d) - (%d + %d) + %d = %d", + gba->x, containerAllocation.x, + vloat->generatingBlock->boxOffsetX(), *leftDiff, + containerAllocation.x, containerAllocation.width, + gba->x, gba->width, vloat->generatingBlock->boxRestWidth(), + *rightDiff); + } else { + DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated"); + result = false; + } + + DBG_OBJ_LEAVE (); + return result; +} + +OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidgetWhenRegistered + (OOFAwareWidget *widget) +{ + DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidgetWhenRegistered", "%p", + widget); + TypedPointer<OOFAwareWidget> key (widget); + TBInfo *tbInfo = tbInfosByOOFAwareWidget->get (&key); + DBG_OBJ_MSGF ("oofm.common", 1, "found? %s", tbInfo ? "yes" : "no"); + DBG_OBJ_LEAVE (); + return tbInfo; +} + +OOFFloatsMgr::TBInfo *OOFFloatsMgr::getOOFAwareWidget (OOFAwareWidget *widget) +{ + DBG_OBJ_ENTER ("oofm.common", 0, "getOOFAwareWidget", "%p", widget); + TBInfo *tbInfo = getOOFAwareWidgetWhenRegistered (widget); + assert (tbInfo); + DBG_OBJ_LEAVE (); + return tbInfo; +} + +/** + * Get the left border for the vertical position of *y*, for a height + * of *h", based on floats; relative to the allocation of the calling + * textblock. + * + * The border includes marging/border/padding of the calling textblock + * but is 0 if there is no float, so a caller should also consider + * other borders. + */ +int OOFFloatsMgr::getLeftBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d", + textblock, y, h, lastGB, lastExtIndex, b); + return b; +} + +/** + * Get the right border for the vertical position of *y*, for a height + * of *h*, based on floats. + * + * See also getLeftBorder(int, int); + */ +int OOFFloatsMgr::getRightBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d", + textblock, y, h, lastGB, lastExtIndex, b); + return b; +} + +int OOFFloatsMgr::getBorder (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int last; + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last); + + DBG_OBJ_MSGF ("border", 1, "first = %d", first); + + if (first == -1) { + // No float. + DBG_OBJ_LEAVE (); + return 0; + } else { + // It is not sufficient to find the first float, since a line + // (with height h) may cover the region of multiple float, of + // which the widest has to be choosen. + int border = 0; + bool covers = true; + + // We are not searching until the end of the list, but until the + // float defined by lastGB and lastExtIndex. + for (int i = first; covers && i <= last; i++) { + Float *vloat = list->get(i); + covers = vloat->covers (textblock, y, h); + DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.", + i, vloat->getWidget(), covers ? "<b>yes</b>" : "no"); + + if (covers) { + int thisBorder; + if (vloat->generatingBlock == textblock) { + int borderIn = side == LEFT ? + vloat->generatingBlock->boxOffsetX() : + vloat->generatingBlock->boxRestWidth(); + thisBorder = vloat->size.width + borderIn; + DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d", + vloat->size.width, borderIn, thisBorder); + } else { + assert (wasAllocated (vloat->generatingBlock)); + assert (vloat->getWidget()->wasAllocated ()); + + Allocation *tba = getAllocation(textblock), + *fla = vloat->getWidget()->getAllocation (); + if (side == LEFT) { + thisBorder = fla->x + fla->width - tba->x; + DBG_OBJ_MSGF ("border", 1, + "not GB: thisBorder = %d + %d - %d = %d", + fla->x, fla->width, tba->x, thisBorder); + } else { + // See also calcFloatX. + thisBorder = + tba->x + textblock->getLineBreakWidth () - fla->x; + DBG_OBJ_MSGF ("border", 1, + "not GB: thisBorder = %d + %d - %d " + "= %d", + tba->x, textblock->getLineBreakWidth (), fla->x, + thisBorder); + } + } + + border = max (border, thisBorder); + DBG_OBJ_MSGF ("border", 1, "=> border = %d", border); + } + } + + DBG_OBJ_LEAVE (); + return border; + } +} + + +OOFFloatsMgr::SortedFloatsVector *OOFFloatsMgr::getFloatsListForOOFAwareWidget + (OOFAwareWidget *textblock, Side side) +{ + DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForOOFAwareWidget", "%p, %s", + textblock, side == LEFT ? "LEFT" : "RIGHT"); + + OOFFloatsMgr::SortedFloatsVector *list; + + if (wasAllocated (textblock)) { + DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list"); + list = side == LEFT ? leftFloatsCB : rightFloatsCB; + } else { + DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list"); + TBInfo *tbInfo = getOOFAwareWidget (textblock); + list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; + } + + DBG_OBJ_LEAVE (); + return list; +} + + +bool OOFFloatsMgr::hasFloatLeft (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s", + textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); + return b; +} + +bool OOFFloatsMgr::hasFloatRight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex); + DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s", + textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); + return b; +} + +bool OOFFloatsMgr::hasFloat (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); + + DBG_OBJ_MSGF ("border", 1, "first = %d", first); + DBG_OBJ_LEAVE (); + return first != -1; +} + +int OOFFloatsMgr::getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex); +} + +int OOFFloatsMgr::getRightFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex) +{ + return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex); +} + +// Calculate height from the position *y*. +int OOFFloatsMgr::getFloatHeight (OOFAwareWidget *textblock, Side side, int y, + int h, OOFAwareWidget *lastGB, + int lastExtIndex) +{ + DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d", + textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, + lastGB, lastExtIndex); + + SortedFloatsVector *list = getFloatsListForOOFAwareWidget (textblock, side); + int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); + assert (first != -1); /* This method must not be called when there is no + float on the respective side. */ + + Float *vloat = list->get(first); + int yRelToFloat; + + if (vloat->generatingBlock == textblock) { + yRelToFloat = y - vloat->yReal; + DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d", + y, vloat->yReal, yRelToFloat); + } else { + // The respective widgets are allocated; otherwise, hasFloat() would have + // returned false. + assert (wasAllocated (textblock)); + assert (vloat->getWidget()->wasAllocated ()); + + Allocation *tba = getAllocation(textblock), + *fla = vloat->getWidget()->getAllocation (); + yRelToFloat = tba->y + y - fla->y; + + DBG_OBJ_MSGF ("border", 1, + "caller is not CB: yRelToFloat = %d + %d - %d = %d", + tba->y, y, fla->y, yRelToFloat); + } + + ensureFloatSize (vloat); + int height = vloat->size.ascent + vloat->size.descent - yRelToFloat; + + DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d", + vloat->size.ascent, vloat->size.descent, yRelToFloat, height); + DBG_OBJ_LEAVE (); + return height; +} + +/** + * Returns position relative to the textblock "tb". + */ +int OOFFloatsMgr::getClearPosition (OOFAwareWidget *textblock) +{ + return getOOFAwareWidget(textblock)->clearPosition; +} + +int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", textblock); + + int pos; + + if (textblock->getStyle()) { + bool left = false, right = false; + switch (textblock->getStyle()->clear) { + case CLEAR_NONE: break; + case CLEAR_LEFT: left = true; break; + case CLEAR_RIGHT: right = true; break; + case CLEAR_BOTH: left = right = true; break; + default: assertNotReached (); + } + + pos = max (left ? calcClearPosition (textblock, LEFT) : 0, + right ? calcClearPosition (textblock, RIGHT) : 0); + } else + pos = 0; + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos); + DBG_OBJ_LEAVE (); + + return pos; +} + +bool OOFFloatsMgr::affectsLeftBorder (core::Widget *widget) +{ + return widget->getStyle()->vloat == core::style::FLOAT_LEFT; +} + +bool OOFFloatsMgr::affectsRightBorder (core::Widget *widget) +{ + return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; +}; + +bool OOFFloatsMgr::mayAffectBordersAtAll () +{ + return true; +} + +int OOFFloatsMgr::calcClearPosition (OOFAwareWidget *textblock, Side side) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s", + textblock, side == LEFT ? "LEFT" : "RIGHT"); + + int pos; + + if (!wasAllocated (textblock)) + // There is no relation yet to floats generated by other + // textblocks, and this textblocks floats are unimportant for + // the "clear" property. + pos = 0; + else { + SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; + + // Search the last float before (therfore -1) this textblock. + int i = list->findFloatIndex (textblock, -1); + if (i < 0) { + pos = 0; + DBG_OBJ_MSG ("resize.oofm", 1, "no float"); + } else { + Float *vloat = list->get(i); + assert (vloat->generatingBlock != textblock); + if (!wasAllocated (vloat->generatingBlock)) + pos = 0; // See above. + else { + ensureFloatSize (vloat); + pos = max (getAllocation(vloat->generatingBlock)->y + vloat->yReal + + vloat->size.ascent + vloat->size.descent + - getAllocation(textblock)->y, + 0); + DBG_OBJ_MSGF ("resize.oofm", 1, + "float %p => max (%d + %d + (%d + %d) - %d, 0)", + vloat->getWidget (), + getAllocation(vloat->generatingBlock)->y, + vloat->yReal, vloat->size.ascent, vloat->size.descent, + getAllocation(textblock)->y); + } + } + } + + DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos); + DBG_OBJ_LEAVE (); + + return pos; +} + +void OOFFloatsMgr::ensureFloatSize (Float *vloat) +{ + // Historical note: relative sizes (e. g. percentages) are already + // handled by (at this time) Layout::containerSizeChanged, so + // Float::dirty will be set. + + DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p", + vloat->getWidget ()); + + if (vloat->dirty) { + DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation"); + + vloat->getWidget()->sizeRequest (&vloat->size); + vloat->cbLineBreakWidth = container->getLineBreakWidth (); + vloat->dirty = false; + DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); + + DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)", + vloat->size.width, vloat->size.ascent, vloat->size.descent); + + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width", + vloat->size.width); + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent", + vloat->size.ascent); + DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent", + vloat->size.descent); + + // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd() + } + + DBG_OBJ_LEAVE (); +} + +bool OOFFloatsMgr::dealingWithSizeOfChild (core::Widget *child) +{ + return false; +} + +int OOFFloatsMgr::getAvailWidthOfChild (Widget *child, bool forceValue) +{ + assertNotReached (); + return 0; +} + +int OOFFloatsMgr::getAvailHeightOfChild (Widget *child, bool forceValue) +{ + assertNotReached (); + return 0; +} + +int OOFFloatsMgr::getNumWidgets () +{ + return leftFloatsAll->size() + rightFloatsAll->size(); +} + +Widget *OOFFloatsMgr::getWidget (int i) +{ + if (i < leftFloatsAll->size()) + return leftFloatsAll->get(i)->getWidget (); + else + return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget (); +} + +} // namespace oof + +} // namespace dw diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh new file mode 100644 index 00000000..f847d614 --- /dev/null +++ b/dw/ooffloatsmgr.hh @@ -0,0 +1,408 @@ +#ifndef __DW_OOFFLOATSMGR_HH__ +#define __DW_OOFFLOATSMGR_HH__ + +#include "outofflowmgr.hh" + +namespace dw { + +namespace oof { + +/** + * \brief OutOfFlowMgr implementation dealing with floats. + * + * Note: The identifiers and comments of this class still refer to + * "Textblock" instead of "OOFAwareWidget"; should be cleaned up some + * day. (OTOH, these widgets are always textblocks.) + */ +class OOFFloatsMgr: public OutOfFlowMgr +{ + friend class WidgetInfo; + +private: + enum Side { LEFT, RIGHT }; + enum SFVType { GB, CB }; + + OOFAwareWidget *container; + + // These two values are redundant to TBInfo::wasAllocated and + // TBInfo::allocation, for some special cases. + bool containerWasAllocated; + core::Allocation containerAllocation; + + class WidgetInfo: public lout::object::Object + { + private: + bool wasAllocated; + int xCB, yCB; // relative to the containing block + int width, height; + + OOFFloatsMgr *oofm; + core::Widget *widget; + + protected: + OOFFloatsMgr *getOOFFloatsMgr () { return oofm; } + + public: + WidgetInfo (OOFFloatsMgr *oofm, core::Widget *widget); + + inline bool wasThenAllocated () { return wasAllocated; } + inline int getOldXCB () { return xCB; } + inline int getOldYCB () { return yCB; } + inline int getOldWidth () { return width; } + inline int getOldHeight () { return height; } + + + void update (bool wasAllocated, int xCB, int yCB, int width, int height); + + inline core::Widget *getWidget () { return widget; } + }; + + class Float: public WidgetInfo + { + public: + class ComparePosition: public lout::object::Comparator + { + private: + OOFFloatsMgr *oofm; + OOFAwareWidget *refTB; + SFVType type; // actually only used for debugging + + public: + ComparePosition (OOFFloatsMgr *oofm, OOFAwareWidget *refTB, + SFVType type) + { this->oofm = oofm; this->refTB = refTB; this->type = type; } + int compare(Object *o1, Object *o2); + }; + + class CompareSideSpanningIndex: public lout::object::Comparator + { + public: + int compare(Object *o1, Object *o2); + }; + + class CompareGBAndExtIndex: public lout::object::Comparator + { + private: + OOFFloatsMgr *oofm; + SFVType type; // actually only used for debugging + + public: + CompareGBAndExtIndex (OOFFloatsMgr *oofm, SFVType type) + { this->oofm = oofm; this->type = type; } + int compare(Object *o1, Object *o2); + }; + + OOFAwareWidget *generatingBlock; + int externalIndex; + int yReq, yReal; // relative to generator, not container + int indexGBList; /* Refers to TBInfo::leftFloatsGB or + TBInfo::rightFloatsGB, respectively. -1 + initially. */ + int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB, + respectively. -1 initially. */ + int sideSpanningIndex, mark; + core::Requisition size; + int cbLineBreakWidth; /* On which the calculation of relative sizes + is based. Height not yet used, and probably + not added before size redesign. */ + bool dirty, sizeChangedSinceLastAllocation; + + Float (OOFFloatsMgr *oofm, core::Widget *widget, + OOFAwareWidget *generatingBlock, int externalIndex); + + inline bool isNowAllocated () { return getWidget()->wasAllocated (); } + inline int getNewXCB () { return getWidget()->getAllocation()->x - + getOOFFloatsMgr()->containerAllocation.x; } + inline int getNewYCB () { return getWidget()->getAllocation()->y - + getOOFFloatsMgr()->containerAllocation.y; } + inline int getNewWidth () { return getWidget()->getAllocation()->width; } + inline int getNewHeight () { return getWidget()->getAllocation()->ascent + + getWidget()->getAllocation()->descent; } + void updateAllocation (); + + inline int *getIndexRef (SFVType type) { + return type == GB ? &indexGBList : &indexCBList; } + inline int getIndex (SFVType type) { return *(getIndexRef (type)); } + inline void setIndex (SFVType type, int value) { + *(getIndexRef (type)) = value; } + + void intoStringBuffer(lout::misc::StringBuffer *sb); + + bool covers (OOFAwareWidget *textblock, int y, int h); + }; + + /** + * This list is kept sorted. + * + * To prevent accessing methods of the base class in an + * uncontrolled way, the inheritance is private, not public; this + * means that all methods must be delegated (see iterator(), size() + * etc. below.) + * + * TODO Update comment: still sorted, but ... + * + * More: add() and change() may check order again. + */ + class SortedFloatsVector: private lout::container::typed::Vector<Float> + { + public: + SFVType type; + + private: + OOFFloatsMgr *oofm; + Side side; + + public: + inline SortedFloatsVector (OOFFloatsMgr *oofm, Side side, SFVType type) : + lout::container::typed::Vector<Float> (1, false) + { this->oofm = oofm; this->side = side; this->type = type; } + + int findFloatIndex (OOFAwareWidget *lastGB, int lastExtIndex); + int find (OOFAwareWidget *textblock, int y, int start, int end); + int findFirst (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex, int *lastReturn); + int findLastBeforeSideSpanningIndex (int sideSpanningIndex); + void put (Float *vloat); + + inline lout::container::typed::Iterator<Float> iterator() + { return lout::container::typed::Vector<Float>::iterator (); } + inline int size () + { return lout::container::typed::Vector<Float>::size (); } + inline Float *get (int pos) + { return lout::container::typed::Vector<Float>::get (pos); } + inline void clear () + { lout::container::typed::Vector<Float>::clear (); } + }; + + class TBInfo: public WidgetInfo + { + public: + int lineBreakWidth; + int index; // position within "tbInfos" + + TBInfo *parent; + int parentExtIndex; + + // These two values are set by sizeAllocateStart(), and they are + // accessable also within sizeAllocateEnd() for the same + // textblock, for which allocation and WAS_ALLOCATED is set + // *after* sizeAllocateEnd(). See the two functions + // wasAllocated(Widget*) and getAllocation(Widget*) (further + // down) for usage. + bool wasAllocated; + core::Allocation allocation; + int clearPosition; + + // These two lists store all floats generated by this textblock, + // as long as this textblock is not allocates. + SortedFloatsVector *leftFloatsGB, *rightFloatsGB; + + TBInfo (OOFFloatsMgr *oofm, OOFAwareWidget *textblock, + TBInfo *parent, int parentExtIndex); + ~TBInfo (); + + inline bool isNowAllocated () { + return getOOFFloatsMgr()->wasAllocated (getOOFAwareWidget ()); } + inline int getNewXCB () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->x - + getOOFFloatsMgr()->containerAllocation.x; } + inline int getNewYCB () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->y - + getOOFFloatsMgr()->containerAllocation.y; } + inline int getNewWidth () { + return getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ())->width; } + inline int getNewHeight () { + core::Allocation *allocation = + getOOFFloatsMgr()->getAllocation (getOOFAwareWidget ()); + return allocation->ascent + allocation->descent; } + void updateAllocation (); + + inline OOFAwareWidget *getOOFAwareWidget () + { return (OOFAwareWidget*)getWidget (); } + }; + + // These two lists store all floats, in the order in which they are + // defined. Only used for iterators. + lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll; + + // These two lists store all floats whose generators are already + // allocated. + SortedFloatsVector *leftFloatsCB, *rightFloatsCB; + + // These two attributes are used in the size allocation process; + // see sizeAllocateStart and sizeAllocateEnd. + int lastAllocatedLeftFloat, lastAllocatedRightFloat; + + lout::container::typed::HashTable<lout::object::TypedPointer + <dw::core::Widget>, Float> *floatsByWidget; + + lout::container::typed::Vector<TBInfo> *tbInfos; + lout::container::typed::HashTable<lout::object::TypedPointer<OOFAwareWidget>, + TBInfo> *tbInfosByOOFAwareWidget; + + int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark; + + /** + * Variant of Widget::wasAllocated(), which can also be used within + * OOFM::sizeAllocateEnd(). + */ + inline bool wasAllocated (OOFAwareWidget *textblock) { + return getOOFAwareWidget(textblock)->wasAllocated; + } + + /** + * Variant of Widget::getAllocation(), which can also be used + * within OOFM::sizeAllocateEnd(). + */ + inline core::Allocation *getAllocation (OOFAwareWidget *textblock) { + return &(getOOFAwareWidget(textblock)->allocation); + } + + void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex, + int diff); + Float *findFloatByWidget (core::Widget *widget); + + void moveFromGBToCB (Side side); + void sizeAllocateFloats (Side side, int newLastAllocatedFloat); + int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, + int gbLineBreakWidth); + + bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos, + core::Widget **minFloat); + bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos, + core::Widget **minFloat); + bool hasRelationChanged (bool oldTBAlloc, + int oldTBx, int oldTBy, int oldTBw, int oldTBh, + int newTBx, int newTBy, int newTBw, int newTBh, + bool oldFlAlloc, + int oldFlx, int oldFly, int oldFlw, int oldFlh, + int newFlx, int newFly, int newFlw, int newFlh, + Side side, int *floatPos); + + void checkAllocatedFloatCollisions (Side side); + + bool doFloatsExceedCB (Side side); + bool haveExtremesChanged (Side side); + + void drawFloats (SortedFloatsVector *list, core::View *view, + core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, int *index, + int startIndex); + core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, + core::StackingIteratorStack + *iteratorStack, + core::Widget **interruptedWidget, + int *index, int startIndex); + + bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal); + bool collidesH (Float *vloat, Float *other, SFVType type); + + void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame, + SortedFloatsVector **listOpp, Side *side); + + void getFloatsSize (core::Requisition *cbReq, Side side, int *width, + int *height); + void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth, + int *maxWidth); + bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff); + + TBInfo *getOOFAwareWidget (OOFAwareWidget *widget); + TBInfo *getOOFAwareWidgetWhenRegistered (OOFAwareWidget *widget); + inline bool isOOFAwareWidgetRegistered (OOFAwareWidget *widget) + { return getOOFAwareWidgetWhenRegistered (widget) != NULL; } + int getBorder (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + SortedFloatsVector *getFloatsListForOOFAwareWidget (OOFAwareWidget + *textblock, + Side side); + bool hasFloat (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int getFloatHeight (OOFAwareWidget *textblock, Side side, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int calcClearPosition (OOFAwareWidget *textblock); + int calcClearPosition (OOFAwareWidget *textblock, Side side); + + void ensureFloatSize (Float *vloat); + + inline static int createSubRefLeftFloat (int index) { return index << 1; } + inline static int createSubRefRightFloat (int index) + { return (index << 1) | 1; } + + inline static bool isSubRefLeftFloat (int ref) + { return ref != -1 && (ref & 1) == 0; } + inline static bool isSubRefRightFloat (int ref) + { return ref != -1 && (ref & 1) == 1; } + + inline static int getFloatIndexFromSubRef (int ref) + { return ref == -1 ? ref : (ref >> 1); } + +public: + OOFFloatsMgr (OOFAwareWidget *container); + ~OOFFloatsMgr (); + + void sizeAllocateStart (OOFAwareWidget *caller, + core::Allocation *allocation); + void sizeAllocateEnd (OOFAwareWidget *caller); + void containerSizeChangedForChildren (); + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, int *index); + + void markSizeChange (int ref); + void markExtremesChange (int ref); + core::Widget *getWidgetAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, + int *index); + + void addWidgetInFlow (OOFAwareWidget *textblock, OOFAwareWidget *parentBlock, + int externalIndex); + int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generatingBlock, + int externalIndex); + void moveExternalIndices (OOFAwareWidget *generatingBlock, int oldStartIndex, + int diff); + + void tellPosition (core::Widget *widget, int x, int y); + + void getSize (core::Requisition *cbReq, int *oofWidth, int *oofHeight); + bool containerMustAdjustExtraSpace (); + void getExtremes (core::Extremes *cbExtr, + int *oofMinWidth, int *oofMaxWidth); + + int getLeftBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + int getRightBorder (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + bool hasFloatLeft (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + bool hasFloatRight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + int getLeftFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + int getRightFloatHeight (OOFAwareWidget *textblock, int y, int h, + OOFAwareWidget *lastGB, int lastExtIndex); + + bool affectsLeftBorder (core::Widget *widget); + bool affectsRightBorder (core::Widget *widget); + bool mayAffectBordersAtAll (); + + int getClearPosition (OOFAwareWidget *textblock); + + bool dealingWithSizeOfChild (core::Widget *child); + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + + int getNumWidgets (); + core::Widget *getWidget (int i); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFFLOATSMGR_HH__ diff --git a/dw/oofposabsmgr.cc b/dw/oofposabsmgr.cc new file mode 100644 index 00000000..07daca86 --- /dev/null +++ b/dw/oofposabsmgr.cc @@ -0,0 +1,69 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofposabsmgr.hh" +#include "oofawarewidget.hh" + +namespace dw { + +namespace oof { + +OOFPosAbsMgr::OOFPosAbsMgr (OOFAwareWidget *container) : + OOFPositionedMgr (container) +{ + DBG_OBJ_CREATE ("dw::OOFPosAbsMgr"); +} + +OOFPosAbsMgr::~OOFPosAbsMgr () +{ + DBG_OBJ_DELETE (); +} + +// Comment for all containerBox* implementations: for the toplevel +// widget, assume margin = border = 0 (should perhaps set so when +// widgets are constructed), so that the padding area is actually the +// allocation. + +int OOFPosAbsMgr::containerBoxOffsetX () +{ + return container->getParent () ? + container->boxOffsetX () - container->getStyle()->padding.left : 0; +} + +int OOFPosAbsMgr::containerBoxOffsetY () +{ + return container->getParent () ? + container->boxOffsetY () - container->getStyle()->padding.top : 0; +} + +int OOFPosAbsMgr::containerBoxRestWidth () +{ + return container->getParent () ? + container->boxRestWidth () - container->getStyle()->padding.right : 0; +} + +int OOFPosAbsMgr::containerBoxRestHeight () +{ + return container->getParent () ? + container->boxRestHeight () - container->getStyle()->padding.bottom : 0; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofposabsmgr.hh b/dw/oofposabsmgr.hh new file mode 100644 index 00000000..20c09535 --- /dev/null +++ b/dw/oofposabsmgr.hh @@ -0,0 +1,27 @@ +#ifndef __DW_OOFPOSABSMGR_HH__ +#define __DW_OOFPOSABSMGR_HH__ + +#include "oofpositionedmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPosAbsMgr: public OOFPositionedMgr +{ +protected: + int containerBoxOffsetX (); + int containerBoxOffsetY (); + int containerBoxRestWidth (); + int containerBoxRestHeight (); + +public: + OOFPosAbsMgr (OOFAwareWidget *container); + ~OOFPosAbsMgr (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSABSMGR_HH__ diff --git a/dw/oofposfixedmgr.cc b/dw/oofposfixedmgr.cc new file mode 100644 index 00000000..22cca983 --- /dev/null +++ b/dw/oofposfixedmgr.cc @@ -0,0 +1,60 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "oofposfixedmgr.hh" + +namespace dw { + +namespace oof { + +OOFPosFixedMgr::OOFPosFixedMgr (OOFAwareWidget *container) : + OOFPositionedMgr (container) +{ + DBG_OBJ_CREATE ("dw::OOFPosFixedMgr"); +} + +OOFPosFixedMgr::~OOFPosFixedMgr () +{ + DBG_OBJ_DELETE (); +} + + +int OOFPosFixedMgr::containerBoxOffsetX () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxOffsetY () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxRestWidth () +{ + return 0; +} + +int OOFPosFixedMgr::containerBoxRestHeight () +{ + return 0; +} + +} // namespace oof + +} // namespace dw diff --git a/dw/oofposfixedmgr.hh b/dw/oofposfixedmgr.hh new file mode 100644 index 00000000..38937878 --- /dev/null +++ b/dw/oofposfixedmgr.hh @@ -0,0 +1,27 @@ +#ifndef __DW_OOFPOSFIXEDMGR_HH__ +#define __DW_OOFPOSFIXEDMGR_HH__ + +#include "oofpositionedmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPosFixedMgr: public OOFPositionedMgr +{ +protected: + int containerBoxOffsetX (); + int containerBoxOffsetY (); + int containerBoxRestWidth (); + int containerBoxRestHeight (); + +public: + OOFPosFixedMgr (OOFAwareWidget *container); + ~OOFPosFixedMgr (); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSFIXEDMGR_HH__ diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc new file mode 100644 index 00000000..bcc7e12d --- /dev/null +++ b/dw/oofpositionedmgr.cc @@ -0,0 +1,605 @@ +/* + * 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, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *index) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d]", + area->x, area->y, area->width, area->height, *index); + + OOFAwareWidget::OOFStackingIterator *osi = + (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop (); + + while (*interruptedWidget == NULL && *index < children->size()) { + Child *child = children->get(*index); + + Rectangle childArea; + if (!osi->hasWidgetBeenDrawnAfterInterruption (child->widget) && + !StackingContextMgr::handledByStackingContextMgr (child->widget) && + child->widget->intersects (area, &childArea)) + child->widget->drawTotal (view, &childArea, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)++; + } + + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::addWidgetInFlow (OOFAwareWidget *widget, + OOFAwareWidget *parent, + int externalIndex) +{ +} + +int OOFPositionedMgr::addWidgetOOF (Widget *widget, OOFAwareWidget *generator, + int externalIndex) +{ + DBG_OBJ_ENTER ("construct.oofm", 0, "addWidgetOOF", "%p, %p, %d", + widget, generator, externalIndex); + + Child *child = new Child (widget, generator); + children->put (child); + childrenByWidget->put (new TypedPointer<Widget> (widget), child); + + int subRef = children->size() - 1; + DBG_OBJ_SET_NUM ("children.size", children->size()); + DBG_OBJ_ARRSET_PTR ("children", children->size() - 1, widget); + + DBG_OBJ_SET_PTR_O (widget, "<Positioned>.generator", generator); + + DBG_OBJ_MSGF ("construct.oofm", 1, "=> %d", subRef); + DBG_OBJ_LEAVE (); + return subRef; +} + +void OOFPositionedMgr::moveExternalIndices (OOFAwareWidget *generator, + int oldStartIndex, int diff) +{ +} + +void OOFPositionedMgr::markSizeChange (int ref) +{ +} + + +void OOFPositionedMgr::markExtremesChange (int ref) +{ +} + +Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y, + StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int *index) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + + Widget *widgetAtPoint = NULL; + OOFAwareWidget::OOFStackingIterator *osi = + (OOFAwareWidget::OOFStackingIterator*)iteratorStack->getTop (); + + while (widgetAtPoint == NULL && *interruptedWidget == NULL && *index >= 0) { + Widget *childWidget = children->get(*index)->widget; + if (!osi->hasWidgetBeenDrawnAfterInterruption (childWidget) && + !StackingContextMgr::handledByStackingContextMgr (childWidget)) + widgetAtPoint = + childWidget->getWidgetAtPointTotal (x, y, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)--; + } + + DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + +void OOFPositionedMgr::tellPosition (Widget *widget, int x, int y) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "tellPosition", "%p, %d, %d", + widget, x, y); + + TypedPointer<Widget> key (widget); + Child *child = childrenByWidget->get (&key); + assert (child); + + child->x = x; + child->y = y; + + DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.x", x); + DBG_OBJ_SET_NUM_O (child->widget, "<Positioned>.y", y); + + DBG_OBJ_LEAVE (); +} + +void OOFPositionedMgr::getSize (Requisition *containerReq, int *oofWidth, + int *oofHeight) +{ + DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); + + *oofWidth = *oofHeight = 0; + + int refWidth = container->getAvailWidth (true); + int refHeight = container->getAvailHeight (true); + + for (int i = 0; i < children->size(); i++) { + Child *child = children->get(i); + 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 (); +} + +bool OOFPositionedMgr::containerMustAdjustExtraSpace () +{ + return true; +} + +void OOFPositionedMgr::getExtremes (Extremes *containerExtr, int *oofMinWidth, + int *oofMaxWidth) +{ + DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", + containerExtr->minWidth, containerExtr->maxWidth); + + // 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..a1b1d68c --- /dev/null +++ b/dw/oofpositionedmgr.hh @@ -0,0 +1,127 @@ +#ifndef __DW_OOFPOSITIONEDMGR_HH__ +#define __DW_OOFPOSITIONEDMGR_HH__ + +#include "outofflowmgr.hh" + +namespace dw { + +namespace oof { + +class OOFPositionedMgr: public OutOfFlowMgr +{ +protected: + class Child: public lout::object::Object + { + public: + core::Widget *widget; + OOFAwareWidget *generator; + int x, y; + + inline Child (core::Widget *widget, OOFAwareWidget *generator) + { this->widget = widget; this->generator = generator; x = y = 0; } + }; + + virtual int containerBoxOffsetX () = 0; + virtual int containerBoxOffsetY () = 0; + virtual int containerBoxRestWidth () = 0; + virtual int containerBoxRestHeight () = 0; + + inline int containerBoxDiffWidth () + { return containerBoxOffsetX () + containerBoxRestWidth (); } + inline int containerBoxDiffHeight () + { return containerBoxOffsetY () + containerBoxRestHeight (); } + + OOFAwareWidget *container; + 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, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, int *index); + + void markSizeChange (int ref); + void markExtremesChange (int ref); + core::Widget *getWidgetAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, + int *index); + + void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent, + int externalIndex); + int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator, + int externalIndex); + void moveExternalIndices (OOFAwareWidget *generator, int oldStartIndex, + int diff); + + void tellPosition (core::Widget *widget, int x, int y); + + void getSize (core::Requisition *containerReq, int *oofWidth, + int *oofHeight); + bool containerMustAdjustExtraSpace (); + void getExtremes (core::Extremes *containerExtr, + int *oofMinWidth, int *oofMaxWidth); + + int getLeftBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + int getRightBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + bool hasFloatLeft (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + bool hasFloatRight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + int getRightFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex); + + int getClearPosition (OOFAwareWidget *widget); + + bool affectsLeftBorder (core::Widget *widget); + bool affectsRightBorder (core::Widget *widget); + bool mayAffectBordersAtAll (); + + bool dealingWithSizeOfChild (core::Widget *child); + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + + int getNumWidgets (); + core::Widget *getWidget (int i); +}; + +} // namespace oof + +} // namespace dw + +#endif // __DW_OOFPOSITIONEDMGR_HH__ diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc index eb56edbb..405c5e62 100644 --- a/dw/outofflowmgr.cc +++ b/dw/outofflowmgr.cc @@ -19,2266 +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"); +namespace oof { - update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), - getNewHeight ()); - - DBG_OBJ_LEAVE_O (getWidget ()); -} - -void OutOfFlowMgr::Float::intoStringBuffer(StringBuffer *sb) -{ - sb->append ("{ widget = "); - sb->appendPointer (getWidget ()); - - if (getWidget ()) { - sb->append (" ("); - sb->append (getWidget()->getClassName ()); - sb->append (")"); - } - - sb->append (", indexGBList = "); - sb->appendInt (indexGBList); - sb->append (", indexCBList = "); - sb->appendInt (indexCBList); - sb->append (", sideSpanningIndex = "); - sb->appendInt (sideSpanningIndex); - sb->append (", generatingBlock = "); - sb->appendPointer (generatingBlock); - sb->append (", yReq = "); - sb->appendInt (yReq); - sb->append (", yReal = "); - sb->appendInt (yReal); - sb->append (", size = { "); - sb->appendInt (size.width); - sb->append (" * "); - sb->appendInt (size.ascent); - sb->append (" + "); - sb->appendInt (size.descent); - sb->append (" }, dirty = "); - sb->appendBool (dirty); - sb->append (", sizeChangedSinceLastAllocation = "); - sb->appendBool (sizeChangedSinceLastAllocation); - sb->append (" }"); -} - -bool OutOfFlowMgr::Float::covers (Textblock *textblock, int y, int h) +OutOfFlowMgr::OutOfFlowMgr () { - DBG_OBJ_ENTER_O ("border", 0, getOutOfFlowMgr (), "covers", - "%p, %d, %d [vloat: %p]", - textblock, y, h, getWidget ()); - - bool b; - - if (textblock == generatingBlock) { - int reqyGB = y; - int flyGB = yReal; - getOutOfFlowMgr()->ensureFloatSize (this); - int flh = size.ascent + size.descent; - b = flyGB + flh > reqyGB && flyGB < reqyGB + h; - - DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (), - "for generator: reqyGB = %d, flyGB = %d, " - "flh = %d + %d = %d => %s", - reqyGB, flyGB, size.ascent, size.descent, flh, - b ? "true" : "false"); - } else { - // (If the textblock were not allocated, the GB list would have - // been choosen instead of the CB list, and so this else-branch - // would not have been not executed.) - assert (getOutOfFlowMgr()->wasAllocated (textblock)); - - if (!getWidget()->wasAllocated ()) { - DBG_OBJ_MSG_O ("border", 1, getOutOfFlowMgr (), - "not generator (not allocated) => false"); - b = false; - } else { - Allocation *tba = getOutOfFlowMgr()->getAllocation(textblock), - *fla = getWidget()->getAllocation (); - int reqyCanv = tba->y + y; - int flyCanv = fla->y; - int flh = fla->ascent + fla->descent; - b = flyCanv + flh > reqyCanv && flyCanv < reqyCanv + h; - - DBG_OBJ_MSGF_O ("border", 1, getOutOfFlowMgr (), - "not generator (allocated): reqyCanv = %d + %d = %d, " - "flyCanv = %d, flh = %d + %d = %d => %s", - tba->y, y, reqyCanv, flyCanv, - fla->ascent, fla->descent, flh, b ? "true" : "false"); - } - } - - 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); - - DBG_OBJ_MSGF_O ("border", 2, oofm, "generators are %p and %p", - fl1->generatingBlock, fl2->generatingBlock); - - // (i) Floats may not yet been allocated. Non-allocated floats - // do not have an effect yet, they are considered "at the end" - // of the list. - - // (ii) Float::widget is NULL for the key used for binary - // search. In this case, Float::yReal is used instead (which is - // set in SortedFloatsVector::find, too). The generator is the - // textblock, and should be allocated. (If not, the GB list - // would have been choosen instead of the CB list, and so this - // else-branch would not have been not executed.) - - bool a1 = fl1->getWidget () ? fl1->getWidget()->wasAllocated () : true; - bool a2 = fl2->getWidget () ? fl2->getWidget()->wasAllocated () : true; - - DBG_OBJ_MSGF_O ("border", 2, oofm, - "float 1 (%p) allocated: %s; float 2 (%p) allocated: %s", - fl1->getWidget (), a1 ? "yes" : "no", fl2->getWidget (), - a2 ? "yes" : "no"); - - if (a1 && a2) { - int fly1, fly2; - - if (fl1->getWidget()) { - fly1 = fl1->getWidget()->getAllocation()->y; - DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d", fly1); - } else { - assert (oofm->wasAllocated (fl1->generatingBlock)); - fly1 = oofm->getAllocation(fl1->generatingBlock)->y + fl1->yReal; - DBG_OBJ_MSGF_O ("border", 2, oofm, "fly1 = %d + %d = %d", - oofm->getAllocation(fl1->generatingBlock)->y, - fl1->yReal, fly1); - } - - if (fl2->getWidget()) { - fly2 = fl2->getWidget()->getAllocation()->y; - DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d", fly2); - } else { - assert (oofm->wasAllocated (fl2->generatingBlock)); - fly2 = oofm->getAllocation(fl2->generatingBlock)->y + fl2->yReal; - DBG_OBJ_MSGF_O ("border", 2, oofm, "fly2 = %d + %d = %d", - oofm->getAllocation(fl2->generatingBlock)->y, - fl2->yReal, fly2); - } - - r = fly1 - fly2; - - DBG_OBJ_MSGF_O ("border", 2, oofm, "r = %d - %d = %d", fly1, fly2, r); - } else if (a1 && !a2) - r = -1; - else if (!a1 && a2) - r = +1; - else // if (!a1 && !a2) - return 0; - - DBG_OBJ_MSG_END_O (oofm); - } - - DBG_OBJ_MSGF_O ("border", 1, oofm, "result: %d", r); - DBG_OBJ_LEAVE_O (oofm); - return r; -} - -int OutOfFlowMgr::Float::CompareSideSpanningIndex::compare (Object *o1, - Object *o2) -{ - return ((Float*)o1)->sideSpanningIndex - ((Float*)o2)->sideSpanningIndex; -} - -int OutOfFlowMgr::Float::CompareGBAndExtIndex::compare (Object *o1, Object *o2) -{ - Float *f1 = (Float*)o1, *f2 = (Float*)o2; - int r = -123; // Compiler happiness: GCC 4.7 does not handle this?; - - DBG_OBJ_ENTER_O ("border", 1, oofm, "CompareGBAndExtIndex/compare", - "#%d -> %p/%d, #%d -> %p/#%d", - f1->getIndex (type), f1->generatingBlock, f1->externalIndex, - f2->getIndex (type), f2->generatingBlock, - f2->externalIndex); - - if (f1->generatingBlock == f2->generatingBlock) { - r = f1->externalIndex - f2->externalIndex; - DBG_OBJ_MSGF_O ("border", 2, oofm, - "(a) generating blocks equal => %d - %d = %d", - f1->externalIndex, f2->externalIndex, r); - } else { - TBInfo *t1 = oofm->getTextblock (f1->generatingBlock), - *t2 = oofm->getTextblock (f2->generatingBlock); - bool rdef = false; - - for (TBInfo *t = t1; t != NULL; t = t->parent) - if (t->parent == t2) { - rdef = true; - r = t->parentExtIndex - f2->externalIndex; - DBG_OBJ_MSGF_O ("border", 2, oofm, - "(b) %p is an achestor of %p; direct child is " - "%p (%d) => %d - %d = %d\n", - t2->getTextblock (), t1->getTextblock (), - t->getTextblock (), t->parentExtIndex, - t->parentExtIndex, f2->externalIndex, r); - } - - for (TBInfo *t = t2; !rdef && t != NULL; t = t->parent) - if (t->parent == t1) { - r = f1->externalIndex - t->parentExtIndex; - rdef = true; - DBG_OBJ_MSGF_O ("border", 2, oofm, - "(c) %p is an achestor of %p; direct child is %p " - "(%d) => %d - %d = %d\n", - t1->getTextblock (), t2->getTextblock (), - t->getTextblock (), t->parentExtIndex, - f1->externalIndex, t->parentExtIndex, r); - } - - if (!rdef) { - r = t1->index - t2->index; - DBG_OBJ_MSGF_O ("border", 2, oofm, "(d) other => %d - %d = %d", - t1->index, t2->index, r); - } - } - - DBG_OBJ_MSGF_O ("border", 2, oofm, "result: %d", r); - DBG_OBJ_LEAVE_O (oofm); - return r; -} - -int OutOfFlowMgr::SortedFloatsVector::findFloatIndex (Textblock *lastGB, - int lastExtIndex) -{ - DBG_OBJ_ENTER_O ("border", 0, oofm, "findFloatIndex", "%p, %d", - lastGB, lastExtIndex); - - Float key (oofm, NULL, lastGB, lastExtIndex); - key.setIndex (type, -1); // for debugging - Float::CompareGBAndExtIndex comparator (oofm, type); - int i = bsearch (&key, false, &comparator); - - // At position i is the next larger element, so element i should - // not included, but i - 1 returned; except if the exact element is - // found: then include it and so return i. - int r; - if (i == size()) - r = i - 1; - else { - Float *f = get (i); - if (comparator.compare (f, &key) == 0) - r = i; - else - r = i - 1; - } - - //printf ("[%p] findFloatIndex (%p, %d) => i = %d, r = %d (size = %d); " - // "in %s list %p on the %s side\n", - // oofm->containingBlock, lastGB, lastExtIndex, i, r, size (), - // type == GB ? "GB" : "CB", this, side == LEFT ? "left" : "right"); - - //for (int i = 0; i < size (); i++) { - // Float *f = get(i); - // TBInfo *t = oofm->getTextblock(f->generatingBlock); - // printf (" %d: (%p [%d, %p], %d)\n", i, f->generatingBlock, - // t->index, t->parent ? t->parent->textblock : NULL, - // get(i)->externalIndex); - //} - - DBG_OBJ_MSGF_O ("border", 1, oofm, "=> r = %d", r); - DBG_OBJ_LEAVE_O (oofm); - return r; -} - -int OutOfFlowMgr::SortedFloatsVector::find (Textblock *textblock, int y, - int start, int end) -{ - DBG_OBJ_ENTER_O ("border", 0, oofm, "find", "%p, %d, %d, %d", - textblock, y, start, end); - - Float key (oofm, NULL, NULL, 0); - key.generatingBlock = textblock; - key.yReal = y; - key.setIndex (type, -1); // for debugging - Float::ComparePosition comparator (oofm, textblock, type); - int result = bsearch (&key, false, start, end, &comparator); - - DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); - DBG_OBJ_LEAVE_O (oofm); - return result; -} - -int OutOfFlowMgr::SortedFloatsVector::findFirst (Textblock *textblock, - int y, int h, - Textblock *lastGB, - int lastExtIndex, - int *lastReturn) -{ - DBG_OBJ_ENTER_O ("border", 0, oofm, "findFirst", "%p, %d, %d, %p, %d", - textblock, y, h, lastGB, lastExtIndex); - - DBG_IF_RTFL { - DBG_OBJ_MSG_O ("border", 2, oofm, "searching in list:"); - DBG_OBJ_MSG_START_O (oofm); - - for (int i = 0; i < size(); i++) { - DBG_OBJ_MSGF_O ("border", 2, oofm, - "%d: (%p, i = %d/%d, y = %d/%d, s = (%d * (%d + %d)), " - "%s, %s, ext = %d, GB = %p); widget at (%d, %d)", - i, get(i)->getWidget (), get(i)->getIndex (type), - get(i)->sideSpanningIndex, get(i)->yReq, get(i)->yReal, - get(i)->size.width, get(i)->size.ascent, - get(i)->size.descent, - get(i)->dirty ? "dirty" : "clean", - get(i)->sizeChangedSinceLastAllocation ? "scsla" - : "sNcsla", - get(i)->externalIndex, get(i)->generatingBlock, - get(i)->getWidget()->getAllocation()->x, - get(i)->getWidget()->getAllocation()->y); - } - - DBG_OBJ_MSG_END_O (oofm); - } - - int last = findFloatIndex (lastGB, lastExtIndex); - DBG_OBJ_MSGF_O ("border", 1, oofm, "last = %d", last); - assert (last < size()); - - // If the caller wants to reuse this value: - if (lastReturn) - *lastReturn = last; - - int i = find (textblock, y, 0, last), result; - DBG_OBJ_MSGF_O ("border", 1, oofm, "i = %d", i); - - // Note: The smallest value of "i" is 0, which means that "y" is before or - // equal to the first float. The largest value is "last + 1", which means - // that "y" is after the last float. In both cases, the first or last, - // respectively, float is a candidate. Generally, both floats, before and - // at the search position, are candidates. - - if (i > 0 && get(i - 1)->covers (textblock, y, h)) - result = i - 1; - else if (i <= last && get(i)->covers (textblock, y, h)) - result = i; - else - result = -1; - - DBG_OBJ_MSGF_O ("border", 1, oofm, "=> result = %d", result); - DBG_OBJ_LEAVE_O (oofm); - return result; -} - -int OutOfFlowMgr::SortedFloatsVector::findLastBeforeSideSpanningIndex - (int sideSpanningIndex) -{ - OutOfFlowMgr::Float::CompareSideSpanningIndex comparator; - Float key (NULL, NULL, NULL, 0); - key.sideSpanningIndex = sideSpanningIndex; - return bsearch (&key, false, &comparator) - 1; -} - -void OutOfFlowMgr::SortedFloatsVector::put (Float *vloat) -{ - lout::container::typed::Vector<Float>::put (vloat); - vloat->setIndex (type, size() - 1); -} - -OutOfFlowMgr::TBInfo::TBInfo (OutOfFlowMgr *oofm, Textblock *textblock, - TBInfo *parent, int parentExtIndex) : - WidgetInfo (oofm, textblock) -{ - this->parent = parent; - this->parentExtIndex = parentExtIndex; - - leftFloatsGB = new SortedFloatsVector (oofm, LEFT, GB); - rightFloatsGB = new SortedFloatsVector (oofm, RIGHT, GB); - - wasAllocated = getWidget()->wasAllocated (); - allocation = *(getWidget()->getAllocation ()); - clearPosition = 0; -} - -OutOfFlowMgr::TBInfo::~TBInfo () -{ - delete leftFloatsGB; - delete rightFloatsGB; -} - -void OutOfFlowMgr::TBInfo::updateAllocation () -{ - DBG_OBJ_ENTER0_O ("resize.oofm", 0, getWidget (), "updateAllocation"); - - update (isNowAllocated (), getNewXCB (), getNewYCB (), getNewWidth (), - getNewHeight ()); - - DBG_OBJ_LEAVE_O (getWidget ()); -} - -OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock) -{ - DBG_OBJ_CREATE ("dw::OutOfFlowMgr"); - - this->containingBlock = containingBlock; - - leftFloatsCB = new SortedFloatsVector (this, LEFT, CB); - rightFloatsCB = new SortedFloatsVector (this, RIGHT, CB); - - DBG_OBJ_SET_NUM ("leftFloatsCB.size", leftFloatsCB->size()); - DBG_OBJ_SET_NUM ("rightFloatsCB.size", rightFloatsCB->size()); - - leftFloatsAll = new Vector<Float> (1, true); - rightFloatsAll = new Vector<Float> (1, true); - - DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size()); - DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size()); - - floatsByWidget = new HashTable <TypedPointer <Widget>, Float> (true, false); - - tbInfos = new Vector<TBInfo> (1, false); - tbInfosByTextblock = - new HashTable <TypedPointer <Textblock>, TBInfo> (true, true); - - leftFloatsMark = rightFloatsMark = 0; - lastLeftTBIndex = lastRightTBIndex = 0; - - containingBlockWasAllocated = containingBlock->wasAllocated (); - containingBlockAllocation = *(containingBlock->getAllocation()); - - addWidgetInFlow (containingBlock, NULL, 0); } OutOfFlowMgr::~OutOfFlowMgr () { - //printf ("OutOfFlowMgr::~OutOfFlowMgr\n"); - - delete leftFloatsCB; - delete rightFloatsCB; - - // Order is important: tbInfosByTextblock is owner of the instances - // of TBInfo.tbInfosByTextblock - delete tbInfos; - delete tbInfosByTextblock; - - delete floatsByWidget; - - // Order is important, since the instances of Float are owned by - // leftFloatsAll and rightFloatsAll, so these should be deleted - // last. - delete leftFloatsAll; - delete rightFloatsAll; - - DBG_OBJ_DELETE (); -} - -void OutOfFlowMgr::sizeAllocateStart (Textblock *caller, Allocation *allocation) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateStart", - "%p, (%d, %d, %d * (%d + %d))", - caller, allocation->x, allocation->y, allocation->width, - allocation->ascent, allocation->descent); - - getTextblock(caller)->allocation = *allocation; - getTextblock(caller)->wasAllocated = true; - - if (caller == containingBlock) { - // In the size allocation process, the *first* OOFM method - // called is sizeAllocateStart, with the containing block as an - // argument. So this is the correct point to initialize size - // allocation. - - containingBlockAllocation = *allocation; - containingBlockWasAllocated = true; - - // Move floats from GB lists to the one CB list. - moveFromGBToCB (LEFT); - moveFromGBToCB (RIGHT); - - // These attributes are used to keep track which floats have - // been allocated (referring to leftFloatsCB and rightFloatsCB). - lastAllocatedLeftFloat = lastAllocatedRightFloat = -1; - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "sizeAllocateEnd", "%p", caller); - - // (Later, absolutely positioned blocks have to be allocated.) - - if (caller != containingBlock) { - // Allocate all floats "before" this textblock. - sizeAllocateFloats (LEFT, leftFloatsCB->findFloatIndex (caller, -1)); - sizeAllocateFloats (RIGHT, rightFloatsCB->findFloatIndex (caller, -1)); - } - - // The checks below do not cover "clear position" in all cases, so - // this is done here separately. This position is stored in TBInfo - // and calculated at this points; changes will be noticed to the - // textblock. - TBInfo *tbInfo = getTextblock (caller); - int newClearPosition = calcClearPosition (caller); - if (newClearPosition != tbInfo->clearPosition) { - tbInfo->clearPosition = newClearPosition; - caller->clearPositionChanged (); - } - - if (caller == containingBlock) { - // In the size allocation process, the *last* OOFM method called - // is sizeAllocateEnd, with the containing block as an - // argument. So this is the correct point to finish size - // allocation. - - // Allocate all remaining floats. - sizeAllocateFloats (LEFT, leftFloatsCB->size () - 1); - sizeAllocateFloats (RIGHT, rightFloatsCB->size () - 1); - - // Check changes of both textblocks and floats allocation. (All - // is checked by hasRelationChanged (...).) - for (lout::container::typed::Iterator<TypedPointer <Textblock> > it = - tbInfosByTextblock->iterator (); - it.hasNext (); ) { - TypedPointer <Textblock> *key = it.getNext (); - TBInfo *tbInfo = tbInfosByTextblock->get (key); - Textblock *tb = key->getTypedValue(); - - int minFloatPos; - Widget *minFloat; - if (hasRelationChanged (tbInfo, &minFloatPos, &minFloat)) - tb->borderChanged (minFloatPos, minFloat); - } - - checkAllocatedFloatCollisions (LEFT); - checkAllocatedFloatCollisions (RIGHT); - - // Store some information for later use. - for (lout::container::typed::Iterator<TypedPointer <Textblock> > it = - tbInfosByTextblock->iterator (); - it.hasNext (); ) { - TypedPointer <Textblock> *key = it.getNext (); - TBInfo *tbInfo = tbInfosByTextblock->get (key); - Textblock *tb = key->getTypedValue(); - - tbInfo->updateAllocation (); - tbInfo->lineBreakWidth = tb->getLineBreakWidth (); - } - - // There are cases where some allocated floats (TODO: later also - // absolutely positioned elements?) exceed the CB allocation. - bool sizeChanged = doFloatsExceedCB (LEFT) || doFloatsExceedCB (RIGHT); - - // Similar for extremes. (TODO: here also absolutely positioned - // elements?) - bool extremesChanged = - haveExtremesChanged (LEFT) || haveExtremesChanged (RIGHT); - - for (int i = 0; i < leftFloatsCB->size(); i++) - leftFloatsCB->get(i)->updateAllocation (); - - for (int i = 0; i < rightFloatsCB->size(); i++) - rightFloatsCB->get(i)->updateAllocation (); - - if (sizeChanged || extremesChanged) - containingBlock->oofSizeChanged (extremesChanged); - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::containerSizeChangedForChildren () -{ - DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren"); - - DBG_OBJ_MSGF ("resize", 0, - "%d left floats, %d right floats %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 (); - - 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); -} - -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); - } -} - -/** - * 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) -{ - return isWidgetFloat (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 - // May be extended. - assertNotReached(); - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::moveExternalIndices (Textblock *generatingBlock, - int oldStartIndex, int diff) -{ - TBInfo *tbInfo = getTextblock (generatingBlock); - moveExternalIndices (tbInfo->leftFloatsGB, oldStartIndex, diff); - moveExternalIndices (tbInfo->rightFloatsGB, oldStartIndex, diff); -} - -void OutOfFlowMgr::moveExternalIndices (SortedFloatsVector *list, - int oldStartIndex, int diff) -{ - // Could be faster with binary search, but the GB (not CB!) lists - // should be rather small. - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - if (vloat->externalIndex >= oldStartIndex) { - vloat->externalIndex += diff; - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.externalIndex", - vloat->externalIndex); - } - } -} - -OutOfFlowMgr::Float *OutOfFlowMgr::findFloatByWidget (Widget *widget) -{ - TypedPointer <Widget> key (widget); - Float *vloat = floatsByWidget->get (&key); - assert (vloat != NULL); - return vloat; -} - -void OutOfFlowMgr::markSizeChange (int ref) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "markSizeChange", "%d", ref); - - if (isRefFloat (ref)) { - Float *vloat; - - if (isRefLeftFloat (ref)) { - int i = getFloatIndexFromRef (ref); - vloat = leftFloatsAll->get (i); - //printf (" => left float %d\n", i); - } else if (isRefRightFloat (ref)) { - int i = getFloatIndexFromRef (ref); - vloat = rightFloatsAll->get (i); - //printf (" => right float %d\n", i); - } else { - assertNotReached(); - vloat = NULL; // compiler happiness - } - - vloat->dirty = vloat->sizeChangedSinceLastAllocation = true; - - DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); - DBG_OBJ_SET_BOOL_O (vloat->getWidget (), - "<Float>.sizeChangedSinceLastAllocation", - vloat->sizeChangedSinceLastAllocation); - - // The generating block is told directly about this. (Others later, in - // sizeAllocateEnd.) Could be faster (cf. hasRelationChanged, which - // differentiates many special cases), but the size is not known yet, - vloat->generatingBlock->borderChanged (vloat->yReal, vloat->getWidget ()); - } else - assertNotReached(); - - DBG_OBJ_LEAVE (); -} - - -void OutOfFlowMgr::markExtremesChange (int ref) -{ - // Nothing to do here. -} - -Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level) -{ - Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level); - if (childAtPoint == NULL) - childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level); - return childAtPoint; -} - -Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, - int x, int y, int level) -{ - for (int i = 0; i < list->size(); i++) { - // Could use binary search to be faster. - Float *vloat = list->get(i); - if (vloat->getWidget()->wasAllocated ()) { - Widget *childAtPoint = - vloat->getWidget()->getWidgetAtPoint (x, y, level + 1); - if (childAtPoint) - return childAtPoint; - } - } - - return NULL; -} - -void OutOfFlowMgr::tellPosition (Widget *widget, int yReq) -{ - if (isWidgetFloat (widget)) - tellFloatPosition (widget, yReq); - - // Nothing to do for absolutely positioned blocks. -} - - -void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "tellFloatPosition", "%p, %d", - widget, yReq); - - assert (yReq >= 0); - - Float *vloat = findFloatByWidget(widget); - - SortedFloatsVector *listSame, *listOpp; - Side side; - getFloatsListsAndSide (vloat, &listSame, &listOpp, &side); - ensureFloatSize (vloat); - - // "yReal" may change due to collisions (see below). - vloat->yReq = vloat->yReal = yReq; - - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReq", vloat->yReq); - DBG_OBJ_SET_NUM_O (vloat->getWidget (), "<Float>.yReal", vloat->yReal); - - // Test collisions (on this side). Although there are (rare) cases - // where it could make sense, the horizontal dimensions are not - // tested; especially since searching and border calculation would - // be confused. For this reaspn, only the previous float is - // relevant. (Cf. below, collisions on the other side.) - int index = vloat->getIndex (listSame->type), yRealNew; - if (index >= 1 && - collidesV (vloat, listSame->get (index - 1), listSame->type, - &yRealNew)) { - 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 { - // If the other float is not allocated, there is no collision. The - // allocation of this float (vloat) is not used at all. - if (!other->getWidget()->wasAllocated ()) - result = false; - else { - assert (wasAllocated (vloat->generatingBlock)); - Allocation *gba = getAllocation (vloat->generatingBlock), - *flaOther = other->getWidget()->getAllocation (); - 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 { - // Again, if the other float is not allocated, there is no - // collision. Compare to collidesV. (But vloat->size is used - // here.) - if (!other->getWidget()->wasAllocated ()) - collidesH = false; - else { - assert (wasAllocated (vloat->generatingBlock)); - Allocation *gba = getAllocation (vloat->generatingBlock); - int vloatX = - calcFloatX (vloat, - vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ? - LEFT : RIGHT, - gba->x, gba->width, - vloat->generatingBlock->getLineBreakWidth ()); - - // Generally: right border of the left float > left border of - // the right float (all in canvas coordinates). - if (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT) - // "vloat" is left, "other" is right - collidesH = vloatX + vloat->size.width - > other->getWidget()->getAllocation()->x; - else - // "other" is left, "vloat" is right - collidesH = other->getWidget()->getAllocation()->x - + other->getWidget()->getAllocation()->width - > vloatX; - } - } - - return collidesH; -} - -void OutOfFlowMgr::getFloatsListsAndSide (Float *vloat, - SortedFloatsVector **listSame, - SortedFloatsVector **listOpp, - Side *side) -{ - TBInfo *tbInfo = getTextblock (vloat->generatingBlock); - - switch (vloat->getWidget()->getStyle()->vloat) { - case FLOAT_LEFT: - if (wasAllocated (vloat->generatingBlock)) { - if (listSame) *listSame = leftFloatsCB; - if (listOpp) *listOpp = rightFloatsCB; - } else { - if (listSame) *listSame = tbInfo->leftFloatsGB; - if (listOpp) *listOpp = tbInfo->rightFloatsGB; - } - if (side) *side = LEFT; - break; - - case FLOAT_RIGHT: - if (wasAllocated (vloat->generatingBlock)) { - if (listSame) *listSame = rightFloatsCB; - if (listOpp) *listOpp = leftFloatsCB; - } else { - if (listSame) *listSame = tbInfo->rightFloatsGB; - if (listOpp) *listOpp = tbInfo->leftFloatsGB; - } - if (side) *side = RIGHT; - break; - - default: - assertNotReached(); - } -} - -void OutOfFlowMgr::getSize (Requisition *cbReq, int *oofWidth, int *oofHeight) -{ - DBG_OBJ_ENTER0 ("resize.oofm", 0, "getSize"); - - int oofWidthtLeft, oofWidthRight, oofHeightLeft, oofHeightRight; - getFloatsSize (cbReq, LEFT, &oofWidthtLeft, &oofHeightLeft); - getFloatsSize (cbReq, RIGHT, &oofWidthRight, &oofHeightRight); - - *oofWidth = max (oofWidthtLeft, oofWidthRight); - *oofHeight = max (oofHeightLeft, oofHeightRight); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> (l: %d, r: %d => %d) * (l: %d, r: %d => %d)", - oofWidthtLeft, oofWidthRight, *oofWidth, - oofHeightLeft, oofHeightRight, *oofHeight); - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width, - int *height) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsSize", "(%d * (%d + %d), %s, ...", - cbReq->width, cbReq->ascent, cbReq->descent, - side == LEFT ? "LEFT" : "RIGHT"); - - SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side); - - *width = *height = 0; - - DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats on this side", list->size()); - - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - - if (vloat->generatingBlock == containingBlock || - wasAllocated (vloat->generatingBlock)) { - ensureFloatSize (vloat); - int x, y; - - if (vloat->generatingBlock == containingBlock) { - x = calcFloatX (vloat, side, 0, cbReq->width, - vloat->generatingBlock->getLineBreakWidth ()); - y = vloat->yReal; - } else { - Allocation *gba = getAllocation(vloat->generatingBlock); - x = calcFloatX (vloat, side, - gba->x - containingBlockAllocation.x, gba->width, - vloat->generatingBlock->getLineBreakWidth ()); - y = gba->y - containingBlockAllocation.y + vloat->yReal; - } - - *width = max (*width, x + vloat->size.width); - *height = max (*height, y + vloat->size.ascent + vloat->size.descent); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: (%d + %d) * " - "(%d + (%d + %d)) => %d * %d", - vloat->getWidget (), vloat->generatingBlock, - x, vloat->size.width, - y, vloat->size.ascent, vloat->size.descent, - *width, *height); - } else - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: not allocated", - vloat->getWidget (), vloat->generatingBlock); - } - - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getExtremes (Extremes *cbExtr, int *oofMinWidth, - int *oofMaxWidth) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getExtremes", "(%d / %d), ...", - cbExtr->minWidth, cbExtr->maxWidth); - - int oofMinWidthtLeft, oofMinWidthRight, oofMaxWidthLeft, oofMaxWidthRight; - getFloatsExtremes (cbExtr, LEFT, &oofMinWidthtLeft, &oofMaxWidthLeft); - getFloatsExtremes (cbExtr, RIGHT, &oofMinWidthRight, &oofMaxWidthRight); - - *oofMinWidth = max (oofMinWidthtLeft, oofMinWidthRight); - *oofMaxWidth = max (oofMaxWidthLeft, oofMaxWidthRight); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "=> (l: %d, r: %d => %d) / (l: %d, r: %d => %d)", - oofMinWidthtLeft, oofMinWidthRight, *oofMinWidth, - oofMaxWidthLeft, oofMaxWidthRight, *oofMaxWidth); - DBG_OBJ_LEAVE (); -} - -void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side, - int *minWidth, int *maxWidth) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getFloatsExtremes", "(%d / %d), %s, ...", - cbExtr->minWidth, cbExtr->maxWidth, - side == LEFT ? "LEFT" : "RIGHT"); - - *minWidth = *maxWidth = 0; - - SortedFloatsVector *list = getFloatsListForTextblock (containingBlock, side); - DBG_OBJ_MSGF ("resize.oofm", 1, "%d floats to be examined", list->size()); - - for (int i = 0; i < list->size(); i++) { - Float *vloat = list->get(i); - int leftDiff, rightDiff; - - if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff)) { - Extremes extr; - vloat->getWidget()->getExtremes (&extr); - - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: %d / %d", - vloat->getWidget (), vloat->generatingBlock, - extr.minWidth, extr.maxWidth); - - // TODO: Or zero (instead of rightDiff) for right floats? - *minWidth = - max (*minWidth, - extr.minWidth + (side == LEFT ? leftDiff : rightDiff)); - *maxWidth = max (*maxWidth, extr.maxWidth + leftDiff + rightDiff); - - DBG_OBJ_MSGF ("resize.oofm", 1, " => %d / %d", *minWidth, *maxWidth); - } else - DBG_OBJ_MSGF ("resize.oofm", 1, - "considering float %p generated by %p: not allocated", - vloat->getWidget (), vloat->generatingBlock); - } - - DBG_OBJ_LEAVE (); -} - -// Returns "false" when borders cannot yet determined; *leftDiff and -// *rightDiff are undefined in this case. -bool OutOfFlowMgr::getFloatDiffToCB (Float *vloat, int *leftDiff, - int *rightDiff) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getDiffToCB", - "float %p [generated by %p], ...", - vloat->getWidget (), vloat->generatingBlock); - - bool result; - - if (vloat->generatingBlock == containingBlock) { - *leftDiff = vloat->generatingBlock->getStyle()->boxOffsetX(); - *rightDiff = vloat->generatingBlock->getStyle()->boxRestWidth(); - result = true; - DBG_OBJ_MSGF ("resize.oofm", 1, - "GB == CB => leftDiff = %d, rightDiff = %d", - *leftDiff, *rightDiff); - } else if (wasAllocated (vloat->generatingBlock)) { - Allocation *gba = getAllocation(vloat->generatingBlock); - *leftDiff = gba->x - containingBlockAllocation.x - + vloat->generatingBlock->getStyle()->boxOffsetX(); - *rightDiff = - (containingBlockAllocation.x + containingBlockAllocation.width) - - (gba->x + gba->width) - + vloat->generatingBlock->getStyle()->boxRestWidth(); - result = true; - DBG_OBJ_MSGF ("resize.oofm", 1, - "GB != CB => leftDiff = %d - %d + %d = %d, " - "rightDiff = (%d + %d) - (%d + %d) + %d = %d", - gba->x, containingBlockAllocation.x, - vloat->generatingBlock->getStyle()->boxOffsetX(), - *leftDiff, containingBlockAllocation.x, - containingBlockAllocation.width, gba->x, gba->width, - vloat->generatingBlock->getStyle()->boxRestWidth(), - *rightDiff); - } else { - DBG_OBJ_MSG ("resize.oofm", 1, "GB != CB, and float not allocated"); - result = false; - } - - DBG_OBJ_LEAVE (); - return result; -} - -OutOfFlowMgr::TBInfo *OutOfFlowMgr::getTextblock (Textblock *textblock) -{ - TypedPointer<Textblock> key (textblock); - TBInfo *tbInfo = tbInfosByTextblock->get (&key); - assert (tbInfo); - return tbInfo; -} - -/** - * Get the left border for the vertical position of *y*, for a height - * of *h", based on floats; relative to the allocation of the calling - * textblock. - * - * The border includes marging/border/padding of the calling textblock - * but is 0 if there is no float, so a caller should also consider - * other borders. - */ -int OutOfFlowMgr::getLeftBorder (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - int b = getBorder (textblock, LEFT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "left border (%p, %d, %d, %p, %d) => %d", - textblock, y, h, lastGB, lastExtIndex, b); - return b; -} - -/** - * Get the right border for the vertical position of *y*, for a height - * of *h*, based on floats. - * - * See also getLeftBorder(int, int); - */ -int OutOfFlowMgr::getRightBorder (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - int b = getBorder (textblock, RIGHT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "right border (%p, %d, %d, %p, %d) => %d", - textblock, y, h, lastGB, lastExtIndex, b); - return b; -} - -int OutOfFlowMgr::getBorder (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "getBorder", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int last; - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, &last); - - DBG_OBJ_MSGF ("border", 1, "first = %d", first); - - if (first == -1) { - // No float. - DBG_OBJ_LEAVE (); - return 0; - } else { - // It is not sufficient to find the first float, since a line - // (with height h) may cover the region of multiple float, of - // which the widest has to be choosen. - int border = 0; - bool covers = true; - - // We are not searching until the end of the list, but until the - // float defined by lastGB and lastExtIndex. - for (int i = first; covers && i <= last; i++) { - Float *vloat = list->get(i); - covers = vloat->covers (textblock, y, h); - DBG_OBJ_MSGF ("border", 1, "float %d (%p) covers? %s.", - i, vloat->getWidget(), covers ? "<b>yes</b>" : "no"); - - if (covers) { - int thisBorder; - if (vloat->generatingBlock == textblock) { - int borderIn = side == LEFT ? - vloat->generatingBlock->getStyle()->boxOffsetX() : - vloat->generatingBlock->getStyle()->boxRestWidth(); - thisBorder = vloat->size.width + borderIn; - DBG_OBJ_MSGF ("border", 1, "GB: thisBorder = %d + %d = %d", - vloat->size.width, borderIn, thisBorder); - } else { - assert (wasAllocated (vloat->generatingBlock)); - assert (vloat->getWidget()->wasAllocated ()); - - Allocation *tba = getAllocation(textblock), - *fla = vloat->getWidget()->getAllocation (); - if (side == LEFT) { - thisBorder = fla->x + fla->width - tba->x; - DBG_OBJ_MSGF ("border", 1, - "not GB: thisBorder = %d + %d - %d = %d", - fla->x, fla->width, tba->x, thisBorder); - } else { - // See also calcFloatX. - thisBorder = - tba->x + textblock->getLineBreakWidth () - fla->x; - DBG_OBJ_MSGF ("border", 1, - "not GB: thisBorder = %d + %d - %d " - "= %d", - tba->x, textblock->getLineBreakWidth (), fla->x, - thisBorder); - } - } - - border = max (border, thisBorder); - DBG_OBJ_MSGF ("border", 1, "=> border = %d", border); - } - } - - DBG_OBJ_LEAVE (); - return border; - } -} - - -OutOfFlowMgr::SortedFloatsVector *OutOfFlowMgr::getFloatsListForTextblock - (Textblock *textblock, Side side) -{ - DBG_OBJ_ENTER ("oofm.common", 1, "getFloatsListForTextblock", "%p, %s", - textblock, side == LEFT ? "LEFT" : "RIGHT"); - - OutOfFlowMgr::SortedFloatsVector *list; - - if (wasAllocated (textblock)) { - DBG_OBJ_MSG ("oofm.common", 2, "returning <b>CB</b> list"); - list = side == LEFT ? leftFloatsCB : rightFloatsCB; - } else { - DBG_OBJ_MSG ("oofm.common", 2, "returning <b>GB</b> list"); - TBInfo *tbInfo = getTextblock (textblock); - list = side == LEFT ? tbInfo->leftFloatsGB : tbInfo->rightFloatsGB; - } - - DBG_OBJ_LEAVE (); - return list; -} - - -bool OutOfFlowMgr::hasFloatLeft (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - bool b = hasFloat (textblock, LEFT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "has float left (%p, %d, %d, %p, %d) => %s", - textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); - return b; -} - -bool OutOfFlowMgr::hasFloatRight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - bool b = hasFloat (textblock, RIGHT, y, h, lastGB, lastExtIndex); - DBG_OBJ_MSGF ("border", 0, "has float right (%p, %d, %d, %p, %d) => %s", - textblock, y, h, lastGB, lastExtIndex, b ? "true" : "false"); - return b; -} - -bool OutOfFlowMgr::hasFloat (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "hasFloat", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); - - DBG_OBJ_MSGF ("border", 1, "first = %d", first); - DBG_OBJ_LEAVE (); - return first != -1; -} - -int OutOfFlowMgr::getLeftFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - return getFloatHeight (textblock, LEFT, y, h, lastGB, lastExtIndex); -} - -int OutOfFlowMgr::getRightFloatHeight (Textblock *textblock, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - return getFloatHeight (textblock, RIGHT, y, h, lastGB, lastExtIndex); -} - -// Calculate height from the position *y*. -int OutOfFlowMgr::getFloatHeight (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex) -{ - DBG_OBJ_ENTER ("border", 0, "getFloatHeight", "%p, %s, %d, %d, %p, %d", - textblock, side == LEFT ? "LEFT" : "RIGHT", y, h, - lastGB, lastExtIndex); - - SortedFloatsVector *list = getFloatsListForTextblock (textblock, side); - int first = list->findFirst (textblock, y, h, lastGB, lastExtIndex, NULL); - assert (first != -1); /* This method must not be called when there is no - float on the respective side. */ - - Float *vloat = list->get(first); - int yRelToFloat; - - if (vloat->generatingBlock == textblock) { - yRelToFloat = y - vloat->yReal; - DBG_OBJ_MSGF ("border", 1, "caller is CB: yRelToFloat = %d - %d = %d", - y, vloat->yReal, yRelToFloat); - } else { - // The respective widgets are allocated; otherwise, hasFloat() would have - // returned false. - assert (wasAllocated (textblock)); - assert (vloat->getWidget()->wasAllocated ()); - - Allocation *tba = getAllocation(textblock), - *fla = vloat->getWidget()->getAllocation (); - yRelToFloat = tba->y + y - fla->y; - - DBG_OBJ_MSGF ("border", 1, - "caller is not CB: yRelToFloat = %d + %d - %d = %d", - tba->y, y, fla->y, yRelToFloat); - } - - ensureFloatSize (vloat); - int height = vloat->size.ascent + vloat->size.descent - yRelToFloat; - - DBG_OBJ_MSGF ("border", 1, "=> (%d + %d) - %d = %d", - vloat->size.ascent, vloat->size.descent, yRelToFloat, height); - DBG_OBJ_LEAVE (); - return height; -} - -/** - * Returns position relative to the textblock "tb". - */ -int OutOfFlowMgr::getClearPosition (Textblock *tb) -{ - return getTextblock(tb)->clearPosition; -} - -int OutOfFlowMgr::calcClearPosition (Textblock *tb) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p", tb); - - int pos; - - if (tb->getStyle()) { - bool left = false, right = false; - switch (tb->getStyle()->clear) { - case CLEAR_NONE: break; - case CLEAR_LEFT: left = true; break; - case CLEAR_RIGHT: right = true; break; - case CLEAR_BOTH: left = right = true; break; - default: assertNotReached (); - } - - pos = max (left ? calcClearPosition (tb, LEFT) : 0, - right ? calcClearPosition (tb, RIGHT) : 0); - } else - pos = 0; - - DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos); - DBG_OBJ_LEAVE (); - - return pos; -} - -int OutOfFlowMgr::calcClearPosition (Textblock *tb, Side side) -{ - DBG_OBJ_ENTER ("resize.oofm", 0, "getClearPosition", "%p, %s", - tb, side == LEFT ? "LEFT" : "RIGHT"); - - int pos; - - if (!wasAllocated (tb)) - // There is no relation yet to floats generated by other - // textblocks, and this textblocks floats are unimportant for - // the "clear" property. - pos = 0; - else { - SortedFloatsVector *list = side == LEFT ? leftFloatsCB : rightFloatsCB; - - // Search the last float before (therfore -1) this textblock. - int i = list->findFloatIndex (tb, -1); - if (i < 0) { - pos = 0; - DBG_OBJ_MSG ("resize.oofm", 1, "no float"); - } else { - Float *vloat = list->get(i); - assert (vloat->generatingBlock != tb); - if (!wasAllocated (vloat->generatingBlock)) - pos = 0; // See above. - else { - ensureFloatSize (vloat); - pos = max (getAllocation(vloat->generatingBlock)->y + vloat->yReal - + vloat->size.ascent + vloat->size.descent - - getAllocation(tb)->y, - 0); - DBG_OBJ_MSGF ("resize.oofm", 1, - "float %p => max (%d + %d + (%d + %d) - %d, 0)", - vloat->getWidget (), - getAllocation(vloat->generatingBlock)->y, - vloat->yReal, vloat->size.ascent, vloat->size.descent, - getAllocation(tb)->y); - } - } - } - - DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", pos); - DBG_OBJ_LEAVE (); - - return pos; -} - -void OutOfFlowMgr::ensureFloatSize (Float *vloat) -{ - // Historical note: relative sizes (e. g. percentages) are already - // handled by (at this time) Layout::containerSizeChanged, so - // Float::dirty will be set. - - DBG_OBJ_ENTER ("resize.oofm", 0, "ensureFloatSize", "%p", - vloat->getWidget ()); - - if (vloat->dirty) { - DBG_OBJ_MSG ("resize.oofm", 1, "dirty: recalculation"); - - vloat->getWidget()->sizeRequest (&vloat->size); - vloat->cbLineBreakWidth = containingBlock->getLineBreakWidth (); - vloat->dirty = false; - DBG_OBJ_SET_BOOL_O (vloat->getWidget (), "<Float>.dirty", vloat->dirty); - - DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)", - vloat->size.width, vloat->size.ascent, vloat->size.descent); - - DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width", - vloat->size.width); - DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.ascent", - vloat->size.ascent); - DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.descent", - vloat->size.descent); - - // "sizeChangedSinceLastAllocation" is reset in sizeAllocateEnd() - } - - DBG_OBJ_LEAVE (); -} +} // namespace oof } // namespace dw diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh index 179d4aa0..151c29f5 100644 --- a/dw/outofflowmgr.hh +++ b/dw/outofflowmgr.hh @@ -5,426 +5,88 @@ namespace dw { -class Textblock; +/** + * \brief Out Of Flow. See \ref dw-out-of-flow. + */ +namespace oof { + +class OOFAwareWidget; /** - * \brief Represents additional data for containing blocks. + * \brief Represents additional data for OOF containers. */ class OutOfFlowMgr { - friend class WidgetInfo; - -private: - enum Side { LEFT, RIGHT }; - enum SFVType { GB, CB }; - - Textblock *containingBlock; - - // These two values are redundant to TBInfo::wasAllocated and - // TBInfo::allocation, for some special cases. - bool containingBlockWasAllocated; - core::Allocation containingBlockAllocation; - - class WidgetInfo: public lout::object::Object - { - private: - bool wasAllocated; - int xCB, yCB; // relative to the containing block - int width, height; - - OutOfFlowMgr *oofm; - core::Widget *widget; - - protected: - OutOfFlowMgr *getOutOfFlowMgr () { return oofm; } - - public: - WidgetInfo (OutOfFlowMgr *oofm, core::Widget *widget); - - inline bool wasThenAllocated () { return wasAllocated; } - inline int getOldXCB () { return xCB; } - inline int getOldYCB () { return yCB; } - inline int getOldWidth () { return width; } - inline int getOldHeight () { return height; } - - - void update (bool wasAllocated, int xCB, int yCB, int width, int height); - - inline core::Widget *getWidget () { return widget; } - }; - - class Float: public WidgetInfo - { - public: - class ComparePosition: public lout::object::Comparator - { - private: - OutOfFlowMgr *oofm; - Textblock *refTB; - SFVType type; // actually only used for debugging - - public: - ComparePosition (OutOfFlowMgr *oofm, Textblock *refTB, SFVType type) - { this->oofm = oofm; this->refTB = refTB; this->type = type; } - int compare(Object *o1, Object *o2); - }; - - class CompareSideSpanningIndex: public lout::object::Comparator - { - public: - int compare(Object *o1, Object *o2); - }; - - class CompareGBAndExtIndex: public lout::object::Comparator - { - private: - OutOfFlowMgr *oofm; - SFVType type; // actually only used for debugging - - public: - CompareGBAndExtIndex (OutOfFlowMgr *oofm, SFVType type) - { this->oofm = oofm; this->type = type; } - int compare(Object *o1, Object *o2); - }; - - Textblock *generatingBlock; - int externalIndex; - int yReq, yReal; // relative to generator, not container - int indexGBList; /* Refers to TBInfo::leftFloatsGB or - TBInfo::rightFloatsGB, respectively. -1 - initially. */ - int indexCBList; /* Refers to leftFloatsCB or rightFloatsCB, - respectively. -1 initially. */ - int sideSpanningIndex, mark; - core::Requisition size; - int cbLineBreakWidth; /* On which the calculation of relative sizes - is based. Height not yet used, and probably - not added before size redesign. */ - bool dirty, sizeChangedSinceLastAllocation; - - Float (OutOfFlowMgr *oofm, core::Widget *widget, - Textblock *generatingBlock, int externalIndex); - - inline bool isNowAllocated () { return getWidget()->wasAllocated (); } - inline int getNewXCB () { return getWidget()->getAllocation()->x - - getOutOfFlowMgr()->containingBlockAllocation.x; } - inline int getNewYCB () { return getWidget()->getAllocation()->y - - getOutOfFlowMgr()->containingBlockAllocation.y; } - inline int getNewWidth () { return getWidget()->getAllocation()->width; } - inline int getNewHeight () { return getWidget()->getAllocation()->ascent + - getWidget()->getAllocation()->descent; } - void updateAllocation (); - - inline int *getIndexRef (SFVType type) { - return type == GB ? &indexGBList : &indexCBList; } - inline int getIndex (SFVType type) { return *(getIndexRef (type)); } - inline void setIndex (SFVType type, int value) { - *(getIndexRef (type)) = value; } - - void intoStringBuffer(lout::misc::StringBuffer *sb); - - bool covers (Textblock *textblock, int y, int h); - }; - - /** - * This list is kept sorted. - * - * To prevent accessing methods of the base class in an - * uncontrolled way, the inheritance is private, not public; this - * means that all methods must be delegated (see iterator(), size() - * etc. below.) - * - * TODO Update comment: still sorted, but ... - * - * More: add() and change() may check order again. - */ - class SortedFloatsVector: private lout::container::typed::Vector<Float> - { - public: - SFVType type; - - private: - OutOfFlowMgr *oofm; - Side side; - - public: - inline SortedFloatsVector (OutOfFlowMgr *oofm, Side side, SFVType type) : - lout::container::typed::Vector<Float> (1, false) - { this->oofm = oofm; this->side = side; this->type = type; } - - int findFloatIndex (Textblock *lastGB, int lastExtIndex); - int find (Textblock *textblock, int y, int start, int end); - int findFirst (Textblock *textblock, int y, int h, Textblock *lastGB, - int lastExtIndex, int *lastReturn); - int findLastBeforeSideSpanningIndex (int sideSpanningIndex); - void put (Float *vloat); - - inline lout::container::typed::Iterator<Float> iterator() - { return lout::container::typed::Vector<Float>::iterator (); } - inline int size () - { return lout::container::typed::Vector<Float>::size (); } - inline Float *get (int pos) - { return lout::container::typed::Vector<Float>::get (pos); } - inline void clear () - { lout::container::typed::Vector<Float>::clear (); } - }; - - class TBInfo: public WidgetInfo - { - public: - int lineBreakWidth; - int index; // position within "tbInfos" - - TBInfo *parent; - int parentExtIndex; - - // These two values are set by sizeAllocateStart(), and they are - // accessable also within sizeAllocateEnd() for the same - // textblock, for which allocation and WAS_ALLOCATED is set - // *after* sizeAllocateEnd(). See the two functions - // wasAllocated(Widget*) and getAllocation(Widget*) (further - // down) for usage. - bool wasAllocated; - core::Allocation allocation; - int clearPosition; - - // These two lists store all floats generated by this textblock, - // as long as this textblock is not allocates. - SortedFloatsVector *leftFloatsGB, *rightFloatsGB; - - TBInfo (OutOfFlowMgr *oofm, Textblock *textblock, - TBInfo *parent, int parentExtIndex); - ~TBInfo (); - - inline bool isNowAllocated () { - return getOutOfFlowMgr()->wasAllocated (getTextblock ()); } - inline int getNewXCB () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->x - - getOutOfFlowMgr()->containingBlockAllocation.x; } - inline int getNewYCB () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->y - - getOutOfFlowMgr()->containingBlockAllocation.y; } - inline int getNewWidth () { - return getOutOfFlowMgr()->getAllocation (getTextblock ())->width; } - inline int getNewHeight () { - core::Allocation *allocation = - getOutOfFlowMgr()->getAllocation (getTextblock ()); - return allocation->ascent + allocation->descent; } - void updateAllocation (); - - inline Textblock *getTextblock () { return (Textblock*)getWidget (); } - }; - - // These two lists store all floats, in the order in which they are - // defined. Only used for iterators. - lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll; - - // These two lists store all floats whose generators are already - // allocated. - SortedFloatsVector *leftFloatsCB, *rightFloatsCB; - - // These two attributes are used in the size allocation process; - // see sizeAllocateStart and sizeAllocateEnd. - int lastAllocatedLeftFloat, lastAllocatedRightFloat; - - lout::container::typed::HashTable<lout::object::TypedPointer - <dw::core::Widget>, Float> *floatsByWidget; - - lout::container::typed::Vector<TBInfo> *tbInfos; - lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>, - TBInfo> *tbInfosByTextblock; - - int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark; - - /** - * Variant of Widget::wasAllocated(), which can also be used within - * OOFM::sizeAllocateEnd(). - */ - inline bool wasAllocated (Textblock *textblock) { - return getTextblock(textblock)->wasAllocated; - } - - /** - * Variant of Widget::getAllocation(), which can also be used - * within OOFM::sizeAllocateEnd(). - */ - inline core::Allocation *getAllocation (Textblock *textblock) { - return &(getTextblock(textblock)->allocation); - } - - void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex, - int diff); - Float *findFloatByWidget (core::Widget *widget); - - void moveFromGBToCB (Side side); - void sizeAllocateFloats (Side side, int newLastAllocatedFloat); - int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth, - int gbLineBreakWidth); - - bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos, - core::Widget **minFloat); - bool hasRelationChanged (TBInfo *tbInfo, Side side, int *minFloatPos, - core::Widget **minFloat); - bool hasRelationChanged (bool oldTBAlloc, - int oldTBx, int oldTBy, int oldTBw, int oldTBh, - int newTBx, int newTBy, int newTBw, int newTBh, - bool oldFlAlloc, - int oldFlx, int oldFly, int oldFlw, int oldFlh, - int newFlx, int newFly, int newFlw, int newFlh, - Side side, int *floatPos); - - void checkAllocatedFloatCollisions (Side side); - - bool doFloatsExceedCB (Side side); - bool haveExtremesChanged (Side side); - - void drawFloats (SortedFloatsVector *list, core::View *view, - core::Rectangle *area); - core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, - int level); - - bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal); - bool collidesH (Float *vloat, Float *other, SFVType type); - - void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame, - SortedFloatsVector **listOpp, Side *side); - - void getFloatsSize (core::Requisition *cbReq, Side side, int *width, - int *height); - void getFloatsExtremes (core::Extremes *cbExtr, Side side, int *minWidth, - int *maxWidth); - bool getFloatDiffToCB (Float *vloat, int *leftDiff, int *rightDiff); - - TBInfo *getTextblock (Textblock *textblock); - int getBorder (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - SortedFloatsVector *getFloatsListForTextblock (Textblock *textblock, - Side side); - bool hasFloat (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - - int getFloatHeight (Textblock *textblock, Side side, int y, int h, - Textblock *lastGB, int lastExtIndex); - - int calcClearPosition (Textblock *tb, Side side); - int calcClearPosition (Textblock *tb); - - void ensureFloatSize (Float *vloat); - - void tellFloatPosition (core::Widget *widget, int yReq); - - static inline bool isWidgetFloat (core::Widget *widget) - { return widget->getStyle()->vloat != core::style::FLOAT_NONE; } - - /* - * Format for parent ref (see also below for isRefOutOfFlow, - * createRefNormalFlow, and getLineNoFromRef. - * - * Widget in flow: - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | line number | 0 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * So, anything with the least signifant bit set to 1 is out of flow. - * - * Floats: - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | left float index | 0 | 0 | 1 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * | right float index | 1 | 0 | 1 | - * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - * - * Absolutely positioned blocks: solved differently in the - * "dillo_grows" repository. - */ - - inline static bool isRefFloat (int ref) - { return ref != -1 && (ref & 3) == 1; } - inline static bool isRefLeftFloat (int ref) - { return ref != -1 && (ref & 7) == 1; } - inline static bool isRefRightFloat (int ref) - { return ref != -1 && (ref & 7) == 5; } - - inline static int createRefLeftFloat (int index) - { return (index << 3) | 1; } - inline static int createRefRightFloat (int index) - { return (index << 3) | 5; } - - inline static int getFloatIndexFromRef (int ref) - { return ref == -1 ? ref : (ref >> 3); } - public: - OutOfFlowMgr (Textblock *containingBlock); - ~OutOfFlowMgr (); - - void sizeAllocateStart (Textblock *caller, core::Allocation *allocation); - void sizeAllocateEnd (Textblock *caller); - void containerSizeChangedForChildren (); - void draw (core::View *view, core::Rectangle *area); - - void markSizeChange (int ref); - void markExtremesChange (int ref); - core::Widget *getWidgetAtPoint (int x, int y, int level); - - static bool 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, + core::StackingIteratorStack *iteratorStack, + core::Widget **interruptedWidget, int *index) = 0; + + virtual void markSizeChange (int ref) = 0; + virtual void markExtremesChange (int ref) = 0; + virtual core::Widget *getWidgetAtPoint (int x, int y, + core::StackingIteratorStack + *iteratorStack, + core::Widget **interruptedWidget, + int *index)= 0; + + virtual void addWidgetInFlow (OOFAwareWidget *widget, + OOFAwareWidget *parent, int externalIndex) = 0; + virtual int addWidgetOOF (core::Widget *widget, OOFAwareWidget *generator, + int externalIndex) = 0; + virtual void moveExternalIndices (OOFAwareWidget *generator, + int oldStartIndex, int diff) = 0; + + virtual void tellPosition (core::Widget *widget, int x, int y) = 0; + + virtual void getSize (core::Requisition *containerReq, int *oofWidth, + int *oofHeight) = 0; + virtual bool containerMustAdjustExtraSpace ()= 0; + virtual void getExtremes (core::Extremes *containerExtr, int *oofMinWidth, + int *oofMaxWidth) = 0; + + + virtual int getLeftBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + virtual int getRightBorder (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + + virtual bool hasFloatLeft (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + virtual bool hasFloatRight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) = 0; + + virtual int getLeftFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) + = 0; + virtual int getRightFloatHeight (OOFAwareWidget *widget, int y, int h, + OOFAwareWidget *lastGen, int lastExtIndex) + = 0; + + virtual bool affectsLeftBorder (core::Widget *widget) = 0; + virtual bool affectsRightBorder (core::Widget *widget) = 0; + virtual bool mayAffectBordersAtAll () = 0; + + virtual int getClearPosition (OOFAwareWidget *widget) = 0; + + virtual bool dealingWithSizeOfChild (core::Widget *child) = 0; + virtual int getAvailWidthOfChild (core::Widget *child, bool forceValue) = 0; + virtual int getAvailHeightOfChild (core::Widget *child, bool forceValue) = 0; + // for iterators - inline int getNumWidgets () - { return leftFloatsAll->size() + rightFloatsAll->size(); } - - inline core::Widget *getWidget (int i) { - if (i < leftFloatsAll->size()) - return leftFloatsAll->get(i)->getWidget (); - else - return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget (); - } - - inline bool affectsLeftBorder (core::Widget *widget) { - return widget->getStyle()->vloat == core::style::FLOAT_LEFT; } - inline bool affectsRightBorder (core::Widget *widget) { - return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; } + virtual int getNumWidgets () = 0; + virtual core::Widget *getWidget (int i) = 0; }; +} // namespace oof + } // namespace dw #endif // __DW_OUTOFFLOWMGR_HH__ diff --git a/dw/ruler.cc b/dw/ruler.cc index 3fdbfb6d..979cb03c 100644 --- a/dw/ruler.cc +++ b/dw/ruler.cc @@ -32,15 +32,14 @@ Ruler::Ruler () void Ruler::sizeRequestImpl (core::Requisition *requisition) { - requisition->width = - lout::misc::max (getAvailWidth (true), getStyle()->boxDiffWidth ()); - requisition->ascent = getStyle()->boxOffsetY (); - requisition->descent = getStyle()->boxRestHeight (); + requisition->width = lout::misc::max (getAvailWidth (true), boxDiffWidth ()); + requisition->ascent = boxOffsetY (); + requisition->descent = boxRestHeight (); } void Ruler::getExtremesImpl (core::Extremes *extremes) { - extremes->minWidth = extremes->maxWidth = getStyle()->boxDiffWidth (); + extremes->minWidth = extremes->maxWidth = boxDiffWidth (); extremes->minWidthIntrinsic = extremes->minWidth; extremes->maxWidthIntrinsic = extremes->maxWidth; correctExtremes (extremes); @@ -63,7 +62,9 @@ bool Ruler::usesAvailWidth () return true; } -void Ruler::draw (core::View *view, core::Rectangle *area) +void Ruler::draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { drawWidgetBox (view, area, false); } diff --git a/dw/ruler.hh b/dw/ruler.hh index 1f3491bc..c94c2e55 100644 --- a/dw/ruler.hh +++ b/dw/ruler.hh @@ -20,7 +20,9 @@ protected: void getExtremesImpl (core::Extremes *extremes); void containerSizeChangedForChildren (); bool usesAvailWidth (); - void draw (core::View *view, core::Rectangle *area); + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); public: Ruler (); diff --git a/dw/selection.cc b/dw/selection.cc index b67f4a6d..a69eb82a 100644 --- a/dw/selection.cc +++ b/dw/selection.cc @@ -93,63 +93,79 @@ void SelectionState::resetLink () bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo, EventButton *event) { + DBG_IF_RTFL { + misc::StringBuffer sb; + it->intoStringBuffer (&sb); + DBG_OBJ_ENTER ("events", 0, "buttonPress", "[%s], %d, %d, ...", + sb.getChars (), charPos, linkNo); + } + Widget *itWidget = it->getWidget (); bool ret = false; - if (!event) return ret; - - if (event->button == 3) { - // menu popup - layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event); - ret = true; - } else if (linkNo != -1) { - // link handling - (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event); - resetLink (); - linkState = LINK_PRESSED; - linkButton = event->button; - DeepIterator *newLink = new DeepIterator (it); - if (newLink->isEmpty ()) { - delete newLink; + if (event) { + if (event->button == 3) { + // menu popup + layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event); + ret = true; + } else if (linkNo != -1) { + // link handling + (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event); resetLink (); - } else { - link = newLink; - // It may be that the user has pressed on something activatable - // (linkNo != -1), but there is no contents, e.g. with images - // without ALTernative text. - if (link) { - linkChar = correctCharPos (link, charPos); - linkNumber = linkNo; + linkState = LINK_PRESSED; + linkButton = event->button; + DeepIterator *newLink = new DeepIterator (it); + if (newLink->isEmpty ()) { + delete newLink; + resetLink (); + } else { + link = newLink; + // It may be that the user has pressed on something activatable + // (linkNo != -1), but there is no contents, e.g. with images + // without ALTernative text. + if (link) { + linkChar = correctCharPos (link, charPos); + linkNumber = linkNo; + } } - } - // We do not return the value of the signal method, - // but we do actually process this event. - ret = true; - } else if (event->button == 1) { - // normal selection handling - highlight (false, 0); - resetSelection (); - - selectionState = SELECTING; - DeepIterator *newFrom = new DeepIterator (it); - if (newFrom->isEmpty ()) { - delete newFrom; + // We do not return the value of the signal method, + // but we do actually process this event. + ret = true; + } else if (event->button == 1) { + // normal selection handling + highlight (false, 0); resetSelection (); - } else { - from = newFrom; - fromChar = correctCharPos (from, charPos); - to = from->cloneDeepIterator (); - toChar = correctCharPos (to, charPos); + + selectionState = SELECTING; + DeepIterator *newFrom = new DeepIterator (it); + if (newFrom->isEmpty ()) { + delete newFrom; + resetSelection (); + } else { + from = newFrom; + fromChar = correctCharPos (from, charPos); + to = from->cloneDeepIterator (); + toChar = correctCharPos (to, charPos); + } + ret = true; } - ret = true; } + DBG_OBJ_MSGF ("events", 1, "=> %s", ret ? "true" : "false"); + DBG_OBJ_LEAVE (); return ret; } bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo, EventButton *event) { + DBG_IF_RTFL { + misc::StringBuffer sb; + it->intoStringBuffer (&sb); + DBG_OBJ_ENTER ("events", 0, "buttonRelease", "[%s], %d, %d, ...", + sb.getChars (), charPos, linkNo); + } + Widget *itWidget = it->getWidget (); bool ret = false; @@ -186,6 +202,8 @@ bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo, } } + DBG_OBJ_MSGF ("events", 1, "=> %s", ret ? "true" : "false"); + DBG_OBJ_LEAVE (); return ret; } diff --git a/dw/simpletablecell.cc b/dw/simpletablecell.cc index 02f92db6..62b4a0a4 100644 --- a/dw/simpletablecell.cc +++ b/dw/simpletablecell.cc @@ -119,4 +119,9 @@ int SimpleTableCell::applyPerHeight (int containerHeight, return tablecell::applyPerHeight (this, containerHeight, perHeight); } +bool SimpleTableCell::adjustExtraSpaceWhenCorrectingRequisitionByOOF () +{ + return tablecell::adjustExtraSpaceWhenCorrectingRequisitionByOOF (); +} + } // namespace dw diff --git a/dw/simpletablecell.hh b/dw/simpletablecell.hh index 4c18b454..c90fc040 100644 --- a/dw/simpletablecell.hh +++ b/dw/simpletablecell.hh @@ -18,6 +18,8 @@ protected: bool getAdjustMinWidth (); + bool adjustExtraSpaceWhenCorrectingRequisitionByOOF (); + public: static int CLASS_ID; diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc new file mode 100644 index 00000000..cbdef129 --- /dev/null +++ b/dw/stackingcontextmgr.cc @@ -0,0 +1,216 @@ +/* + * Dillo Widget + * + * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.hh" +#include "../lout/debug.hh" + +using namespace lout::misc; +using namespace lout::container::typed; + +namespace dw { + +namespace core { + +StackingContextMgr::StackingContextMgr (Widget *widget) +{ + DBG_OBJ_CREATE ("dw::core::StackingContextMgr"); + + this->widget = widget; + + childSCWidgets = new Vector<Widget> (1, false); + DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size()); + + minZIndex = maxZIndex = 0; // Just to have some defined values. +} + +StackingContextMgr::~StackingContextMgr () +{ + delete childSCWidgets; + DBG_OBJ_DELETE (); +} + +void StackingContextMgr::addChildSCWidget (Widget *widget) +{ + if (childSCWidgets->size () == 0) + minZIndex = maxZIndex = widget->getStyle()->zIndex; + else { + minZIndex = min (minZIndex, widget->getStyle()->zIndex); + maxZIndex = max (maxZIndex, widget->getStyle()->zIndex); + } + + childSCWidgets->put (widget); + DBG_OBJ_SET_NUM ("childSCWidgets.size", childSCWidgets->size()); + DBG_OBJ_ARRSET_PTR ("childSCWidgets", childSCWidgets->size() - 1, widget); +} + +void StackingContextMgr::drawBottom (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, int *index) +{ + DBG_OBJ_ENTER ("draw", 0, "drawBottom", "(%d, %d, %d * %d), [%d], [%d]", + area->x, area->y, area->width, area->height, *zIndexOffset, + *index); + draw (view, area, iteratorStack, interruptedWidget, index, INT_MIN, -1, + zIndexOffset); + DBG_OBJ_LEAVE (); +} + +void StackingContextMgr::drawTop (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, int *index) +{ + DBG_OBJ_ENTER ("draw", 0, "drawTop", "(%d, %d, %d * %d), [%d], [%d]", + area->x, area->y, area->width, area->height, *zIndexOffset, + *index); + draw (view, area, iteratorStack, interruptedWidget, index, 0, INT_MAX, + zIndexOffset); + DBG_OBJ_LEAVE (); +} + +void StackingContextMgr::draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *zIndexOffset, + int startZIndex, int endZIndex, int *index) +{ + DBG_OBJ_ENTER ("draw", 0, "draw", "(%d, %d, %d * %d), [%d], %d, %d, [%d]", + area->x, area->y, area->width, area->height, + *zIndexOffset, startZIndex, endZIndex, *index); + + DBG_OBJ_MSGF ("draw", 1, "initially: index = %d (of %d)", + *index, childSCWidgets->size ()); + + int startZIndexEff = max (minZIndex, startZIndex), + endZIndexEff = min (maxZIndex, endZIndex); + // Make sure *zIndexOffset starts at 0, for zIndex = startZIndexEff, + // so *zIndexOffset = zIndex - startZIndexEff, and + // zIndex = *zIndexOffset + startZIndexEff. + while (*interruptedWidget == NULL && + *zIndexOffset <= endZIndexEff - startZIndexEff) { + DBG_OBJ_MSGF ("draw", 1, "drawing zIndex = %d + %d", + *zIndexOffset, startZIndexEff); + DBG_OBJ_MSG_START (); + + while (*interruptedWidget == NULL && *index < childSCWidgets->size ()) { + Widget *child = childSCWidgets->get (*index); + DBG_OBJ_MSGF ("draw", 2, "widget %p has zIndex = %d", + child, child->getStyle()->zIndex); + Rectangle childArea; + if (child->getStyle()->zIndex == *zIndexOffset + startZIndexEff && + child->intersects (area, &childArea)) + child->drawTotal (view, &childArea, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)++; + } + + if (*interruptedWidget == NULL) + (*zIndexOffset)++; + + DBG_OBJ_MSG_END (); + } + + DBG_OBJ_MSGF ("draw", 1, "finally: index = %d (of %d)", + *index, childSCWidgets->size ()); + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +Widget *StackingContextMgr::getTopWidgetAtPoint (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, int *index) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTop", "%d, %d", x, y); + Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget, + zIndexOffset, 0, INT_MAX, index); + DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", widget, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widget; +} + +Widget *StackingContextMgr::getBottomWidgetAtPoint (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, + int *index) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y); + Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget, + zIndexOffset, INT_MIN, -1, index); + DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", widget, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widget; +} + +Widget *StackingContextMgr::getWidgetAtPoint (int x, int y, + StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, + int startZIndex, int endZIndex, + int *index) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + + Widget *widgetAtPoint = NULL; + + // For *zIndexOffset, see draw(). Actually, we start at the end and iterate + // to the start (naming is somewhat confusing). + int startZIndexEff = max (minZIndex, startZIndex); + while (*interruptedWidget == NULL && widgetAtPoint == NULL && + *zIndexOffset >= 0) { + DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d + %d", + *zIndexOffset, startZIndexEff); + DBG_OBJ_MSG_START (); + + while (*interruptedWidget == NULL && widgetAtPoint == NULL && + *index >= 0) { + Widget *child = childSCWidgets->get (*index); + DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d", + child, child->getStyle()->zIndex); + if (child->getStyle()->zIndex == *zIndexOffset + startZIndexEff) + widgetAtPoint = + child->getWidgetAtPointTotal (x, y, iteratorStack, + interruptedWidget); + + if (*interruptedWidget == NULL) + (*index)--; + } + + if (*interruptedWidget == NULL) + (*zIndexOffset)--; + + DBG_OBJ_MSG_END (); + } + + DBG_OBJ_MSGF ("events", 0, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + +} // namespace core + +} // namespace dw diff --git a/dw/stackingcontextmgr.hh b/dw/stackingcontextmgr.hh new file mode 100644 index 00000000..3866c68a --- /dev/null +++ b/dw/stackingcontextmgr.hh @@ -0,0 +1,77 @@ +#ifndef __DW_STACKINGCONTEXTMGR_HH__ +#define __DW_STACKINGCONTEXTMGR_HH__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +#include "../lout/container.hh" + +#include <limits.h> + +namespace dw { + +namespace core { + +/** + * \brief See \ref dw-stacking-context. + */ +class StackingContextMgr +{ +private: + Widget *widget; + lout::container::typed::Vector<Widget> *childSCWidgets; + int minZIndex, maxZIndex; + + void draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, Widget **interruptedWidget, + int *zIndexOffset, int startZIndex, int endZIndex, int *index); + Widget *getWidgetAtPoint (int x, int y, StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *zIndexOffset, + int startZIndex, int endZIndex, int *index); + +public: + StackingContextMgr (Widget *widget); + ~StackingContextMgr (); + + inline static bool isEstablishingStackingContext (Widget *widget) { + return widget->getStyle()->position != style::POSITION_STATIC && + widget->getStyle()->zIndex != style::Z_INDEX_AUTO; + } + + inline static bool handledByStackingContextMgr (Widget *widget) { + // Each widget establishing a stacking context is child of another + // stacking context, so drawn by StackingContextMgr::drawTop or + // StackingContextMgr::drawBottom etc. + return widget->getParent () != NULL + && isEstablishingStackingContext (widget); + } + + void addChildSCWidget (Widget *widget); + + inline int getMinZIndex () { return minZIndex; } + inline int getMaxZIndex () { return maxZIndex; } + inline int getNumChildSCWidgets () { return childSCWidgets->size (); } + + void drawBottom (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *zIndexOffset, int *index); + void drawTop (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int *zIndexOffset, int *index); + + Widget *getTopWidgetAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, int *index); + Widget *getBottomWidgetAtPoint (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, + int *zIndexOffset, int *index); +}; + +} // namespace core + +} // namespace dw + +#endif // __DW_STACKINGCONTEXTMGR_HH__ diff --git a/dw/style.cc b/dw/style.cc index 54d9af4b..32a33a9e 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -93,6 +93,7 @@ void StyleAttrs::initValues () display = DISPLAY_INLINE; whiteSpace = WHITE_SPACE_NORMAL; cursor = CURSOR_DEFAULT; + zIndex = Z_INDEX_AUTO; } /** @@ -203,6 +204,7 @@ bool StyleAttrs::equals (object::Object *other) { listStylePosition == otherAttrs->listStylePosition && listStyleType == otherAttrs->listStyleType && cursor == otherAttrs->cursor && + zIndex == otherAttrs->zIndex && x_link == otherAttrs->x_link && x_lang[0] == otherAttrs->x_lang[0] && x_lang[1] == otherAttrs->x_lang[1] && @@ -260,6 +262,7 @@ int StyleAttrs::hashValue () { listStylePosition + listStyleType + cursor + + zIndex + x_link + x_lang[0] + x_lang[1] + x_img + @@ -381,6 +384,7 @@ void Style::copyAttrs (StyleAttrs *attrs) listStylePosition = attrs->listStylePosition; listStyleType = attrs->listStyleType; cursor = attrs->cursor; + zIndex = attrs->zIndex; x_link = attrs->x_link; x_lang[0] = attrs->x_lang[0]; x_lang[1] = attrs->x_lang[1]; diff --git a/dw/style.hh b/dw/style.hh index 230baa24..12ca1664 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -7,6 +7,8 @@ # error Do not include this file directly, use "core.hh" instead. #endif +#include <limits.h> + #include "../lout/signal.hh" #include "../lout/debug.hh" @@ -374,6 +376,17 @@ enum ClearType { CLEAR_NONE }; +enum { + /** + * \brief 'z-index' is stored as int; use this for the value 'auto'. + * + * Only some random value, which has to be checked explicitly; do + * not compare this (less or greater) to integer values of + * 'z-index'. + */ + Z_INDEX_AUTO = INT_MAX +}; + /** * \brief Type for representing all lengths within dw::core::style. * @@ -553,6 +566,7 @@ public: ListStylePosition listStylePosition; ListStyleType listStyleType; Cursor cursor; + int zIndex; int x_link; int x_img; diff --git a/dw/table.cc b/dw/table.cc index 661b8a11..c14ebf97 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -112,18 +112,20 @@ void Table::sizeRequestImpl (core::Requisition *requisition) /** * \bug Baselines are not regarded here. */ - requisition->width = getStyle()->boxDiffWidth () - + (numCols + 1) * getStyle()->hBorderSpacing; + requisition->width = + boxDiffWidth () + (numCols + 1) * getStyle()->hBorderSpacing; for (int col = 0; col < numCols; col++) requisition->width += colWidths->get (col); requisition->ascent = - getStyle()->boxDiffHeight () + cumHeight->get (numRows) - + getStyle()->vBorderSpacing; + boxDiffHeight () + cumHeight->get (numRows) + getStyle()->vBorderSpacing; requisition->descent = 0; correctRequisition (requisition, core::splitHeightPreserveDescent); + // For the order, see similar reasoning for dw::Textblock. + correctRequisitionByOOF (requisition, core::splitHeightPreserveDescent); + DBG_OBJ_LEAVE (); } @@ -152,6 +154,9 @@ void Table::getExtremesImpl (core::Extremes *extremes) correctExtremes (extremes); + // For the order, see similar reasoning for dw::Textblock. + correctExtremesByOOF (extremes); + DBG_OBJ_LEAVE (); } @@ -161,16 +166,16 @@ void Table::sizeAllocateImpl (core::Allocation *allocation) allocation->x, allocation->y, allocation->width, allocation->ascent, allocation->descent); + sizeAllocateStart (allocation); + calcCellSizes (true); /** * \bug Baselines are not regarded here. */ - int offy = - allocation->y + getStyle()->boxOffsetY () + getStyle()->vBorderSpacing; - int x = - allocation->x + getStyle()->boxOffsetX () + getStyle()->hBorderSpacing; + int offy = allocation->y + boxOffsetY () + getStyle()->vBorderSpacing; + int x = allocation->x + boxOffsetX () + getStyle()->hBorderSpacing; for (int col = 0; col < numCols; col++) { for (int row = 0; row < numRows; row++) { @@ -201,6 +206,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation) x += colWidths->get (col) + getStyle()->hBorderSpacing; } + sizeAllocateEnd (); + DBG_OBJ_LEAVE (); } @@ -218,16 +225,22 @@ int Table::getAvailWidthOfChild (Widget *child, bool forceValue) child, forceValue ? "true" : "false"); int width; + oof::OutOfFlowMgr *oofm; - // Unlike other containers, the table widget sometimes narrows - // columns to a width less than specified by CSS (see - // forceCalcCellSizes). For this reason, the column widths have to - // be calculated in all cases. - if (forceValue) { - calcCellSizes (false); - width = calcAvailWidthForDescendant (child); - } else - width = -1; + if (isWidgetOOF(child) && (oofm = getWidgetOutOfFlowMgr(child)) && + oofm->dealingWithSizeOfChild (child)) + width = oofm->getAvailWidthOfChild (child, forceValue); + else { + // Unlike other containers, the table widget sometimes narrows + // columns to a width less than specified by CSS (see + // forceCalcCellSizes). For this reason, the column widths have to + // be calculated in all cases. + if (forceValue) { + calcCellSizes (false); + width = calcAvailWidthForDescendant (child); + } else + width = -1; + } DBG_OBJ_MSGF ("resize", 1, "=> %d", width); DBG_OBJ_LEAVE (); @@ -306,6 +319,8 @@ void Table::containerSizeChangedForChildren () } } + containerSizeChangedForChildrenOOF (); + DBG_OBJ_LEAVE (); } @@ -341,18 +356,22 @@ bool Table::isBlockLevel () return true; } -void Table::draw (core::View *view, core::Rectangle *area) +void Table::drawLevel (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel) { - // Can be optimized, by iterating on the lines in area. - drawWidgetBox (view, area, false); + DBG_OBJ_ENTER ("draw", 0, "Table/drawLevel", "(%d, %d, %d * %d), %s", + area->x, area->y, area->width, area->height, + OOFStackingIterator::majorLevelText (majorLevel)); #if 0 + // This old code belongs perhaps to the background. Check when reactivated. int offx = getStyle()->boxOffsetX () + getStyle()->hBorderSpacing; int offy = getStyle()->boxOffsetY () + getStyle()->vBorderSpacing; int width = getContentWidth (); - + // This part seems unnecessary. It also segfaulted sometimes when - // cumHeight size was less than numRows. --jcid + // cumHeight size was less than numRows. --jcid for (int row = 0; row < numRows; row++) { if (rowStyle->get (row)) drawBox (view, rowStyle->get (row), area, @@ -363,14 +382,95 @@ void Table::draw (core::View *view, core::Rectangle *area) } #endif - for (int i = 0; i < children->size (); i++) { - if (childDefined (i)) { - Widget *child = children->get(i)->cell.widget; - core::Rectangle childArea; - if (child->intersects (area, &childArea)) - child->draw (view, &childArea); + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + + while (*interruptedWidget == NULL && osi->index < children->size ()) { + if (childDefined (osi->index)) { + Widget *child = children->get(osi->index)->cell.widget; + core::Rectangle childArea; + if (!core::StackingContextMgr::handledByStackingContextMgr + (child) + && child->intersects (area, &childArea)) + child->drawTotal (view, &childArea, iteratorStack, + interruptedWidget); + } + + if (*interruptedWidget == NULL) + osi->index++; + } + } + break; + + default: + OOFAwareWidget::drawLevel (view, area, iteratorStack, interruptedWidget, + majorLevel); + break; + } + + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} + +core::Widget *Table::getWidgetAtPointLevel (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int majorLevel) +{ + DBG_OBJ_ENTER ("events", 0, "Table/getWidgetAtPointLevel", "%d, %d, %s", + x, y, OOFStackingIterator::majorLevelText (majorLevel)); + + Widget *widgetAtPoint = NULL; + + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + + while (widgetAtPoint == NULL && *interruptedWidget == NULL && + osi->index >= 0) { + if (childDefined (osi->index)) { + Widget *child = children->get(osi->index)->cell.widget; + if (!core::StackingContextMgr::handledByStackingContextMgr + (child)) + widgetAtPoint = + child->getWidgetAtPointTotal (x, y, iteratorStack, + interruptedWidget); + } + + if (*interruptedWidget == NULL) + osi->index--; + } } + break; + + default: + widgetAtPoint = + OOFAwareWidget::getWidgetAtPointLevel (x, y, iteratorStack, + interruptedWidget, majorLevel); + break; } + + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + +int Table::getLastLevelIndex (int majorLevel, int minorLevel) +{ + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + return children->size () - 1; + + default: + return OOFAwareWidget::getLastLevelIndex (majorLevel, minorLevel); + } } void Table::removeChild (Widget *child) @@ -465,6 +565,8 @@ void Table::addCell (Widget *widget, int colspan, int rowspan) curCol += colspanEff; + widget->parentRef = makeParentRefInFlow (0); + widget->setParent (this); if (rowStyle->get (curRow)) widget->setBgColor (rowStyle->get(curRow)->backgroundColor); diff --git a/dw/table.hh b/dw/table.hh index 1e7c5268..44abc42f 100644 --- a/dw/table.hh +++ b/dw/table.hh @@ -1,7 +1,7 @@ #ifndef __DW_TABLE_HH__ #define __DW_TABLE_HH__ -#include "core.hh" +#include "oofawarewidget.hh" #include "alignedtablecell.hh" #include "../lout/misc.hh" @@ -319,7 +319,7 @@ namespace dw { * Here, \em foo-bar refers to the attribute \em bar of the tag \em foo foo. * Look at the HTML parser for more details. */ -class Table: public core::Widget +class Table: public oof::OOFAwareWidget { private: struct Child @@ -339,20 +339,17 @@ private: }; }; - class TableIterator: public core::Iterator + class TableIterator: public OOFAwareWidgetIterator { - private: - int index; + protected: + int numContentsInFlow (); + void getContentInFlow (int index, core::Content *content); public: TableIterator (Table *table, core::Content::Type mask, bool atEnd); - TableIterator (Table *table, core::Content::Type mask, int index); lout::object::Object *clone(); - int compareTo(lout::object::Comparable *other); - bool next (); - bool prev (); void highlight (int start, int end, core::HighlightLayer layer); void unhighlight (int direction, core::HighlightLayer layer); void getAllocation (int start, int end, core::Allocation *allocation); @@ -474,7 +471,14 @@ protected: bool isBlockLevel (); - void draw (core::View *view, core::Rectangle *area); + void drawLevel (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel); + + Widget *getWidgetAtPointLevel (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel); + int getLastLevelIndex (int majorLevel, int minorLevel); //bool buttonPressImpl (core::EventButton *event); //bool buttonReleaseImpl (core::EventButton *event); diff --git a/dw/table_iterator.cc b/dw/table_iterator.cc index 4da0ef4f..9ba61619 100644 --- a/dw/table_iterator.cc +++ b/dw/table_iterator.cc @@ -28,107 +28,62 @@ namespace dw { Table::TableIterator::TableIterator (Table *table, core::Content::Type mask, bool atEnd): - core::Iterator (table, mask, atEnd) + OOFAwareWidgetIterator (table, mask, atEnd, table->children->size ()) { - index = atEnd ? table->children->size () : -1; - content.type = atEnd ? core::Content::END : core::Content::START; -} - -Table::TableIterator::TableIterator (Table *table, - core::Content::Type mask, int index): - core::Iterator (table, mask, false) -{ - this->index = index; - - if (index < 0) - content.type = core::Content::START; - else if (index >= table->children->size ()) - content.type = core::Content::END; - else { - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - } } object::Object *Table::TableIterator::clone() { - return new TableIterator ((Table*)getWidget(), getMask(), index); -} - -int Table::TableIterator::compareTo(object::Comparable *other) -{ - return index - ((TableIterator*)other)->index; + TableIterator *tIt = + new TableIterator ((Table*)getWidget(), getMask(), false); + cloneValues (tIt); + return tIt; } -bool Table::TableIterator::next () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::END) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::END; - return false; - } - - do { - index++; - if (index >= table->children->size ()) { - content.type = core::Content::END; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} - -bool Table::TableIterator::prev () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::START) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::START; - return false; - } - - do { - index--; - if (index < 0) { - content.type = core::Content::START; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} void Table::TableIterator::highlight (int start, int end, core::HighlightLayer layer) { - /** todo Needs this an implementation? */ + if (inFlow ()) { + /** todo Needs this an implementation? */ + } else + highlightOOF (start, end, layer); } void Table::TableIterator::unhighlight (int direction, core::HighlightLayer layer) { + if (inFlow ()) { + // ??? + } else + unhighlightOOF (direction, layer); } void Table::TableIterator::getAllocation (int start, int end, core::Allocation *allocation) { - /** \bug Not implemented. */ + if (inFlow ()) { + /** \bug Not implemented. */ + } else + getAllocationOOF (start, end, allocation); +} + +int Table::TableIterator::numContentsInFlow () +{ + return ((Table*)getWidget())->children->size (); +} + +void Table::TableIterator::getContentInFlow (int index, + core::Content *content) +{ + Table *table = (Table*)getWidget(); + + if (table->children->get(index) != NULL && + table->children->get(index)->type == Child::CELL) { + content->type = core::Content::WIDGET_IN_FLOW; + content->widget = table->children->get(index)->cell.widget; + } else + content->type = core::Content::INVALID; } } // namespace dw diff --git a/dw/tablecell.hh b/dw/tablecell.hh index 2e26c8e8..f7936203 100644 --- a/dw/tablecell.hh +++ b/dw/tablecell.hh @@ -28,6 +28,8 @@ int applyPerWidth (core::Widget *widget, int containerWidth, int applyPerHeight (core::Widget *widget, int containerHeight, core::style::Length perHeight); +inline bool adjustExtraSpaceWhenCorrectingRequisitionByOOF () { return false; } + } // namespace dw } // namespace dw diff --git a/dw/textblock.cc b/dw/textblock.cc index 47ed7bdb..d88b411f 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -227,7 +227,6 @@ Textblock::Textblock (bool limitTextWidth) registerName ("dw::Textblock", &CLASS_ID); setButtonSensitive(true); - containingBlock = NULL; hasListitemValue = false; leftInnerPadding = 0; line1Offset = 0; @@ -252,7 +251,6 @@ Textblock::Textblock (bool limitTextWidth) nonTemporaryLines = 0; words = new misc::NotSoSimpleVector <Word> (1); anchors = new misc::SimpleVector <Anchor> (1); - outOfFlowMgr = NULL; wrapRefLines = wrapRefParagraphs = -1; @@ -267,9 +265,6 @@ Textblock::Textblock (bool limitTextWidth) lineBreakWidth = -1; DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth); - verticalOffset = 0; - DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset); - this->limitTextWidth = limitTextWidth; for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) { @@ -278,6 +273,11 @@ Textblock::Textblock (bool limitTextWidth) hlStart[layer].nChar = 0; hlEnd[layer].index = 0; hlEnd[layer].nChar = 0; + + DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "index", hlStart[layer].index); + DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "nChar", hlStart[layer].nChar); + DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "index", hlEnd[layer].index); + DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "nChar", hlEnd[layer].nChar); } initNewLine (); @@ -285,8 +285,6 @@ Textblock::Textblock (bool limitTextWidth) Textblock::~Textblock () { - _MSG("Textblock::~Textblock\n"); - /* make sure not to call a free'd tooltip (very fast overkill) */ hoverTooltip = NULL; @@ -304,16 +302,6 @@ Textblock::~Textblock () delete words; delete anchors; - if(outOfFlowMgr) { - // I feel more comfortable by letting the textblock delete these - // widgets, instead of doing this in ~OutOfFlowMgr. - - for (int i = 0; i < outOfFlowMgr->getNumWidgets (); i++) - delete outOfFlowMgr->getWidget (i); - - delete outOfFlowMgr; - } - /* Make sure we don't own widgets anymore. Necessary before call of parent class destructor. (???) */ words = NULL; @@ -347,14 +335,15 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) // Note: the breakSpace of the last line is ignored, so breaks // at the end of a textblock are not visible. - requisition->width = lastLine->maxLineWidth + leftInnerPadding - + getStyle()->boxDiffWidth (); + requisition->width = + lastLine->maxLineWidth + leftInnerPadding + boxDiffWidth (); // Also regard collapsing of this widget top margin and the top // margin of the first line box: requisition->ascent = calcVerticalBorder (getStyle()->padding.top, getStyle()->borderWidth.top, - getStyle()->margin.top, + getStyle()->margin.top + + extraSpace.top, firstLine->borderAscent, firstLine->marginAscent); @@ -367,16 +356,14 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) // for this case is not necessary.) calcVerticalBorder (getStyle()->padding.bottom, getStyle()->borderWidth.bottom, - getStyle()->margin.bottom, + getStyle()->margin.bottom + extraSpace.bottom, lastLine->borderDescent, lastLine->marginDescent); } else { - requisition->width = leftInnerPadding + getStyle()->boxDiffWidth (); - requisition->ascent = getStyle()->boxOffsetY (); - requisition->descent = getStyle()->boxRestHeight ();; + requisition->width = leftInnerPadding + boxDiffWidth (); + requisition->ascent = boxOffsetY (); + requisition->descent = boxRestHeight ();; } - requisition->ascent += verticalOffset; - if (mustBeWidenedToAvailWidth ()) { DBG_OBJ_MSGF ("resize", 1, "before considering lineBreakWidth (= %d): %d * (%d + %d)", @@ -407,25 +394,7 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) // Is this really what we want? An alternative could be that // OutOfFlowMgr::getSize honours CSS attributes an corrected sizes. - DBG_OBJ_MSGF ("resize", 1, "before considering OOF widgets: %d * (%d + %d)", - requisition->width, requisition->ascent, requisition->descent); - - if (outOfFlowMgr) { - int oofWidth, oofHeight; - outOfFlowMgr->getSize (requisition, &oofWidth, &oofHeight); - - // Floats must be within the *content* area, not the *margin* - // area (which is equivalent to the requisition / - // allocation). For this reason, boxRestWidth() and - // boxRestHeight() must be considered. - - if (oofWidth + boxRestWidth () > requisition->width) - requisition->width = oofWidth + boxRestWidth (); - if (oofHeight + boxRestHeight () - > requisition->ascent + requisition->descent) - requisition->descent = - oofHeight + boxRestHeight () - requisition->ascent; - } + correctRequisitionByOOF (requisition, core::splitHeightPreserveAscent); DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)", requisition->width, requisition->ascent, requisition->descent); @@ -512,7 +481,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) extremes->minWidth, extremes->minWidthIntrinsic, extremes->maxWidth, extremes->maxWidthIntrinsic); - int diff = leftInnerPadding + getStyle()->boxDiffWidth (); + int diff = leftInnerPadding + boxDiffWidth (); extremes->minWidth += diff; extremes->minWidthIntrinsic += diff; extremes->maxWidth += diff; @@ -530,20 +499,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) extremes->minWidth, extremes->minWidthIntrinsic, extremes->maxWidth, extremes->maxWidthIntrinsic); - if (outOfFlowMgr) { - int oofMinWidth, oofMaxWidth; - outOfFlowMgr->getExtremes (extremes, &oofMinWidth, &oofMaxWidth); - - DBG_OBJ_MSGF ("resize", 1, "OOFM correction: %d / %d", - oofMinWidth, oofMaxWidth); - - extremes->minWidth = misc::max (extremes->minWidth, oofMinWidth); - extremes->minWidthIntrinsic = - misc::max (extremes->minWidthIntrinsic, oofMinWidth); - extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth); - extremes->maxWidthIntrinsic = - misc::max (extremes->maxWidthIntrinsic, oofMinWidth); - } + correctExtremesByOOF (extremes); DBG_OBJ_MSGF ("resize", 0, "finally, after considering OOFM: %d (%d) / %d (%d)", @@ -595,10 +551,10 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) (lines->size () > 0 ? calcVerticalBorder (getStyle()->padding.top, getStyle()->borderWidth.top, - getStyle()->margin.top, + getStyle()->margin.top + extraSpace.top, lines->getRef(0)->borderAscent, lines->getRef(0)->marginAscent) : - getStyle()->boxOffsetY ()) + verticalOffset); + boxOffsetY ())); childBaseAllocation.descent = allocation->ascent + allocation->descent - childBaseAllocation.ascent; @@ -608,8 +564,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) DBG_OBJ_SET_NUM ("childBaseAllocation.ascent", childBaseAllocation.ascent); DBG_OBJ_SET_NUM ("childBaseAllocation.descent", childBaseAllocation.descent); - if (containingBlock->outOfFlowMgr) - containingBlock->outOfFlowMgr->sizeAllocateStart (this, allocation); + sizeAllocateStart (allocation); int lineIndex, wordIndex; Line *line; @@ -737,9 +692,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; @@ -759,6 +713,20 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) DBG_OBJ_LEAVE (); } +void Textblock::calcExtraSpaceImpl () +{ + OOFAwareWidget::calcExtraSpaceImpl (); + + int clearPosition = 0; + for (int i = 0; i < NUM_OOFM; i++) + if (searchOutOfFlowMgr(i)) + clearPosition = + misc::max (clearPosition, + searchOutOfFlowMgr(i)->getClearPosition (this)); + + extraSpace.top = misc::max (extraSpace.top, clearPosition); +} + int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue) { DBG_OBJ_ENTER ("resize", 0, "Textblock/getAvailWidthOfChild", "%p, %s", @@ -766,25 +734,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); @@ -792,7 +766,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 () { @@ -804,9 +786,8 @@ void Textblock::containerSizeChangedForChildren () word->content.widget->containerSizeChanged (); } - if (outOfFlowMgr) - outOfFlowMgr->containerSizeChangedForChildren (); - + containerSizeChangedForChildrenOOF (); + DBG_OBJ_LEAVE (); } @@ -815,7 +796,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 () && @@ -858,13 +839,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 @@ -872,10 +850,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); @@ -895,13 +873,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 @@ -909,11 +884,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); @@ -922,61 +896,6 @@ void Textblock::markExtremesChange (int ref) DBG_OBJ_LEAVE (); } -void Textblock::notifySetAsTopLevel() -{ - PRINTF ("%p becomes toplevel\n", this); - containingBlock = this; - PRINTF ("-> %p is its own containing block\n", this); -} - -bool Textblock::isContainingBlock (Widget *widget) -{ - return - // Of course, only textblocks are considered as containing - // blocks. - widget->instanceOf (Textblock::CLASS_ID) && - // The second condition: that this block is "out of flow", in a - // wider sense. - (// The toplevel widget is "out of flow", since there is no - // parent, and so no context. - widget->getParent() == NULL || - // A similar reasoning applies to a widget with another parent - // than a textblock (typical example: a table cell (this is - // also a text block) within a table widget). - !widget->getParent()->instanceOf (Textblock::CLASS_ID) || - // Inline blocks are containing blocks, too. - widget->getStyle()->display == core::style::DISPLAY_INLINE_BLOCK || - // Same for blocks with 'overview' set to another value than - // (the default value) 'visible'. - widget->getStyle()->overflow != core::style::OVERFLOW_VISIBLE || - // Finally, "out of flow" in a narrower sense: floats and - // absolute positions. - OutOfFlowMgr::isWidgetOutOfFlow (widget)); -} - -void Textblock::notifySetParent () -{ - PRINTF ("%p becomes a child of %p\n", this, getParent()); - - // Search for containing Box. - containingBlock = NULL; - - for (Widget *widget = this; widget != NULL && containingBlock == NULL; - widget = widget->getParent()) - if (isContainingBlock (widget)) { - containingBlock = (Textblock*)widget; - - if (containingBlock == this) { - PRINTF ("-> %p is its own containing block\n", this); - } else { - PRINTF ("-> %p becomes containing block of %p\n", - containingBlock, this); - } - } - - assert (containingBlock != NULL); -} - bool Textblock::isBlockLevel () { return true; @@ -1066,6 +985,8 @@ void Textblock::leaveNotifyImpl (core::EventCrossing *event) bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, core::MousePositionEvent *event) { + DBG_OBJ_ENTER0 ("events", 0, "sendSelectionEvent"); + core::Iterator *it; int wordIndex; int charPos = 0, link = -1; @@ -1195,11 +1116,17 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, } } } - - it = new TextblockIterator (this, core::Content::maskForSelection (true), - false, wordIndex); + + DBG_OBJ_MSGF ("events", 1, "wordIndex = %d", wordIndex); + DBG_MSG_WORD ("events", 1, "<i>this is:</i> ", wordIndex, ""); + + it = TextblockIterator::createWordIndexIterator + (this, core::Content::maskForSelection (true), wordIndex); r = selectionHandleEvent (eventType, it, charPos, link, event); it->unref (); + + DBG_OBJ_MSGF ("events", 1, "=> %s", r ? "true" : "false"); + DBG_OBJ_LEAVE (); return r; } @@ -1520,10 +1447,14 @@ void Textblock::drawSpace(int wordIndex, core::View *view, * - area is used always (ev. set it to event->area) * - event is only used when is_expose */ -void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area) +void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., %d, %d, %d * %d", area->x, area->y, area->width, area->height); + + OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop (); int xWidget = line->textOffset; int yWidgetBase = lineYOffsetWidget (line) + line->borderAscent; @@ -1531,13 +1462,15 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area) DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)", line->firstWord, line->lastWord, words->size (), xWidget, yWidgetBase); - DBG_MSG_WORD ("draw", 0, "<i>line starts with: </i>", line->firstWord, ""); - DBG_MSG_WORD ("draw", 0, "<i>line ends with: </i>", line->lastWord, ""); + DBG_MSG_WORD ("draw", 1, "<i>line starts with: </i>", line->firstWord, ""); + DBG_MSG_WORD ("draw", 1, "<i>line ends with: </i>", line->lastWord, ""); - for (int wordIndex = line->firstWord; - wordIndex <= line->lastWord && xWidget < area->x + area->width; - wordIndex++) { - Word *word = words->getRef(wordIndex); + if (osi->index < line->firstWord) + osi->index = line->firstWord; + + while (*interruptedWidget == NULL && osi->index <= line->lastWord + && xWidget < area->x + area->width) { + Word *word = words->getRef (osi->index); int wordSize = word->size.width; if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) { @@ -1548,45 +1481,51 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area) if (word->content.type == core::Content::WIDGET_IN_FLOW) { core::Widget *child = word->content.widget; core::Rectangle childArea; - - if (child->intersects (area, &childArea)) - child->draw (view, &childArea); + if (!core::StackingContextMgr::handledByStackingContextMgr + (child) && + child->intersects (area, &childArea)) + child->drawTotal (view, &childArea, iteratorStack, + interruptedWidget); } else { - int wordIndex2 = wordIndex; + int wordIndex2 = osi->index; while (wordIndex2 < line->lastWord && (words->getRef(wordIndex2)->flags & Word::DRAW_AS_ONE_TEXT) && word->style == words->getRef(wordIndex2 + 1)->style) wordIndex2++; - drawWord(line, wordIndex, wordIndex2, view, area, + drawWord(line, osi->index, wordIndex2, view, area, xWidget, yWidgetBase); wordSize = 0; - for (int i = wordIndex; i <= wordIndex2; i++) + for (int i = osi->index; i <= wordIndex2; i++) wordSize += words->getRef(i)->size.width; - wordIndex = wordIndex2; - word = words->getRef(wordIndex); + osi->index = wordIndex2; + word = words->getRef (osi->index); } } - if (word->effSpace > 0 && wordIndex < line->lastWord && - words->getRef(wordIndex + 1)->content.type != + if (word->effSpace > 0 && osi->index < line->lastWord && + words->getRef(osi->index + 1)->content.type != core::Content::BREAK) { if (word->spaceStyle->hasBackground ()) drawBox (view, word->spaceStyle, area, xWidget + wordSize, yWidgetBase - line->borderAscent, word->effSpace, line->borderAscent + line->borderDescent, false); - drawSpace(wordIndex, view, area, xWidget + wordSize, - yWidgetBase); + drawSpace (osi->index, view, area, xWidget + wordSize, + yWidgetBase); } } } xWidget += wordSize + word->effSpace; + + if (*interruptedWidget == NULL) + osi->index++; } + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); DBG_OBJ_LEAVE (); } @@ -1608,7 +1547,8 @@ int Textblock::findLineIndexWhenNotAllocated (int y) return findLineIndex (y, calcVerticalBorder (getStyle()->padding.top, getStyle()->borderWidth.top, - getStyle()->margin.top, + getStyle()->margin.top + + extraSpace.top, lines->getRef(0)->borderAscent, lines->getRef(0)->marginAscent)); } @@ -1754,38 +1694,97 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace) return NULL; } -void Textblock::draw (core::View *view, core::Rectangle *area) +void Textblock::drawLevel (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel) { - DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d", - area->x, area->y, area->width, area->height); - - int lineIndex; - Line *line; + DBG_OBJ_ENTER ("draw", 0, "Textblock/drawLevel", "(%d, %d, %d * %d), %s", + area->x, area->y, area->width, area->height, + OOFStackingIterator::majorLevelText (majorLevel)); - // 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); + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + // Osi->index (word index) is regarded in drawLine. + for (int lineIndex = findLineIndexWhenAllocated (area->y); + *interruptedWidget == NULL && lineIndex < lines->size (); + lineIndex++) { + Line *line = lines->getRef (lineIndex); + if (lineYOffsetWidget (line) >= area->y + area->height) + break; + + DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ()); + drawLine (line, view, area, iteratorStack, interruptedWidget); + } + break; - lineIndex = findLineIndexWhenAllocated (area->y); + case OOFStackingIterator::OOF_REF: + handleOOFReferences (iteratorStack, interruptedWidget, false); + break; - for (; lineIndex < lines->size (); lineIndex++) { - line = lines->getRef (lineIndex); - if (lineYOffsetWidget (line) >= area->y + area->height) - break; - - DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ()); - drawLine (line, view, area); + default: + OOFAwareWidget::drawLevel (view, area, iteratorStack, interruptedWidget, + majorLevel); + break; } - if(outOfFlowMgr) - outOfFlowMgr->draw(view, area); + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + DBG_OBJ_LEAVE (); +} +/** + * \brief Used both for drawing and getting the widget at a point, + * since this method only interrupts, but does not do actual + * drawing or searching, respectively. + */ +void Textblock::handleOOFReferences (core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, bool backwards) +{ + // TODO Inefficient. Store Widgets OOF references in seperate list? + + DBG_OBJ_ENTER ("common", 0, "Textblock/handleOOFReferences", "..., %s", + backwards ? "true [backwards]" : "false [forwards]"); + + OOFStackingIterator *osi = (OOFStackingIterator*)iteratorStack->getTop (); + assert (osi->majorLevel == OOFStackingIterator::OOF_REF); + + while (*interruptedWidget == NULL && + (backwards ? (osi->minorLevel >= 0) : (osi->minorLevel < NUM_OOFM))) { + while (*interruptedWidget == NULL && + (backwards ? (osi->index >= 0) : (osi->index < words->size ()))) { + + //DBG_IF_RTFL { + // misc::StringBuffer sb; + // osi->intoStringBuffer (&sb); + // DBG_OBJ_MSGF ("common", 2, "osi = %s", + // sb.getChars ()); + //} + + Word *word = words->getRef (osi->index); + if (word->content.type == core::Content::WIDGET_OOF_REF && + getOOFMIndex (word->content.widget) == osi->minorLevel && + doesWidgetOOFInterruptDrawing (word->content.widget)) + *interruptedWidget = word->content.widget; + + // The index is increased in any case: the iterator must + // point to the next element. + if (backwards) + osi->index--; + else + osi->index++; + } + + if (*interruptedWidget == NULL) { + if (backwards) { + osi->minorLevel--; + osi->index = words->size () - 1; + } else { + osi->minorLevel++; + osi->index = 0; + } + } + } + + DBG_OBJ_MSGF ("common", 1, "=> %p", *interruptedWidget); DBG_OBJ_LEAVE (); } @@ -2345,21 +2344,23 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) widget->setStyle (style); - PRINTF ("adding the %s %p to %p (word %d) ...\n", - widget->getClassName(), widget, this, words->size()); + initOutOfFlowMgrs (); - if (containingBlock->outOfFlowMgr == NULL) { - containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock); - DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr); - } + if (testWidgetOutOfFlow (widget)) { + int oofmIndex = getOOFMIndex (widget); + widget->setParent (oofContainer[oofmIndex]); + widget->setGenerator (this); - if (OutOfFlowMgr::isWidgetHandledByOOFM (widget)) { - PRINTF (" -> out of flow.\n"); + int oofmSubRef = + searchOutOfFlowMgr(oofmIndex)->addWidgetOOF (widget, this, + words->size ()); + widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef); + + DBG_OBJ_MSGF ("construct.word", 1, + "ouf of flow: oofmIndex = %d, oofmSubRef = %d => " + "parentRef = %d", + oofmIndex, oofmSubRef, widget->parentRef); - widget->setParent (containingBlock); - widget->setGenerator (this); - containingBlock->outOfFlowMgr->addWidgetOOF (widget, this, - words->size ()); Word *word = addWord (0, 0, 0, 0, style); word->content.type = core::Content::WIDGET_OOF_REF; word->content.widget = widget; @@ -2368,14 +2369,16 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) // problems with breaking near float definitions.) setBreakOption (word, style, 0, 0, false); } else { - PRINTF (" -> within flow.\n"); + DBG_OBJ_MSG ("construct.word", 1, "in flow"); widget->setParent (this); // TODO Replace (perhaps) later "textblock" by "OOF aware widget". - if (widget->instanceOf (Textblock::CLASS_ID)) - containingBlock->outOfFlowMgr->addWidgetInFlow ((Textblock*)widget, - this, words->size ()); + if (widget->instanceOf (Textblock::CLASS_ID)) { + for (int i = 0; i < NUM_OOFM; i++) + searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this, + words->size ()); + } core::Requisition size; widget->sizeRequest (&size); @@ -2613,7 +2616,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; @@ -2624,7 +2627,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 = @@ -2633,8 +2636,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; } } @@ -2733,60 +2735,74 @@ void Textblock::breakAdded () words->getRef(words->size () - 2)->effSpace = 0; } -/** - * \brief Search recursively through widget. - * - * This is an optimized version of the general - * dw::core::Widget::getWidgetAtPoint method. - */ -core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level) -{ - //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n", - // 3 * level, "", getClassName (), this, allocation.x, allocation.y, - // allocation.width, allocation.ascent, allocation.descent); - - int lineIndex, wordIndex; - Line *line; - - if (x < allocation.x || - y < allocation.y || - x > allocation.x + allocation.width || - y > allocation.y + getHeight ()) { - return NULL; - } - - // First, search for widgets out of flow, notably floats, since - // there are cases where they overlap child textblocks. Should - // later be refined using z-index. - Widget *oofWidget = - outOfFlowMgr ? outOfFlowMgr->getWidgetAtPoint (x, y, level) : NULL; - if (oofWidget) - return oofWidget; +core::Widget *Textblock::getWidgetAtPointLevel (int x, int y, + core::StackingIteratorStack + *iteratorStack, + Widget **interruptedWidget, + int majorLevel) +{ + DBG_OBJ_ENTER ("events", 0, "Textblock/getWidgetAtPointLevel", "%d, %d, %s", + x, y, OOFStackingIterator::majorLevelText (majorLevel)); + + Widget *widgetAtPoint = NULL; + + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + { + OOFStackingIterator *osi = + (OOFStackingIterator*)iteratorStack->getTop (); + + int lineIndex = findLineIndexWhenAllocated (y - allocation.y); + + if (lineIndex >= 0 || lineIndex < lines->size ()) { + Line *line = lines->getRef (lineIndex); + if (osi->index > line->lastWord) + osi->index = line->lastWord; + + while (widgetAtPoint == NULL && *interruptedWidget == NULL && + osi->index >= 0) { + Word *word = words->getRef (osi->index); + if (word->content.type == core::Content::WIDGET_IN_FLOW && + !core::StackingContextMgr::handledByStackingContextMgr + (word->content.widget)) + widgetAtPoint = word->content.widget + ->getWidgetAtPointTotal (x, y, iteratorStack, + interruptedWidget); + if (*interruptedWidget == NULL) + osi->index--; + } + } + } + break; - lineIndex = findLineIndexWhenAllocated (y - allocation.y); + case OOFStackingIterator::OOF_REF: + handleOOFReferences (iteratorStack, interruptedWidget, true); + // No searching, only interruption. + break; - if (lineIndex < 0 || lineIndex >= lines->size ()) { - return this; + default: + widgetAtPoint = + OOFAwareWidget::getWidgetAtPointLevel (x, y, iteratorStack, + interruptedWidget, majorLevel); + break; } - line = lines->getRef (lineIndex); + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", + widgetAtPoint, *interruptedWidget); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} - for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) { - Word *word = words->getRef (wordIndex); - - if (word->content.type == core::Content::WIDGET_IN_FLOW) { - core::Widget * childAtPoint; - if (word->content.widget->wasAllocated ()) { - childAtPoint = word->content.widget->getWidgetAtPoint (x, y, - level + 1); - if (childAtPoint) { - return childAtPoint; - } - } - } - } +int Textblock::getLastLevelIndex (int majorLevel, int minorLevel) +{ + switch (majorLevel) { + case OOFStackingIterator::IN_FLOW: + case OOFStackingIterator::OOF_REF: + return words->size () - 1; - return this; + default: + return OOFAwareWidget::getLastLevelIndex (majorLevel, minorLevel); + } } @@ -2890,6 +2906,8 @@ void Textblock::changeWordStyle (int from, int to, core::style::Style *style, void Textblock::queueDrawRange (int index1, int index2) { + DBG_OBJ_ENTER ("draw", 0, "queueDrawRange", "%d, %d", index1, index2); + int from = misc::min (index1, index2); int to = misc::max (index1, index2); @@ -2911,24 +2929,12 @@ void Textblock::queueDrawRange (int index1, int index2) queueDrawArea (0, y, allocation.width, h); } -} - -void Textblock::setVerticalOffset (int verticalOffset) -{ - DBG_OBJ_ENTER ("resize", 0, "setVerticalOffset", "%d", verticalOffset); - - if (this->verticalOffset != verticalOffset) { - this->verticalOffset = verticalOffset; - DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset); - mustQueueResize = true; - queueDraw (); // Could perhaps be optimized. - } DBG_OBJ_LEAVE (); } /** - * Called by dw::OutOfFlowMgr when the border has changed due to a + * Called by dw::OOFFloatsMgr when the border has changed due to a * float (or some floats). * * "y", which given in widget coordinates, denotes the minimal @@ -3057,7 +3063,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) @@ -3093,7 +3099,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 (); @@ -3101,6 +3107,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); @@ -3167,18 +3188,17 @@ int Textblock::yOffsetOfLineToBeCreated () int result; if (lines->size () == 0) { - result = verticalOffset + calcVerticalBorder (getStyle()->padding.top, - getStyle()->borderWidth.top, - getStyle()->margin.top, - 0, 0); + result = calcVerticalBorder (getStyle()->padding.top, + getStyle()->borderWidth.top + extraSpace.top, + getStyle()->margin.top, 0, 0); DBG_OBJ_MSGF ("line.yoffset", 1, "first line: ... = %d", result); } else { Line *firstLine = lines->getRef (0), *lastLine = lines->getLastRef (); - result = verticalOffset + calcVerticalBorder (getStyle()->padding.top, - getStyle()->borderWidth.top, - getStyle()->margin.top, - firstLine->borderAscent, - firstLine->marginAscent) + result = calcVerticalBorder (getStyle()->padding.top, + getStyle()->borderWidth.top, + getStyle()->margin.top + extraSpace.top, + firstLine->borderAscent, + firstLine->marginAscent) - firstLine->borderAscent + lastLine->top + lastLine->totalHeight (0); DBG_OBJ_MSGF ("line.yoffset", 1, "other line: ... = %d", result); } diff --git a/dw/textblock.hh b/dw/textblock.hh index 7dbb9d52..aaab0e1a 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. @@ -168,7 +167,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: @@ -196,7 +195,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: /** @@ -290,10 +289,8 @@ private: static const char *hyphenDrawChar; - Textblock *containingBlock; - OutOfFlowMgr *outOfFlowMgr; - protected: + /** * \brief Implementation used for words. */ @@ -505,27 +502,24 @@ protected: int wordIndex; }; - class TextblockIterator: public core::Iterator + class TextblockIterator: public OOFAwareWidgetIterator { - private: - bool oofm; - int index; + protected: + int numContentsInFlow (); + void getContentInFlow (int index, core::Content *content); public: TextblockIterator (Textblock *textblock, core::Content::Type mask, bool atEnd); - TextblockIterator (Textblock *textblock, core::Content::Type mask, - bool oofm, int index); + + static TextblockIterator *createWordIndexIterator + (Textblock *textblock, core::Content::Type mask, int wordIndex); lout::object::Object *clone(); - int compareTo(lout::object::Comparable *other); - bool next (); - bool prev (); void highlight (int start, int end, core::HighlightLayer layer); void unhighlight (int direction, core::HighlightLayer layer); void getAllocation (int start, int end, core::Allocation *allocation); - void print (); }; friend class TextblockIterator; @@ -583,9 +577,6 @@ protected: /* This value is (currently) set by setAscent(). */ int lineBreakWidth; - // Additional vertical offset, used for the "clear" attribute. - int verticalOffset; - int wrapRefLines, wrapRefParagraphs; /* 0-based. Important: Both are the line numbers, not the value stored in @@ -635,7 +626,6 @@ protected: void calcBorders (int lastOofRef, int height); void showMissingLines (); void removeTemporaryLines (); - void setVerticalOffset (int verticalOffset); void decorateText (core::View *view, core::style::Style *style, core::style::Color::Shading shading, @@ -652,7 +642,12 @@ protected: core::Rectangle *area, int xWidget, int yWidgetBase); void drawSpace (int wordIndex, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase); - void drawLine (Line *line, core::View *view, core::Rectangle *area); + void drawLine (Line *line, core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + void handleOOFReferences (core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, bool backwards); + int findLineIndex (int y); int findLineIndexWhenNotAllocated (int y); int findLineIndexWhenAllocated (int y); @@ -772,6 +767,7 @@ protected: void processWord (int wordIndex); virtual int wordWrap (int wordIndex, bool wrapAll); int wrapWordInFlow (int wordIndex, bool wrapAll); + int wrapWordOofRef (int wordIndex, bool wrapAll); void balanceBreakPosAndHeight (int wordIndex, int firstIndex, int *searchUntil, bool tempNewLine, int penaltyIndex, bool borderIsCalculated, @@ -806,10 +802,24 @@ protected: void alignLine (int lineIndex); void calcTextOffset (int lineIndex, int totalWidth); + void drawLevel (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel); + + Widget *getWidgetAtPointLevel (int x, int y, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget, int majorLevel); + int getLastLevelIndex (int majorLevel, int minorLevel); + void sizeRequestImpl (core::Requisition *requisition); void getExtremesImpl (core::Extremes *extremes); void sizeAllocateImpl (core::Allocation *allocation); - int getAvailWidthOfChild (Widget *child, bool forceValue); + + void calcExtraSpaceImpl (); + + int getAvailWidthOfChild (core::Widget *child, bool forceValue); + int getAvailHeightOfChild (core::Widget *child, bool forceValue); + void containerSizeChangedForChildren (); bool affectsSizeChangeContainerChild (Widget *child); bool usesAvailWidth (); @@ -818,13 +828,8 @@ protected: void markSizeChange (int ref); void markExtremesChange (int ref); - void notifySetAsTopLevel(); - void notifySetParent(); - bool isBlockLevel (); - void draw (core::View *view, core::Rectangle *area); - bool buttonPressImpl (core::EventButton *event); bool buttonReleaseImpl (core::EventButton *event); bool motionNotifyImpl (core::EventMotion *event); @@ -839,17 +844,23 @@ protected: core::style::Style *style, int numBreaks, int *breakPos, core::Requisition *wordSize); - static bool isContainingBlock (Widget *widget); inline bool mustBeWidenedToAvailWidth () { DBG_OBJ_ENTER0 ("resize", 0, "mustBeWidenedToAvailWidth"); bool toplevel = getParent () == NULL, block = getStyle()->display == core::style::DISPLAY_BLOCK, - vloat = getStyle()->vloat != core::style::FLOAT_NONE, - result = toplevel || (block && !vloat); - DBG_OBJ_MSGF ("resize", 0, "=> %s (toplevel: %s, block: %s, float: %s)", + vloat = testWidgetFloat (this), + abspos = testWidgetAbsolutelyPositioned (this), + fixpos = testWidgetFixedlyPositioned (this), + // In detail, this depends on what the respective OOFM does + // with the child widget: + result = toplevel || (block && !(vloat || abspos || fixpos)); + DBG_OBJ_MSGF ("resize", 0, + "=> %s (toplevel: %s, block: %s, float: %s, abspos: %s, " + "fixpos: %s)", result ? "true" : "false", toplevel ? "true" : "false", - block ? "true" : "false", vloat ? "true" : "false"); + block ? "true" : "false", vloat ? "true" : "false", + abspos ? "true" : "false", fixpos ? "true" : "false"); DBG_OBJ_LEAVE (); return result; } @@ -864,8 +875,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); @@ -883,7 +894,6 @@ public: void addParbreak (int space, core::style::Style *style); void addLinebreak (core::style::Style *style); - core::Widget *getWidgetAtPoint (int x, int y, int level); void handOverBreak (core::style::Style *style); void changeLinkColor (int link, int newColor); void changeWordStyle (int from, int to, core::style::Style *style, @@ -892,7 +902,9 @@ public: void borderChanged (int y, core::Widget *vloat); void clearPositionChanged (); void oofSizeChanged (bool extremesChanged); - inline int getLineBreakWidth () { return lineBreakWidth; } + int getLineBreakWidth (); + bool isPossibleContainer (int oofmIndex); + bool isPossibleContainerParent (int oofmIndex); }; #define DBG_SET_WORD_PENALTY(n, i, is) \ diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc index b6423a29..95e2ce65 100644 --- a/dw/textblock_iterator.cc +++ b/dw/textblock_iterator.cc @@ -33,173 +33,48 @@ namespace dw { Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, core::Content::Type mask, bool atEnd): - core::Iterator (textblock, mask, atEnd) + OOFAwareWidgetIterator (textblock, mask, atEnd, textblock->words->size ()) { - if (atEnd) { - if (textblock->outOfFlowMgr) { - oofm = true; - index = textblock->outOfFlowMgr->getNumWidgets(); - } else { - oofm = false; - index = textblock->words->size(); - } - } else { - oofm = false; - index = -1; - } - - content.type = atEnd ? core::Content::END : core::Content::START; } -Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, - core::Content::Type mask, - bool oofm, int index): - core::Iterator (textblock, mask, false) +Textblock::TextblockIterator + *Textblock::TextblockIterator::createWordIndexIterator (Textblock *textblock, + core::Content::Type + mask, + int wordIndex) { - this->oofm = oofm; - this->index = index; - - // TODO To be completely exact, oofm should be considered here. - if (index < 0) - content.type = core::Content::START; - else if (index >= textblock->words->size()) - content.type = core::Content::END; - else - content = textblock->words->getRef(index)->content; + TextblockIterator *tbIt = new TextblockIterator (textblock, mask, false); + tbIt->setValues (0, wordIndex); + return tbIt; } object::Object *Textblock::TextblockIterator::clone() { - return - new TextblockIterator ((Textblock*)getWidget(), getMask(), oofm, index); -} - -int Textblock::TextblockIterator::compareTo(object::Comparable *other) -{ - TextblockIterator *otherTI = (TextblockIterator*)other; - - if (oofm && !otherTI->oofm) - return +1; - else if (!oofm && otherTI->oofm) - return -1; - else - return index - otherTI->index; -} - -bool Textblock::TextblockIterator::next () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::END) - return false; - - short type; - - do { - index++; - - if (oofm) { - // Iterating over OOFM. - if (index >= textblock->outOfFlowMgr->getNumWidgets()) { - // End of OOFM list reached. - content.type = core::Content::END; - return false; - } - type = core::Content::WIDGET_OOF_CONT; - } else { - // Iterating over words list. - if (index < textblock->words->size ()) - // Still words left. - type = textblock->words->getRef(index)->content.type; - else { - // End of words list reached. - if (textblock->outOfFlowMgr) { - oofm = true; - index = 0; - if (textblock->outOfFlowMgr->getNumWidgets() > 0) - // Start with OOFM widgets. - type = core::Content::WIDGET_OOF_CONT; - else { - // No OOFM widgets (number is 0). - content.type = core::Content::END; - return false; - } - } else { - // No OOFM widgets (no OOFM agt all). - content.type = core::Content::END; - return false; - } - } - } - } while ((type & getMask()) == 0); - - if (oofm) { - content.type = core::Content::WIDGET_OOF_CONT; - content.widget = textblock->outOfFlowMgr->getWidget (index); - } else - content = textblock->words->getRef(index)->content; - - return true; -} - -bool Textblock::TextblockIterator::prev () -{ - Textblock *textblock = (Textblock*)getWidget(); - - if (content.type == core::Content::START) - return false; - - short type; - - do { - index--; - - if (oofm) { - // Iterating over OOFM. - if (index >= 0) - // Still widgets left. - type = core::Content::WIDGET_OOF_CONT; - else { - // Beginning of OOFM list reached. Continue with words. - oofm = false; - index = textblock->words->size() - 1; - if (index < 0) { - // There are no words. (Actually, this case should not - // happen: When there are OOF widgets, ther must be OOF - // references, or widgets in flow, which contain - // references. - content.type = core::Content::END; - return false; - } - type = textblock->words->getRef(index)->content.type; - } - } else { - // Iterating over words list. - if (index < 0) { - // Beginning of words list reached. - content.type = core::Content::START; - return false; - } - type = textblock->words->getRef(index)->content.type; - } - } while ((type & getMask()) == 0); - - if (oofm) { - content.type = core::Content::WIDGET_OOF_CONT; - content.type = false; - content.widget = textblock->outOfFlowMgr->getWidget (index); - } else - content = textblock->words->getRef(index)->content; - - return true; + TextblockIterator *tbIt = + new TextblockIterator ((Textblock*)getWidget(), getMask(), false); + cloneValues (tbIt); + return tbIt; } void Textblock::TextblockIterator::highlight (int start, int end, core::HighlightLayer layer) { - if (!oofm) { + DBG_OBJ_ENTER_O ("iterator", 0, getWidget (), "TextblockIterator/highlight", + "..., %d, %d, %d", start, end, layer); + + DBG_IF_RTFL { + misc::StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s", + sb.getChars ()); + } + + if (inFlow ()) { + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d", + getInFlowIndex ()); + Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; + int index = getInFlowIndex (), index1 = index, index2 = index; int oldStartIndex = textblock->hlStart[layer].index; int oldStartChar = textblock->hlStart[layer].nChar; @@ -224,22 +99,46 @@ void Textblock::TextblockIterator::highlight (int start, int end, textblock->hlEnd[layer].nChar = end; } + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index", + textblock->hlStart[layer].index); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar", + textblock->hlStart[layer].nChar); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index", + textblock->hlEnd[layer].index); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar", + textblock->hlEnd[layer].nChar); + if (oldStartIndex != textblock->hlStart[layer].index || oldStartChar != textblock->hlStart[layer].nChar || oldEndIndex != textblock->hlEnd[layer].index || oldEndChar != textblock->hlEnd[layer].nChar) textblock->queueDrawRange (index1, index2); - } + } else + highlightOOF (start, end, layer); - // TODO What about OOF widgets? + DBG_OBJ_LEAVE_O (getWidget ()); } void Textblock::TextblockIterator::unhighlight (int direction, core::HighlightLayer layer) { - if (!oofm) { + DBG_OBJ_ENTER_O ("iterator", 0, getWidget (), + "TextblockIterator/unhighlight", "..., %d, %d", + direction, layer); + + DBG_IF_RTFL { + misc::StringBuffer sb; + intoStringBuffer (&sb); + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "iterator: %s", + sb.getChars ()); + } + + if (inFlow ()) { + DBG_OBJ_MSGF_O ("iterator", 1, getWidget (), "in-flow index: %d", + getInFlowIndex ()); + Textblock *textblock = (Textblock*)getWidget(); - int index1 = index, index2 = index; + int index = getInFlowIndex (), index1 = index, index2 = index; if (textblock->hlStart[layer].index > textblock->hlEnd[layer].index) return; @@ -264,26 +163,33 @@ void Textblock::TextblockIterator::unhighlight (int direction, textblock->hlEnd[layer].nChar = INT_MAX; } + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "index", + textblock->hlStart[layer].index); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlStart", layer, "nChar", + textblock->hlStart[layer].nChar); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "index", + textblock->hlEnd[layer].index); + DBG_OBJ_ARRATTRSET_NUM_O (textblock, "hlEnd", layer, "nChar", + textblock->hlEnd[layer].nChar); + if (oldStartIndex != textblock->hlStart[layer].index || oldStartChar != textblock->hlStart[layer].nChar || oldEndIndex != textblock->hlEnd[layer].index || oldEndChar != textblock->hlEnd[layer].nChar) textblock->queueDrawRange (index1, index2); - } + } else + unhighlightOOF (direction, layer); - // TODO What about OOF widgets? + DBG_OBJ_LEAVE_O (getWidget ()); } void Textblock::TextblockIterator::getAllocation (int start, int end, core::Allocation *allocation) { - Textblock *textblock = (Textblock*)getWidget(); + if (inFlow ()) { + Textblock *textblock = (Textblock*)getWidget(); - if (oofm) { - // TODO Consider start and end? - *allocation = - *(textblock->outOfFlowMgr->getWidget(index)->getAllocation()); - } else { + int index = getInFlowIndex (); Word *word = textblock->words->getRef (index); int firstWordOfLine, textOffset, lineYOffsetCanvas, lineBorderAscent; @@ -360,14 +266,19 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, } allocation->ascent = word->size.ascent; allocation->descent = word->size.descent; - } + } else + getAllocationOOF (start, end, allocation); } -void Textblock::TextblockIterator::print () +int Textblock::TextblockIterator::numContentsInFlow () { - Iterator::print (); - printf (", oofm = %s, index = %d", oofm ? "true" : "false", index); + return ((Textblock*)getWidget())->words->size (); +} +void Textblock::TextblockIterator::getContentInFlow (int index, + core::Content *content) +{ + *content = ((Textblock*)getWidget())->words->getRef(index)->content; } } // namespace dw diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 66391952..f9ec1ecd 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -583,7 +583,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); @@ -746,14 +746,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); @@ -764,10 +765,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, @@ -833,8 +841,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); @@ -846,6 +853,29 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll) return diffWords; } +int Textblock::wrapWordOofRef (int wordIndex, bool wrapAll) +{ + DBG_OBJ_ENTER ("construct.word", 0, "wrapWordOofRef", "%d, %s", + wordIndex, wrapAll ? "true" : "false"); + + Word *word = words->getRef (wordIndex); + Widget *widget = word->content.widget; + int yNewLine = yOffsetOfLineToBeCreated (); + + // Floats, which affect either border, are handled in wrapWordInFlow; this + // is rather for positioned elements. + oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (getWidgetOOFIndex (widget)); + DBG_OBJ_MSGF ("construct.word", 1, "parentRef = %d, oofm = %p", + widget->parentRef, oofm); + if (oofm && !oofm->mayAffectBordersAtAll ()) + // TODO Again, "x" is not correct (see above). + oofm->tellPosition (widget, boxOffsetX (), yNewLine); + + DBG_OBJ_LEAVE (); + + return 0; // Words list not changed. +} + // *height must be initialized, but not *breakPos. // *wordIndexEnd must be initialized (initially to wordIndex) void Textblock::balanceBreakPosAndHeight (int wordIndex, int firstIndex, @@ -1427,8 +1457,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); @@ -1500,8 +1531,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex) borderDescent = marginDescent - word->content.widget->getStyle()->margin.bottom; - word->content.widget->parentRef = - OutOfFlowMgr::createRefNormalFlow (lineIndex); + word->content.widget->parentRef = makeParentRefInFlow (lineIndex); } else { borderAscent = marginAscent = word->size.ascent; borderDescent = marginDescent = word->size.descent; @@ -1625,8 +1655,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; @@ -1638,8 +1667,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); @@ -1913,17 +1942,6 @@ void Textblock::initNewLine () { DBG_OBJ_ENTER0 ("construct.line", 0, "initNewLine"); - // At the very beginning, in Textblock::Textblock, where this - // method is called, containingBlock is not yet defined. - - if (containingBlock && containingBlock->outOfFlowMgr) { - if (lines->size () == 0) { - int clearPosition = - containingBlock->outOfFlowMgr->getClearPosition (this); - setVerticalOffset (misc::max (clearPosition, 0)); - } - } - calcBorders (lines->size() > 0 ? lines->getLastRef()->lastOofRefPositionedBeforeThisLine : -1, 1); @@ -1941,81 +1959,97 @@ void Textblock::calcBorders (int lastOofRef, int height) DBG_OBJ_ENTER ("construct.line", 0, "calcBorders", "%d, %d", lastOofRef, height); - if (containingBlock && containingBlock->outOfFlowMgr) { - // Consider the example: - // - // <div> - // Some text A ... - // <p> Some text B ... <img style="float:right" ...> </p> - // Some more text C ... - // </div> - // - // If the image is large enough, it should float around the last - // paragraph, "Some more text C ...": - // - // Some more text A ... - // - // Some more ,---------. - // text B ... | | - // | <img> | - // Some more | | <---- Consider this line! - // text C ... '---------' - // - // Since this float is generated in the <p> element, not in the- - // <div> element, and since they are represented by different - // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine, - // and so lastOofRef, is -1 for the line marked with an arrow; - // this would result in ignoring the float, because -1 is - // equivalent to the very beginning of the <div> element ("Some - // more text A ..."), which is not affected by the float. - // - // On the other hand, the only relevant values of - // Line::lastOofRefPositionedBeforeThisLine are those greater - // than the first word of the new line, so a solution is to use - // the maximum of both. + newLineHasFloatLeft = newLineHasFloatRight = false; + newLineLeftBorder = newLineRightBorder = 0; + newLineLeftFloatHeight = newLineRightFloatHeight = 0; + bool oofmDefined = false; + for (int i = 0; i < NUM_OOFM && !oofmDefined; i++) + if (searchOutOfFlowMgr(i)) + oofmDefined = true; - int firstWordOfLine = lines->size() > 0 ? - lines->getLastRef()->lastWord + 1 : 0; + if (oofmDefined) { + int firstWordOfLine = + lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0; int effOofRef = misc::max (lastOofRef, firstWordOfLine - 1); - int y = yOffsetOfLineToBeCreated (); - - newLineHasFloatLeft = - containingBlock->outOfFlowMgr->hasFloatLeft (this, y, height, this, - effOofRef); - newLineHasFloatRight = - containingBlock->outOfFlowMgr->hasFloatRight (this, y, height, this, - effOofRef); - newLineLeftBorder = - containingBlock->outOfFlowMgr->getLeftBorder (this, y, height, this, - effOofRef); - newLineRightBorder = - containingBlock->outOfFlowMgr->getRightBorder (this, y, height, this, - effOofRef); - newLineLeftFloatHeight = newLineHasFloatLeft ? - containingBlock->outOfFlowMgr->getLeftFloatHeight (this, y, height, - this, effOofRef) : - 0; - newLineRightFloatHeight = newLineHasFloatRight ? - containingBlock->outOfFlowMgr->getRightFloatHeight (this, y, height, - this, effOofRef) : - 0; - - DBG_OBJ_MSGF ("construct.line", 1, - "%d * %d (%s) / %d * %d (%s), at %d (%d), until %d = " - "max (%d, %d - 1)", - newLineLeftBorder, newLineLeftFloatHeight, - newLineHasFloatLeft ? "true" : "false", - newLineRightBorder, newLineRightFloatHeight, - newLineHasFloatRight ? "true" : "false", - y, height, effOofRef, lastOofRef, firstWordOfLine); - } else { - newLineHasFloatLeft = newLineHasFloatRight = false; - newLineLeftBorder = newLineRightBorder = 0; - newLineLeftFloatHeight = newLineRightFloatHeight = 0; - - DBG_OBJ_MSG ("construct.line", 0, "<i>no CB of OOFM</i>"); + + for (int i = 0; i < NUM_OOFM; i++) { + oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr(i); + if (oofm) { + // Consider the example: + // + // <div> + // Some text A ... + // <p> Some text B ... <img style="float:right" ...> </p> + // Some more text C ... + // </div> + // + // If the image is large enough, it should float around the last + // paragraph, "Some more text C ...": + // + // Some more text A ... + // + // Some more ,---------. + // text B ... | | + // | <img> | + // Some more | | <---- Consider this line! + // text C ... '---------' + // + // Since this float is generated in the <p> element, not in the- + // <div> element, and since they are represented by different + // instances of dw::Textblock, lastOofRefPositionedBeforeThisLine, + // and so lastOofRef, is -1 for the line marked with an arrow; + // this would result in ignoring the float, because -1 is + // equivalent to the very beginning of the <div> element ("Some + // more text A ..."), which is not affected by the float. + // + // On the other hand, the only relevant values of + // Line::lastOofRefPositionedBeforeThisLine are those greater + // than the first word of the new line, so a solution is to use + // the maximum of both. + + bool thisHasLeft, thisHasRight; + + thisHasLeft = oofm->hasFloatLeft (this, y, height, this, effOofRef); + newLineHasFloatLeft = newLineHasFloatLeft || thisHasLeft; + thisHasRight = oofm->hasFloatRight (this, y, height, this, + effOofRef); + newLineHasFloatRight = newLineHasFloatRight || thisHasRight; + + newLineLeftBorder = + misc::max (newLineLeftBorder, + oofm->getLeftBorder (this, y, height, this, + effOofRef)); + newLineRightBorder = + misc::max (newLineRightBorder, + oofm->getRightBorder (this, y, height, this, + effOofRef)); + + // TODO "max" is not really correct for the heights. (Does + // not matter, since only one, the float manager, returns + // meaningful values.) + if (thisHasLeft) + newLineLeftFloatHeight = + misc::max (newLineLeftFloatHeight, + oofm->getLeftFloatHeight (this, y, height, this, + effOofRef)); + if (thisHasRight) + newLineRightFloatHeight = + misc::max (newLineRightFloatHeight, + oofm->getRightFloatHeight (this, y, height, this, + effOofRef)); + + DBG_OBJ_MSGF ("construct.line", 1, + "OOFM #%d: %d * %d (%s) / %d * %d (%s), at %d (%d), " + "until %d = max (%d, %d - 1)", + i, newLineLeftBorder, newLineLeftFloatHeight, + newLineHasFloatLeft ? "true" : "false", + newLineRightBorder, newLineRightFloatHeight, + newLineHasFloatRight ? "true" : "false", + y, height, effOofRef, lastOofRef, firstWordOfLine); + } + } } DBG_OBJ_SET_BOOL ("newLineHasFloatLeft", newLineHasFloatLeft); diff --git a/dw/types.hh b/dw/types.hh index 36d6caa1..081b8db4 100644 --- a/dw/types.hh +++ b/dw/types.hh @@ -207,6 +207,10 @@ struct Content WIDGET_OOF_REF = 1 << 5, BREAK = 1 << 6, + /** \brief can be used internally, but should never be exposed, + e. g. by iterators */ + INVALID = 1 << 7, + ALL = 0xff, REAL_CONTENT = 0xff ^ (START | END), SELECTION_CONTENT = TEXT | BREAK, // WIDGET_* must be set additionally @@ -128,7 +128,9 @@ void Embed::setEnabled (bool enabled) resource->setEnabled (enabled); } -void Embed::draw (View *view, Rectangle *area) +void Embed::draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { drawWidgetBox (view, area, false); resource->draw (view, area); @@ -253,7 +253,8 @@ public: void setDisplayed (bool displayed); void setEnabled (bool enabled); - void draw (View *view, Rectangle *area); + void draw (View *view, Rectangle *area, StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); Iterator *iterator (Content::Type mask, bool atEnd); void setStyle (style::Style *style); diff --git a/dw/widget.cc b/dw/widget.cc index 1e7a05d1..9c517f24 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -91,6 +91,8 @@ Widget::Widget () deleteCallbackFunc = NULL; widgetImgRenderer = NULL; + + stackingContextMgr = NULL; } Widget::~Widget () @@ -104,6 +106,9 @@ Widget::~Widget () delete widgetImgRenderer; } + if (stackingContextMgr) + delete stackingContextMgr; + if (style) style->unref (); @@ -125,25 +130,218 @@ Widget::~Widget () */ bool Widget::intersects (Rectangle *area, Rectangle *intersection) { - Rectangle parentArea, childArea; + DBG_OBJ_ENTER ("draw", 0, "intersects", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + bool r; + + if (wasAllocated ()) { + Rectangle parentArea, childArea; + + parentArea = *area; + parentArea.x += parent->allocation.x; + parentArea.y += parent->allocation.y; + + DBG_OBJ_MSGF ("draw", 2, "parentArea: %d, %d, %d * %d", + parentArea.x, parentArea.y, parentArea.width, + parentArea.height); + + childArea.x = allocation.x; + childArea.y = allocation.y; + childArea.width = allocation.width; + childArea.height = getHeight (); + + DBG_OBJ_MSGF ("draw", 2, "childArea: %d, %d, %d * %d", + childArea.x, childArea.y, childArea.width, + childArea.height); + + if (parentArea.intersectsWith (&childArea, intersection)) { + DBG_OBJ_MSGF ("draw", 2, "intersection: %d, %d, %d * %d", + intersection->x, intersection->y, intersection->width, + intersection->height); + + intersection->x -= allocation.x; + intersection->y -= allocation.y; + r = true; + + DBG_OBJ_MSGF ("draw", 1, "=> %d, %d, %d * %d", + intersection->x, intersection->y, intersection->width, + intersection->height); + } else { + r = false; + DBG_OBJ_MSG ("draw", 1, "=> no intersection"); + } + } else { + r = false; + DBG_OBJ_MSG ("draw", 1, "=> not allocated"); + } + + DBG_OBJ_LEAVE (); + return r; +} + +void Widget::drawTotal (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("draw", 0, "drawTotal", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "initial iteratorStack: %s", sb.getChars ()); + } + + Object *si = NULL; + + if (iteratorStack->atRealTop ()) { + si = stackingIterator (false); + if (si) { + iteratorStack->push (si); + } + } else + iteratorStack->forward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "iteratorStack before: %s", + sb.getChars ()); + } + + draw (view, area, iteratorStack, interruptedWidget); + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "iteratorStack after: %s", + sb.getChars ()); + } + + // A value for *interruptedWidget other than NULL indicates a + // widget with a complex drawing process, for which + // stackingIterator() must return something non-NULL, so that the + // interrupted drawing process can be continued. (TODO: Not quite + // correct when forward() was called instead of push().) + + // assert (*interruptedWidget == NULL || si != NULL); + + if (*interruptedWidget == NULL) { + if (si) + iteratorStack->pop (); + } else + iteratorStack->backward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "final iteratorStack: %s", sb.getChars ()); + } + + DBG_OBJ_LEAVE (); +} + +void Widget::drawToplevel (View *view, Rectangle *area) +{ + assert (parent == NULL); + + StackingIteratorStack iteratorStack; + Widget *interruptedWidget = NULL; + drawTotal (view, area, &iteratorStack, &interruptedWidget); + + // Everything should be finished at this point. + assert (interruptedWidget == NULL); +} + +Widget *Widget::getWidgetAtPoint (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + // Suitable for simple widgets, without children. + + if (wasAllocated () && x >= allocation.x && y >= allocation.y && + x <= allocation.x + allocation.width && y <= allocation.y + getHeight ()) + return this; + else + return NULL; +} + +Widget *Widget::getWidgetAtPointTotal (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTotal", "%d, %d", x, y); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "initial iteratorStack: %s", sb.getChars ()); + } + + Object *si = NULL; + + if (iteratorStack->atRealTop ()) { + si = stackingIterator (true); + if (si) { + iteratorStack->push (si); + } + } else + iteratorStack->forward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "iteratorStack before: %s", + sb.getChars ()); + } + + Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget); + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", widget, *interruptedWidget); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "iteratorStack after: %s", + sb.getChars ()); + } - parentArea = *area; - parentArea.x += parent->allocation.x; - parentArea.y += parent->allocation.y; + // See comment in drawTotal(). - childArea.x = allocation.x; - childArea.y = allocation.y; - childArea.width = allocation.width; - childArea.height = getHeight (); + // assert (*interruptedWidget == NULL || si != NULL); - if (parentArea.intersectsWith (&childArea, intersection)) { - intersection->x -= allocation.x; - intersection->y -= allocation.y; - return true; + if (*interruptedWidget == NULL) { + if (si) + iteratorStack->pop (); } else - return false; + iteratorStack->backward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "final iteratorStack: %s", sb.getChars ()); + } + + DBG_OBJ_LEAVE (); + return widget; } +Widget *Widget::getWidgetAtPointToplevel (int x, int y) +{ + assert (parent == NULL); + + StackingIteratorStack iteratorStack; + Widget *interruptedWidget = NULL; + Widget *widget = + getWidgetAtPointTotal (x, y, &iteratorStack, &interruptedWidget); + + // Everything should be finished at this point. + assert (interruptedWidget == NULL); + + return widget; +} + + void Widget::setParent (Widget *parent) { this->parent = parent; @@ -170,6 +368,18 @@ void Widget::setParent (Widget *parent) // Textblock. DBG_OBJ_SET_PTR ("container", container); + // If at all, stackingContextMgr should have set *before*, see also + // Widget::setStyle() and Layout::addWidget(). + if (stackingContextMgr) { + Widget *stackingContextWidget = parent; + while (stackingContextWidget && + stackingContextWidget->stackingContextMgr == NULL) + stackingContextWidget = stackingContextWidget->parent; + assert (stackingContextWidget); + stackingContextWidget->stackingContextMgr->addChildSCWidget (this); + } else + stackingContextWidget = parent->stackingContextWidget; + notifySetParent(); } @@ -496,6 +706,7 @@ void Widget::sizeRequest (Requisition *requisition) } if (needsResize ()) { + calcExtraSpace (); /** \todo Check requisition == &(this->requisition) and do what? */ sizeRequestImpl (requisition); this->requisition = *requisition; @@ -622,7 +833,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 @@ -903,6 +1114,8 @@ void Widget::getExtremes (Extremes *extremes) } if (extremesChanged ()) { + calcExtraSpace (); + // For backward compatibility (part 1/2): extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1; @@ -932,6 +1145,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. */ @@ -1075,6 +1306,16 @@ void Widget::setStyle (style::Style *style) layout->updateCursor (); } + // After Layout::addWidget() (as toplevel widget) or Widget::setParent() + // (which also sets layout), changes of the style cannot be considered + // anymore. (Should print a warning?) + if (layout == NULL && + StackingContextMgr::isEstablishingStackingContext (this)) { + stackingContextMgr = new StackingContextMgr (this); + DBG_OBJ_ASSOC_CHILD (stackingContextMgr); + stackingContextWidget = this; + } + if (sizeChanged) queueResize (0, true); else @@ -1183,7 +1424,7 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area, // TODO Handle inverse drawing the same way as in drawWidgetBox? // Maybe this method (drawBox) is anyway obsolete when extraSpace - // is fully supported (as in the "dillo_grows" repository). + // is fully supported (as here, in the "dillo_grows" repository). int xPad, yPad, widthPad, heightPad; getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); @@ -1213,8 +1454,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); @@ -1350,53 +1593,6 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget) return widget1; } - -/** - * \brief Search recursively through widget. - * - * Used by dw::core::Layout:getWidgetAtPoint. - */ -Widget *Widget::getWidgetAtPoint (int x, int y, int level) -{ - Iterator *it; - Widget *childAtPoint; - - //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n", - // 3 * level, "", getClassName (), this, allocation.x, allocation.y, - // allocation.width, allocation.ascent, allocation.descent); - - if (x >= allocation.x && - y >= allocation.y && - x <= allocation.x + allocation.width && - y <= allocation.y + getHeight ()) { - //_MSG ("%*s -> inside\n", 3 * level, ""); - /* - * Iterate over the children of this widget. Test recursively, whether - * the point is within the child (or one of its children...). If there - * is such a child, it is returned. Otherwise, this widget is returned. - */ - childAtPoint = NULL; - it = iterator ((Content::Type) - (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT), - false); - - while (childAtPoint == NULL && it->next ()) { - Widget *child = it->getContent()->widget; - if (child->wasAllocated ()) - childAtPoint = child->getWidgetAtPoint (x, y, level + 1); - } - - it->unref (); - - if (childAtPoint) - return childAtPoint; - else - return this; - } else - return NULL; -} - - void Widget::scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height) { @@ -1404,6 +1600,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). * @@ -1413,18 +1627,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) { } @@ -1737,6 +1964,11 @@ void Widget::leaveNotifyImpl (EventCrossing *) tooltip->onLeave(); } +lout::object::Object *Widget::stackingIterator (bool atEnd) +{ + return NULL; +} + void Widget::removeChild (Widget *child) { // Should be implemented. diff --git a/dw/widget.hh b/dw/widget.hh index 0f3e2d37..1a1bf41e 100644 --- a/dw/widget.hh +++ b/dw/widget.hh @@ -180,19 +180,36 @@ protected: Allocation allocation; inline int getHeight () { return allocation.ascent + allocation.descent; } - inline int getContentWidth() { return allocation.width - - style->boxDiffWidth (); } - inline int getContentHeight() { return getHeight () - - style->boxDiffHeight (); } + inline int getContentWidth() { return allocation.width - boxDiffWidth (); } + inline int getContentHeight() { return getHeight () - boxDiffHeight (); } Layout *layout; /** * \brief Space around the margin box. Allocation is extraSpace + - * margin + border + padding + contents; + * margin + border + padding + contents. + * + * See also dw::core::Widget::calcExtraSpace and + * dw::core::Widget::calcExtraSpaceImpl. Also, it is feasible to + * correct this value within dw::core::Widget::sizeRequestImpl. */ style::Box extraSpace; + /** + * \brief Set iff this widget constitutes a stacking context, as defined by + * CSS. + */ + StackingContextMgr *stackingContextMgr; + + /** + * \brief The bottom-most ancestor (or this) for which stackingContextMgr is + * set. + */ + Widget *stackingContextWidget; + + inline StackingContextMgr *getNextStackingContextMgr () + { return stackingContextWidget->stackingContextMgr; } + /*inline void printFlags () { DBG_IF_RTFL { char buf[10 * 3 - 1 + 1]; @@ -254,7 +271,6 @@ protected: inline void unsetFlags (Flags f) { flags = (Flags)(flags & ~f); printFlag (f); } - inline void queueDraw () { queueDrawArea (0, 0, allocation.width, getHeight()); } void queueDrawArea (int x, int y, int width, int height); @@ -271,6 +287,8 @@ protected: */ virtual void getExtremesImpl (Extremes *extremes) = 0; + virtual void calcExtraSpaceImpl (); + /** * \brief See \ref dw-widget-sizes. */ @@ -292,8 +310,6 @@ protected: */ virtual void markExtremesChange (int ref); - int getMinWidth (Extremes *extremes, bool forceValue); - virtual int getAvailWidthOfChild (Widget *child, bool forceValue); virtual int getAvailHeightOfChild (Widget *child, bool forceValue); virtual void correctRequisitionOfChild (Widget *child, @@ -425,6 +441,8 @@ public: void getExtremes (Extremes *extremes); void sizeAllocate (Allocation *allocation); + void calcExtraSpace (); + int getAvailWidth (bool forceValue); int getAvailHeight (bool forceValue); virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; } @@ -441,6 +459,8 @@ public: virtual int applyPerWidth (int containerWidth, style::Length perWidth); virtual int applyPerHeight (int containerHeight, style::Length perHeight); + int getMinWidth (Extremes *extremes, bool forceValue); + virtual bool isBlockLevel (); virtual bool isPossibleContainer (); @@ -449,7 +469,21 @@ public: bool intersects (Rectangle *area, Rectangle *intersection); /** Area is given in widget coordinates. */ - virtual void draw (View *view, Rectangle *area) = 0; + virtual void draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) = 0; + void drawTotal (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + void drawToplevel (View *view, Rectangle *area); + + virtual Widget *getWidgetAtPoint (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + Widget *getWidgetAtPointTotal (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); + Widget *getWidgetAtPointToplevel (int x, int y); bool buttonPress (EventButton *event); bool buttonRelease (EventButton *event); @@ -480,11 +514,11 @@ public: inline Layout *getLayout () { return layout; } - virtual Widget *getWidgetAtPoint (int x, int y, int level); - void scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height); + void getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar); + void getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor); void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad); /** @@ -501,6 +535,14 @@ public: * dw::core::Iterator::prev in this case. */ virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0; + + /** + * \brief ... + * + * May return NULL. + */ + virtual lout::object::Object *stackingIterator (bool atEnd); + virtual void removeChild (Widget *child); }; diff --git a/lout/debug.hh b/lout/debug.hh index 896564cf..5c0169e3 100644 --- a/lout/debug.hh +++ b/lout/debug.hh @@ -29,351 +29,7 @@ # define DEBUG_MSG(level, ...) # endif /* DEBUG_LEVEL */ - - -/* - * See <http://home.gna.org/rtfl/>. - */ - -#ifdef DBG_RTFL - -#include <unistd.h> -#include <stdio.h> - -#define DBG_IF_RTFL if(1) - -// "\n" at the beginning just in case that the previous line is not finished -// yet. -#define RTFL_PREFIX_FMT "\n[rtfl]%s:%d:%d:" -#define RTFL_PREFIX_ARGS CUR_WORKING_DIR "/" __FILE__, __LINE__, getpid() - -#define DBG_OBJ_MSG(aspect, prio, msg) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \ - RTFL_PREFIX_ARGS, this, aspect, prio, msg); \ - fflush (stdout); \ - } D_STMT_END - -// Variant which does not use "this", but an explicitly passed -// object. Should be applied to other macros. (Also, for use in C.) -#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \ - RTFL_PREFIX_ARGS, obj, aspect, prio, msg); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \ - RTFL_PREFIX_ARGS, this, aspect, prio, __VA_ARGS__); \ - fflush (stdout); \ - } D_STMT_END - -// See DBG_OBJ_MSG_O. -#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \ - RTFL_PREFIX_ARGS, obj, aspect, prio, __VA_ARGS__); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_MSG_START() \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \ - RTFL_PREFIX_ARGS, this); \ - fflush (stdout); \ - } D_STMT_END - -// See DBG_OBJ_MSG_O. -#define DBG_OBJ_MSG_START_O(obj) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \ - RTFL_PREFIX_ARGS, obj); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_MSG_END() \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \ - RTFL_PREFIX_ARGS, this); \ - fflush (stdout); \ - } D_STMT_END - -// See DBG_OBJ_MSG_O. -#define DBG_OBJ_MSG_END_O(obj) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \ - RTFL_PREFIX_ARGS, obj); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ENTER0(aspect, prio, funname) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \ - RTFL_PREFIX_ARGS, this, aspect, prio, funname); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \ - RTFL_PREFIX_ARGS, obj, aspect, prio, funname); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \ - D_STMT_START { \ - fflush (stdout); \ - printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \ - RTFL_PREFIX_ARGS, this, aspect, prio, funname, __VA_ARGS__); \ - } D_STMT_END - -#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \ - D_STMT_START { \ - fflush (stdout); \ - printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \ - RTFL_PREFIX_ARGS, obj, aspect, prio, funname, __VA_ARGS__); \ - } D_STMT_END - -#define DBG_OBJ_LEAVE() \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \ - RTFL_PREFIX_ARGS, this); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_LEAVE_O(obj) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \ - RTFL_PREFIX_ARGS, obj); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_CREATE(klass) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-create:%p:%s\n", \ - RTFL_PREFIX_ARGS, this, klass); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_DELETE() \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-delete:%p\n", \ - RTFL_PREFIX_ARGS, this); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_BASECLASS(klass) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-ident:%p:%p\n", \ - RTFL_PREFIX_ARGS, this, (klass*)this); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ASSOC(parent, child) \ - D_STMT_START { \ - if (child) { \ - printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \ - RTFL_PREFIX_ARGS, parent, child); \ - fflush (stdout); \ - } \ - } D_STMT_END - -#define DBG_OBJ_ASSOC_PARENT(parent) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \ - RTFL_PREFIX_ARGS, parent, this); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ASSOC_CHILD(child) \ - D_STMT_START { \ - if (child) { \ - printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \ - RTFL_PREFIX_ARGS, this, child); \ - fflush (stdout); \ - } \ - } D_STMT_END - -#define DBG_OBJ_SET_NUM(var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \ - RTFL_PREFIX_ARGS, this, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_NUM_O(obj, var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \ - RTFL_PREFIX_ARGS, obj, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_SYM(var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \ - RTFL_PREFIX_ARGS, this, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_STR(var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:\"%s\"\n", \ - RTFL_PREFIX_ARGS, this, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_PTR(var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \ - RTFL_PREFIX_ARGS, this, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_PTR_O(obj, var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \ - RTFL_PREFIX_ARGS, obj, var, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_BOOL(var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \ - RTFL_PREFIX_ARGS, this, var, val ? "true" : "false"); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_SET_BOOL_O(obj, var, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \ - RTFL_PREFIX_ARGS, obj, var, val ? "true" : "false"); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRSET_NUM(var, ind, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%d\n", \ - RTFL_PREFIX_ARGS, this, var, ind, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRSET_SYM(var, ind, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \ - RTFL_PREFIX_ARGS, this, var, ind, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \ - RTFL_PREFIX_ARGS, this, var, ind, val ? "true" : "false"); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRSET_STR(var, ind, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:\"%s\"\n", \ - RTFL_PREFIX_ARGS, this, var, ind, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRSET_PTR(var, ind, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%p\n", \ - RTFL_PREFIX_ARGS, this, var, ind, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%d\n", \ - RTFL_PREFIX_ARGS, this, var, ind, attr, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \ - RTFL_PREFIX_ARGS, this, var, ind, attr, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \ - RTFL_PREFIX_ARGS, this, var, ind, attr, val ? "true" : "false"); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:\"%s\"\n", \ - RTFL_PREFIX_ARGS, this, var, ind, attr, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%p\n", \ - RTFL_PREFIX_ARGS, this, var, ind, attr, val); \ - fflush (stdout); \ - } D_STMT_END - -#define DBG_OBJ_COLOR(klass, color) \ - D_STMT_START { \ - printf (RTFL_PREFIX_FMT "obj-color:%s:%s\n", \ - RTFL_PREFIX_ARGS, color, klass); \ - fflush (stdout); \ - } D_STMT_END - -#else /* DBG_RTFL */ - -#define DBG_IF_RTFL if(0) - -#define DBG_OBJ_MSG(aspect, prio, msg) D_STMT_NOP -#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) D_STMT_NOP -#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) D_STMT_NOP -#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) D_STMT_NOP -#define DBG_OBJ_MSG_START() D_STMT_NOP -#define DBG_OBJ_MSG_START_O(obj) D_STMT_NOP -#define DBG_OBJ_MSG_END() D_STMT_NOP -#define DBG_OBJ_MSG_END_O(obj) D_STMT_NOP -#define DBG_OBJ_ENTER0(aspect, prio, funname) D_STMT_NOP -#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) D_STMT_NOP -#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) D_STMT_NOP -#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) D_STMT_NOP -#define DBG_OBJ_LEAVE() D_STMT_NOP -#define DBG_OBJ_LEAVE_O(obj) D_STMT_NOP -#define DBG_OBJ_CREATE(klass) D_STMT_NOP -#define DBG_OBJ_DELETE() D_STMT_NOP -#define DBG_OBJ_BASECLASS(klass) D_STMT_NOP -#define DBG_OBJ_ASSOC_PARENT(parent) D_STMT_NOP -#define DBG_OBJ_ASSOC_CHILD(child) D_STMT_NOP -#define DBG_OBJ_ASSOC(parent, child) D_STMT_NOP -#define DBG_OBJ_SET_NUM(var, val) D_STMT_NOP -#define DBG_OBJ_SET_NUM_O(obj, var, val) D_STMT_NOP -#define DBG_OBJ_SET_SYM(var, val) D_STMT_NOP -#define DBG_OBJ_SET_STR(var, val) D_STMT_NOP -#define DBG_OBJ_SET_PTR(var, val) D_STMT_NOP -#define DBG_OBJ_SET_PTR_O(obj, var, val) D_STMT_NOP -#define DBG_OBJ_SET_BOOL(var, val) D_STMT_NOP -#define DBG_OBJ_SET_BOOL_O(obj, var, val) D_STMT_NOP -#define DBG_OBJ_ARRSET_NUM(var, ind, val) D_STMT_NOP -#define DBG_OBJ_ARRSET_SYM(var, ind, val) D_STMT_NOP -#define DBG_OBJ_ARRSET_STR(var, ind, val) D_STMT_NOP -#define DBG_OBJ_ARRSET_PTR(var, ind, val) D_STMT_NOP -#define DBG_OBJ_ARRSET_BOOL(var, ind, val) D_STMT_NOP -#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) D_STMT_NOP -#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) D_STMT_NOP -#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) D_STMT_NOP -#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) D_STMT_NOP -#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) D_STMT_NOP -#define DBG_OBJ_COLOR(klass, color) D_STMT_NOP - -#endif /* DBG_RTFL */ +#include "debug_rtfl.hh" #endif /* __LOUT_DEBUG_H__ */ diff --git a/lout/debug_rtfl.hh b/lout/debug_rtfl.hh new file mode 100644 index 00000000..c2ecfd8b --- /dev/null +++ b/lout/debug_rtfl.hh @@ -0,0 +1,340 @@ +// WARNING: This file has been generated. Do not edit! + +/* + * This file is part of RTFL, see <http://home.gna.org/rtfl/> + * for details. + * + * This file (but not RTFL itself) is in the public domain, since it is only a + * simple implementation of a protocol, containing nothing more than trivial + * work. However, it would be nice to keep this notice, along with the URL + * above. + * + * ---------------------------------------------------------------------------- + * + * Defines macros for printing RTFL commands. See documentation for detail + * (online at <http://home.gna.org/rtfl/doc/rtfl.html>). These macros are only + * active, when the pre-processor variable DBG_RTFL is defined. If not, + * alternatives are defined, which have no effect. + * + * This variant assumes that __FILE__ is only the base of the source file name, + * so, to get the full path, CUR_WORKING_DIR has to be defined. See RTFL + * documentation for more details. + */ + +#ifndef __DEBUG_RTFL_HH__ +#define __DEBUG_RTFL_HH__ + +#ifdef DBG_RTFL + +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> + +#define DBG_IF_RTFL if(1) + +#define STMT_START do +#define STMT_END while (0) + +// Prints an RTFL message to stdout. "fmt" contains simple format +// characters how to deal with the additional arguments (no "%" +// preceeding, as in printf), or other characters, which are simply +// printed. No quoting: this function cannot be used to print the +// characters "d", "p", and "s" directly. + +inline void rtfl_print (const char *version, const char *file, int line, + const char *fmt, ...) +{ + // "\n" at the beginning just in case that the previous line is not + // finished yet. + printf ("\n[rtfl-%s]%s:%d:%d:", version, file, line, getpid ()); + + va_list args; + va_start (args, fmt); + + for (int i = 0; fmt[i]; i++) { + int n; + void *p; + char *s; + + switch (fmt[i]) { + case 'd': + n = va_arg(args, int); + printf ("%d", n); + break; + + case 'p': + p = va_arg(args, void*); + printf ("%p", p); + break; + + case 's': + s = va_arg (args, char*); + for (int j = 0; s[j]; j++) { + if (s[j] == ':' || s[j] == '\\') + putchar ('\\'); + putchar (s[j]); + } + break; + + default: + putchar (fmt[i]); + break; + } + } + + va_end (args); + + putchar ('\n'); + fflush (stdout); +} + +#define RTFL_PRINT(version, cmd, fmt, ...) \ + rtfl_print (version, CUR_WORKING_DIR "/" __FILE__, __LINE__, "s:" fmt, \ + cmd, __VA_ARGS__) + +#define RTFL_OBJ_VERSION "1.0" + +#define RTFL_OBJ_PRINT(cmd, fmt, ...) \ + RTFL_PRINT (RTFL_OBJ_VERSION, "obj-" cmd, fmt, __VA_ARGS__) + +#define DBG_OBJ_MSG(aspect, prio, msg) \ + DBG_OBJ_MSG_O (aspect, prio, this, msg) + +#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \ + RTFL_OBJ_PRINT ("msg", "p:s:d:s", obj, aspect, prio, msg) + +#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \ + STMT_START { \ + char msg[256]; \ + snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \ + DBG_OBJ_MSG (aspect, prio, msg); \ + } STMT_END + +#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \ + STMT_START { \ + char msg[256]; \ + snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \ + DBG_OBJ_MSG_O (aspect, prio, obj, msg); \ + } STMT_END + +#define DBG_OBJ_MSG_START() \ + DBG_OBJ_MSG_START_O (this) + +#define DBG_OBJ_MSG_START_O(obj) \ + RTFL_OBJ_PRINT ("msg-start", "p", obj) + +#define DBG_OBJ_MSG_END() \ + DBG_OBJ_MSG_END_O (this) + +#define DBG_OBJ_MSG_END_O(obj) \ + RTFL_OBJ_PRINT ("msg-end", "p", obj) + +#define DBG_OBJ_ENTER0(aspect, prio, funname) \ + DBG_OBJ_ENTER0_O (aspect, prio, this, funname) + +#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \ + RTFL_OBJ_PRINT ("enter", "p:s:d:s:", obj, aspect, prio, funname); + +#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \ + STMT_START { \ + char args[256]; \ + snprintf (args, sizeof (args), fmt, __VA_ARGS__); \ + RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", this, aspect, prio, funname, \ + args); \ + } STMT_END + +#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \ + STMT_START { \ + char args[256]; \ + snprintf (args, sizeof (args), fmt, __VA_ARGS__); \ + RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", obj, aspect, prio, funname, \ + args); \ + } STMT_END + +#define DBG_OBJ_LEAVE() \ + DBG_OBJ_LEAVE_O (this) + +#define DBG_OBJ_LEAVE_O(obj) \ + RTFL_OBJ_PRINT ("leave", "p", obj); + +#define DBG_OBJ_CREATE(klass) \ + DBG_OBJ_CREATE_O (this, klass) + +#define DBG_OBJ_CREATE_O(obj, klass) \ + RTFL_OBJ_PRINT ("create", "p:s", obj, klass); + +#define DBG_OBJ_DELETE() \ + DBG_OBJ_DELETE_O (this) + +#define DBG_OBJ_DELETE_O(obj) \ + RTFL_OBJ_PRINT ("delete", "p", obj); + +#define DBG_OBJ_BASECLASS(klass) \ + RTFL_OBJ_PRINT ("ident", "p:p", this, (klass*)this); + +#define DBG_OBJ_ASSOC(parent, child) \ + RTFL_OBJ_PRINT ("assoc", "p:p", parent, child); \ + +#define DBG_OBJ_ASSOC_PARENT(parent) \ + DBG_OBJ_ASSOC (parent, this); + +#define DBG_OBJ_ASSOC_CHILD(child) \ + DBG_OBJ_ASSOC (this, child); + +#define DBG_OBJ_SET_NUM(var, val) \ + DBG_OBJ_SET_NUM_O (this, var, val) + +#define DBG_OBJ_SET_NUM_O(obj, var, val) \ + RTFL_OBJ_PRINT ("set", "p:s:d", obj, var, val) + +#define DBG_OBJ_SET_SYM(var, val) \ + DBG_OBJ_SET_SYM_O (this, var, val) + +#define DBG_OBJ_SET_SYM_O(obj, var, val) \ + RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, val) + +#define DBG_OBJ_SET_BOOL(var, val) \ + DBG_OBJ_SET_BOOL_O (this, var, val) + +#define DBG_OBJ_SET_BOOL_O(obj, var, val) \ + RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, (val) ? "true" : "false") + +#define DBG_OBJ_SET_STR(var, val) \ + DBG_OBJ_SET_STR_O (this, var, val) + +#define DBG_OBJ_SET_STR_O(obj, var, val) \ + RTFL_OBJ_PRINT ("set", "p:s:\"s\"", obj, var, val) + +#define DBG_OBJ_SET_PTR(var, val) \ + DBG_OBJ_SET_PTR_O (this, var, val) + +#define DBG_OBJ_SET_PTR_O(obj, var, val) \ + RTFL_OBJ_PRINT ("set", "p:s:p", obj, var, val) + +#define DBG_OBJ_ARRSET_NUM(var, ind, val) \ + DBG_OBJ_ARRSET_NUM_O (this, var, ind, val) + +#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d:d", obj, var, ind, val) + +#define DBG_OBJ_ARRSET_SYM(var, ind, val) \ + DBG_OBJ_ARRSET_SYM_O (this, var, ind, val) + +#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, val) + +#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \ + DBG_OBJ_ARRSET_BOOL_O (this, var, ind, val) + +#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, (val) ? "true" : "false") + +#define DBG_OBJ_ARRSET_STR(var, ind, val) \ + DBG_OBJ_ARRSET_STR_O (this, var, ind, val) + +#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d:\"s\"", obj, var, ind, val) + +#define DBG_OBJ_ARRSET_PTR(var, ind, val) \ + DBG_OBJ_ARRSET_PTR_O (this, var, ind, val) + +#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d:p", obj, var, ind, val) + +#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \ + DBG_OBJ_ARRATTRSET_NUM_O (this, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d.s:d", obj, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \ + DBG_OBJ_ARRATTRSET_SYM_O (this, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \ + DBG_OBJ_ARRATTRSET_BOOL_O (this, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, \ + (val) ? "true" : "false") + +#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \ + DBG_OBJ_ARRATTRSET_STR_O (this, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d.s:\"s\"", obj, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \ + DBG_OBJ_ARRATTRSET_PTR_O (this, var, ind, attr, val) + +#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) \ + RTFL_OBJ_PRINT ("set", "p:s.d.s:p", obj, var, ind, attr, val) + +#define DBG_OBJ_CLASS_COLOR(klass, color) \ + RTFL_OBJ_PRINT ("class-color", "s:s", klass, color) + +#else /* DBG_RTFL */ + +#define STMT_NOP do { } while (0) + +#define DBG_IF_RTFL if(0) + +#define DBG_OBJ_MSG(aspect, prio, msg) STMT_NOP +#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) STMT_NOP +#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) STMT_NOP +#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) STMT_NOP +#define DBG_OBJ_MSG_START() STMT_NOP +#define DBG_OBJ_MSG_START_O(obj) STMT_NOP +#define DBG_OBJ_MSG_END() STMT_NOP +#define DBG_OBJ_MSG_END_O(obj) STMT_NOP +#define DBG_OBJ_ENTER0(aspect, prio, funname) STMT_NOP +#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) STMT_NOP +#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) STMT_NOP +#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) STMT_NOP +#define DBG_OBJ_LEAVE() STMT_NOP +#define DBG_OBJ_LEAVE_O(obj) STMT_NOP +#define DBG_OBJ_CREATE(klass) STMT_NOP +#define DBG_OBJ_CREATE_O(obj, klass) STMT_NOP +#define DBG_OBJ_DELETE() STMT_NOP +#define DBG_OBJ_DELETE_O(obj) STMT_NOP +#define DBG_OBJ_BASECLASS(klass) STMT_NOP +#define DBG_OBJ_ASSOC(parent, child) STMT_NOP +#define DBG_OBJ_ASSOC_PARENT(parent) STMT_NOP +#define DBG_OBJ_ASSOC_CHILD(child) STMT_NOP +#define DBG_OBJ_SET_NUM(var, val) STMT_NOP +#define DBG_OBJ_SET_NUM_O(obj, var, val) STMT_NOP +#define DBG_OBJ_SET_SYM(var, val) STMT_NOP +#define DBG_OBJ_SET_SYM_O(obj, var, val) STMT_NOP +#define DBG_OBJ_SET_BOOL(var, val) STMT_NOP +#define DBG_OBJ_SET_BOOL_O(obj, var, val) STMT_NOP +#define DBG_OBJ_SET_STR(var, val) STMT_NOP +#define DBG_OBJ_SET_STR_O(obj, var, val) STMT_NOP +#define DBG_OBJ_SET_PTR(var, val) STMT_NOP +#define DBG_OBJ_SET_PTR_O(obj, var, val) STMT_NOP +#define DBG_OBJ_ARRSET_NUM(var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_SYM(var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_BOOL(var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_STR(var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_PTR(var, ind, val) STMT_NOP +#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) STMT_NOP +#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) STMT_NOP +#define DBG_OBJ_CLASS_COLOR(klass, color) STMT_NOP + +#endif /* DBG_RTFL */ + +#endif /* __DEBUG_RTFL_HH__ */ diff --git a/src/cssparser.cc b/src/cssparser.cc index 1487a605..57661ff1 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -222,7 +222,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"font-weight", {CSS_TYPE_ENUM, CSS_TYPE_FONT_WEIGHT, CSS_TYPE_UNUSED}, Css_font_weight_enum_vals}, {"height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, - {"left", {CSS_TYPE_UNUSED}, NULL}, + {"left", {CSS_TYPE_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", @@ -277,7 +277,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, {"word-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, Css_word_spacing_enum_vals}, - {"z-index", {CSS_TYPE_UNUSED}, NULL}, + {"z-index", {CSS_TYPE_INTEGER, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, /* These are extensions, for internal used, and never parsed. */ {"x-link", {CSS_TYPE_INTEGER, CSS_TYPE_UNUSED}, NULL}, @@ -793,9 +793,12 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type) return true; break; - case CSS_TYPE_UNUSED: case CSS_TYPE_INTEGER: - /* Not used for parser values. */ + if (ttype == CSS_TK_DECINT) + return true; + break; + + case CSS_TYPE_UNUSED: default: assert(false); break; @@ -1174,12 +1177,18 @@ bool CssParser::parseValue(CssPropertyName prop, } break; + case CSS_TYPE_INTEGER: + if (ttype == CSS_TK_DECINT) { + val->intVal = strtol(tval, NULL, 10); + ret = true; + nextToken(); + } + break; + case CSS_TYPE_UNUSED: /* nothing */ break; - case CSS_TYPE_INTEGER: - /* Not used for parser values. */ default: assert(false); /* not reached */ } diff --git a/src/dillo.cc b/src/dillo.cc index 44a8d754..f4925dd2 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -379,18 +379,18 @@ static DilloUrl *makeStartUrl(char *str, bool local) */ int main(int argc, char **argv) { - DBG_OBJ_COLOR ("dw::*", "#c0ff80"); - DBG_OBJ_COLOR ("dw::fltk::*", "#c0c0ff"); - DBG_OBJ_COLOR ("dw::core::*", "#ffa0a0"); - DBG_OBJ_COLOR ("dw::core::style::*", "#ffe0a0"); - - DBG_OBJ_COLOR ("dw::Image", "#80ffa0"); - DBG_OBJ_COLOR ("dw::Textblock", "#f0ff80"); - DBG_OBJ_COLOR ("dw::OutOfFlowMgr", "#d0ff80"); - DBG_OBJ_COLOR ("dw::AlignedTextblock", "#e0ff80"); - DBG_OBJ_COLOR ("dw::ListItem", "#b0ff80"); - DBG_OBJ_COLOR ("dw::TableCell", "#80ff80"); - DBG_OBJ_COLOR ("dw::Table", "#80ffc0"); + DBG_OBJ_CLASS_COLOR ("dw::*", "#c0ff80"); + DBG_OBJ_CLASS_COLOR ("dw::fltk::*", "#c0c0ff"); + DBG_OBJ_CLASS_COLOR ("dw::core::*", "#ffa0a0"); + DBG_OBJ_CLASS_COLOR ("dw::core::style::*", "#ffe0a0"); + + DBG_OBJ_CLASS_COLOR ("dw::Image", "#80ffa0"); + DBG_OBJ_CLASS_COLOR ("dw::Textblock", "#f0ff80"); + DBG_OBJ_CLASS_COLOR ("dw::OutOfFlowMgr", "#d0ff80"); + DBG_OBJ_CLASS_COLOR ("dw::AlignedTextblock", "#e0ff80"); + DBG_OBJ_CLASS_COLOR ("dw::ListItem", "#b0ff80"); + DBG_OBJ_CLASS_COLOR ("dw::TableCell", "#80ff80"); + DBG_OBJ_CLASS_COLOR ("dw::Table", "#80ffc0"); uint_t opt_id; uint_t options_got = 0; diff --git a/src/styleengine.cc b/src/styleengine.cc index 918e7460..a660b175 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -728,6 +728,12 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, case CSS_PROPERTY_MAX_HEIGHT: computeLength (&attrs->maxHeight, p->value.intVal, attrs->font); break; + case CSS_PROPERTY_Z_INDEX: + if (p->type == CSS_LENGTH_TYPE_AUTO) + attrs->zIndex = dw::core::style::Z_INDEX_AUTO; + else + attrs->zIndex = p->value.intVal; + break; case PROPERTY_X_LINK: attrs->x_link = p->value.intVal; break; diff --git a/test/Makefile.am b/test/Makefile.am index 3b474466..fd3252dc 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -25,6 +25,7 @@ noinst_PROGRAMS = \ dw-resource-test \ dw-ui-test \ containers \ + identity \ shapes \ cookies \ liang \ @@ -191,6 +192,9 @@ shapes_LDADD = \ containers_SOURCES = containers.cc containers_LDADD = $(top_builddir)/lout/liblout.a +identity_SOURCES = identity.cc +identity_LDADD = $(top_builddir)/lout/liblout.a + cookies_SOURCES = cookies.c cookies_LDADD = \ $(top_builddir)/dpip/libDpip.a \ diff --git a/test/dw_simple_container.cc b/test/dw_simple_container.cc index e19511a6..94dec2d5 100644 --- a/test/dw_simple_container.cc +++ b/test/dw_simple_container.cc @@ -27,190 +27,192 @@ using namespace lout::misc; namespace dw { -int SimpleContainer::CLASS_ID = -1; + int SimpleContainer::CLASS_ID = -1; -// ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- -SimpleContainer::SimpleContainerIterator::SimpleContainerIterator + SimpleContainer::SimpleContainerIterator::SimpleContainerIterator (SimpleContainer *simpleContainer, Content::Type mask, bool atEnd) : - Iterator (simpleContainer, mask, atEnd) -{ - content.type = atEnd ? Content::END : Content::START; -} + Iterator (simpleContainer, mask, atEnd) + { + content.type = atEnd ? Content::END : Content::START; + } -lout::object::Object *SimpleContainer::SimpleContainerIterator::clone () -{ - SimpleContainerIterator *sci = - new SimpleContainerIterator ((SimpleContainer*)getWidget(), - getMask(), false); - sci->content = content; - return sci; -} + lout::object::Object *SimpleContainer::SimpleContainerIterator::clone () + { + SimpleContainerIterator *sci = + new SimpleContainerIterator ((SimpleContainer*)getWidget(), + getMask(), false); + sci->content = content; + return sci; + } -int SimpleContainer::SimpleContainerIterator::index () -{ - switch (content.type) { - case Content::START: - return 0; - case Content::WIDGET_IN_FLOW: - return 1; - case Content::END: - return 2; - default: - assertNotReached (); - return 0; + int SimpleContainer::SimpleContainerIterator::index () + { + switch (content.type) { + case Content::START: + return 0; + case Content::WIDGET_IN_FLOW: + return 1; + case Content::END: + return 2; + default: + assertNotReached (); + return 0; + } } -} -int SimpleContainer::SimpleContainerIterator::compareTo + int SimpleContainer::SimpleContainerIterator::compareTo (lout::object::Comparable *other) -{ - return index () - ((SimpleContainerIterator*)other)->index (); -} + { + return index () - ((SimpleContainerIterator*)other)->index (); + } -bool SimpleContainer::SimpleContainerIterator::next () -{ - SimpleContainer *simpleContainer = (SimpleContainer*)getWidget(); + bool SimpleContainer::SimpleContainerIterator::next () + { + SimpleContainer *simpleContainer = (SimpleContainer*)getWidget(); - if (content.type == Content::END) - return false; + if (content.type == Content::END) + return false; - // simple containers only contain widgets: - if ((getMask() & Content::WIDGET_IN_FLOW) == 0) { - content.type = Content::END; - return false; - } + // simple containers only contain widgets: + if ((getMask() & Content::WIDGET_IN_FLOW) == 0) { + content.type = Content::END; + return false; + } - if (content.type == Content::START) { - if (simpleContainer->child != NULL) { - content.type = Content::WIDGET_IN_FLOW; - content.widget = simpleContainer->child; - return true; - } else { + if (content.type == Content::START) { + if (simpleContainer->child != NULL) { + content.type = Content::WIDGET_IN_FLOW; + content.widget = simpleContainer->child; + return true; + } else { + content.type = Content::END; + return false; + } + } else /* if (content.type == Content::WIDGET) */ { content.type = Content::END; return false; } - } else /* if (content.type == Content::WIDGET) */ { - content.type = Content::END; - return false; } -} -bool SimpleContainer::SimpleContainerIterator::prev () -{ - SimpleContainer *simpleContainer = (SimpleContainer*)getWidget(); + bool SimpleContainer::SimpleContainerIterator::prev () + { + SimpleContainer *simpleContainer = (SimpleContainer*)getWidget(); - if (content.type == Content::START) - return false; + if (content.type == Content::START) + return false; - // simple containers only contain widgets: - if ((getMask() & Content::WIDGET_IN_FLOW) == 0) { - content.type = Content::START; - return false; - } + // simple containers only contain widgets: + if ((getMask() & Content::WIDGET_IN_FLOW) == 0) { + content.type = Content::START; + return false; + } - if (content.type == Content::END) { - if (simpleContainer->child != NULL) { - content.type = Content::WIDGET_IN_FLOW; - content.widget = simpleContainer->child; - return true; - } else { + if (content.type == Content::END) { + if (simpleContainer->child != NULL) { + content.type = Content::WIDGET_IN_FLOW; + content.widget = simpleContainer->child; + return true; + } else { + content.type = Content::START; + return false; + } + } else /* if (content.type == Content::WIDGET) */ { content.type = Content::START; return false; } - } else /* if (content.type == Content::WIDGET) */ { - content.type = Content::START; - return false; } -} -void SimpleContainer::SimpleContainerIterator::highlight (int start, - int end, - HighlightLayer layer) -{ - /** todo Needs this an implementation? */ -} + void SimpleContainer::SimpleContainerIterator::highlight (int start, + int end, + HighlightLayer layer) + { + /** todo Needs this an implementation? */ + } -void SimpleContainer::SimpleContainerIterator::unhighlight (int direction, - HighlightLayer - layer) -{ - /** todo Needs this an implementation? */ -} + void SimpleContainer::SimpleContainerIterator::unhighlight (int direction, + HighlightLayer + layer) + { + /** todo Needs this an implementation? */ + } -void SimpleContainer::SimpleContainerIterator::getAllocation (int start, - int end, - Allocation - *allocation) -{ - /** \bug Not implemented. */ -} + void SimpleContainer::SimpleContainerIterator::getAllocation (int start, + int end, + Allocation + *allocation) + { + /** \bug Not implemented. */ + } -// ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- -SimpleContainer::SimpleContainer () -{ - registerName ("dw::SimpleContainer", &CLASS_ID); - child = NULL; -} + SimpleContainer::SimpleContainer () + { + registerName ("dw::SimpleContainer", &CLASS_ID); + child = NULL; + } -SimpleContainer::~SimpleContainer () -{ - if (child) - delete child; -} + SimpleContainer::~SimpleContainer () + { + if (child) + delete child; + } -void SimpleContainer::sizeRequestImpl (Requisition *requisition) -{ - Requisition childReq; - if (child) - child->sizeRequest (&childReq); - else - childReq.width = childReq.ascent = childReq.descent = 0; + void SimpleContainer::sizeRequestImpl (Requisition *requisition) + { + Requisition childReq; + if (child) + child->sizeRequest (&childReq); + else + childReq.width = childReq.ascent = childReq.descent = 0; - requisition->width = childReq.width + boxDiffWidth (); - requisition->ascent = childReq.ascent + boxOffsetY (); - requisition->descent = childReq.descent + boxRestHeight (); + requisition->width = childReq.width + boxDiffWidth (); + requisition->ascent = childReq.ascent + boxOffsetY (); + requisition->descent = childReq.descent + boxRestHeight (); - correctRequisition (requisition, splitHeightPreserveAscent); -} + correctRequisition (requisition, splitHeightPreserveAscent); + } -void SimpleContainer::getExtremesImpl (Extremes *extremes) -{ - Extremes childExtr; - if (child) - child->getExtremes (&childExtr); - else - childExtr.minWidth = childExtr.maxWidth = 0; + void SimpleContainer::getExtremesImpl (Extremes *extremes) + { + Extremes childExtr; + if (child) + child->getExtremes (&childExtr); + else + childExtr.minWidth = childExtr.maxWidth = 0; - extremes->minWidth = childExtr.minWidth + boxDiffWidth (); - extremes->maxWidth = childExtr.maxWidth + boxDiffWidth (); + extremes->minWidth = childExtr.minWidth + boxDiffWidth (); + extremes->maxWidth = childExtr.maxWidth + boxDiffWidth (); - correctExtremes (extremes); -} + correctExtremes (extremes); + } -void SimpleContainer::sizeAllocateImpl (Allocation *allocation) -{ - Allocation childAlloc; - - if (child) { - childAlloc.x = allocation->x + boxOffsetX (); - childAlloc.y = allocation->y + boxOffsetY (); - childAlloc.width = allocation->width - boxDiffWidth (); - childAlloc.ascent = allocation->ascent - boxOffsetY (); - childAlloc.descent = allocation->descent - boxRestHeight (); - child->sizeAllocate (&childAlloc); + void SimpleContainer::sizeAllocateImpl (Allocation *allocation) + { + Allocation childAlloc; + + if (child) { + childAlloc.x = allocation->x + boxOffsetX (); + childAlloc.y = allocation->y + boxOffsetY (); + childAlloc.width = allocation->width - boxDiffWidth (); + childAlloc.ascent = allocation->ascent - boxOffsetY (); + childAlloc.descent = allocation->descent - boxRestHeight (); + child->sizeAllocate (&childAlloc); + } } -} -void SimpleContainer::draw (View *view, Rectangle *area) +void SimpleContainer::draw (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) { drawWidgetBox (view, area, false); Rectangle childArea; if (child && child->intersects (area, &childArea)) - child->draw (view, &childArea); + child->drawTotal (view, &childArea, iteratorStack, interruptedWidget); } Iterator *SimpleContainer::iterator (Content::Type mask, bool atEnd) diff --git a/test/dw_simple_container.hh b/test/dw_simple_container.hh index bb1a37af..9f3b2ca6 100644 --- a/test/dw_simple_container.hh +++ b/test/dw_simple_container.hh @@ -44,7 +44,9 @@ public: SimpleContainer (); ~SimpleContainer (); - void draw (core::View *view, core::Rectangle *area); + void draw (core::View *view, core::Rectangle *area, + core::StackingIteratorStack *iteratorStack, + Widget **interruptedWidget); core::Iterator *iterator (core::Content::Type mask, bool atEnd); void removeChild (Widget *child); diff --git a/test/identity.cc b/test/identity.cc new file mode 100644 index 00000000..a1a136eb --- /dev/null +++ b/test/identity.cc @@ -0,0 +1,55 @@ +/* + * This small program tests how IdentifiableObject works with multiple + * inheritance ("diamond" inheritance, more precisely, since all + * classes have there root in IdentifiableObject.) + * + * Current status: With virtual superclasses, you get a class + * hierarchie "root -> A -> B -> C", so that the first part of this + * example works actually (C is a subclass of A and of B), but the + * second fails (it should print "false", but it is erroneously + * assumed that B is a subclass of A.) + */ + +#include "../lout/identity.hh" + +using namespace lout::identity; + +class A: virtual public IdentifiableObject +{ +public: + static int CLASS_ID; + inline A () { registerName ("A", &CLASS_ID); } +}; + +class B: virtual public IdentifiableObject +{ +public: + static int CLASS_ID; + inline B () { registerName ("B", &CLASS_ID); } +}; + +class C: public A, public B +{ +public: + static int CLASS_ID; + inline C () { registerName ("C", &CLASS_ID); } +}; + +int A::CLASS_ID = -1, B::CLASS_ID = -1, C::CLASS_ID = -1; + +int main (int argc, char *argv[]) +{ + printf ("A: %d, B: %d, C: %d\n", A::CLASS_ID, B::CLASS_ID, C::CLASS_ID); + + C x; + assert (x.instanceOf (A::CLASS_ID)); + assert (x.instanceOf (B::CLASS_ID)); + assert (x.instanceOf (C::CLASS_ID)); + printf ("x: %d\n", x.getClassId ()); + + B y; + printf ("y: %d; instance of A: %s\n", + y.getClassId (), y.instanceOf (B::CLASS_ID) ? "true" : "false"); + + return 0; +} |