aboutsummaryrefslogtreecommitdiff
path: root/dw/oofawarewidget.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/oofawarewidget.cc')
-rw-r--r--dw/oofawarewidget.cc858
1 files changed, 858 insertions, 0 deletions
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
new file mode 100644
index 00000000..6e34b32f
--- /dev/null
+++ b/dw/oofawarewidget.cc
@@ -0,0 +1,858 @@
+/*
+ * 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 {
+
+const char *OOFAwareWidget::OOFM_NAME[NUM_OOFM] = {
+ "FLOATS", "ABSOLUTE", "FIXED"
+};
+
+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;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ 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 ()
+{
+ for (int i = 0; i < NUM_OOFM; i++) {
+ oofContainer[i] = this;
+ DBG_OBJ_ARRSET_PTR ("oofContainer", i, oofContainer[i]);
+ }
+}
+
+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:
+ // We use the toplevel widget as container, i. e. parent widget.
+ // See also OOFPosAbsMgr::isReference for the definition of the
+ // "reference widget".
+ //return widget->getParent() == NULL;
+
+ // The above does not work. Temporary re-enact old behaviour:
+ return widget->instanceOf (OOFAwareWidget::CLASS_ID) &&
+ (widget->getParent() == NULL ||
+ OOFAwareWidget::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*))
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisitionByOOF", "%d * (%d + %d), ...",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofWidth, oofHeight;
+
+ outOfFlowMgr[i]->getSize (requisition, &oofWidth, &oofHeight);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * %d", 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);
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void OOFAwareWidget::correctExtremesByOOF (Extremes *extremes)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremesByOOF", "%d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ for (int i = 0; i < NUM_OOFM; i++) {
+ if (outOfFlowMgr[i]) {
+ DBG_OBJ_MSGF ("resize", 1, "OOFM for %s", OOFM_NAME[i]);
+ DBG_OBJ_MSG_START ();
+
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr[i]->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
+ DBG_OBJ_MSGF ("resize", 1, "result: %d / %d",
+ 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);
+
+ DBG_OBJ_MSGF ("resize", 1, "after correction: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+ DBG_OBJ_MSG_END ();
+ } else
+ DBG_OBJ_MSGF ("resize", 1, "no OOFM for %s", OOFM_NAME[i]);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+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 ("draw", 1,"%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) {
+ DBG_OBJ_MSGF ("draw", 1, "interrupted at %p (parent = %p)",
+ *interruptedWidget, (*interruptedWidget)->getParent ());
+
+ if ((*interruptedWidget)->getParent () == this) {
+ DBG_OBJ_MSG ("draw", 1, "drawing seperately");
+ DBG_OBJ_MSG_START ();
+
+ 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);
+ //if (interruptedWidget2 != NULL)
+ // DBG_OBJ_MSGF ("draw", 0,
+ // "===== Assertion failed: "
+ // "interruptedWidget2 = %p =====",
+ // interruptedWidget2);
+ }
+
+ ((OOFStackingIterator*)iteratorStack->getTop())
+ ->registerWidgetDrawnAfterInterruption (*interruptedWidget);
+
+ // Continue with the current state of "iterator".
+ *interruptedWidget = NULL;
+
+ DBG_OBJ_MSG_END ();
+ }
+ } 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:
+ case OOFStackingIterator::SC_TOP:
+ // See StackingContextMgr: refers to list of z-indices; region
+ // (top or bottom) does not play a role.
+ if (stackingContextMgr)
+ return stackingContextMgr->getNumZIndices () - 1;
+ else
+ return 0;
+
+ case OOFStackingIterator::IN_FLOW:
+ return 0;
+
+ case OOFStackingIterator::OOF_REF:
+ case OOFStackingIterator::OOF_CONT:
+ return NUM_OOFM - 1;
+
+
+ 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