aboutsummaryrefslogtreecommitdiff
path: root/dw/outofflowmgr.hh
diff options
context:
space:
mode:
Diffstat (limited to 'dw/outofflowmgr.hh')
-rw-r--r--dw/outofflowmgr.hh429
1 files changed, 429 insertions, 0 deletions
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
new file mode 100644
index 00000000..c5c560c7
--- /dev/null
+++ b/dw/outofflowmgr.hh
@@ -0,0 +1,429 @@
+#ifndef __DW_OUTOFFLOWMGR_HH__
+#define __DW_OUTOFFLOWMGR_HH__
+
+#include "core.hh"
+
+namespace dw {
+
+class Textblock;
+
+/**
+ * \brief Represents additional data for containing blocks.
+ */
+class OutOfFlowMgr
+{
+ friend class WidgetInfo;
+
+private:
+ enum Side { LEFT, RIGHT };
+
+ Textblock *containingBlock;
+
+ // These two values are set by sizeAllocateStart(), and they are
+ // accessable also within sizeAllocateEnd(), and also for the
+ // containing block, for which allocation and WAS_ALLOCATED is set
+ // *after* sizeAllocateEnd(). See the two inline functions
+ // wasAllocated(Widget*) and getAllocation(Widget*) (further down)
+ // for usage.
+ core::Allocation containingBlockAllocation;
+ bool containingBlockWasAllocated;
+
+ 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; }
+
+ inline bool isNowAllocated () { return widget->wasAllocated (); }
+ inline int getNewXCB () { return widget->getAllocation()->x -
+ oofm->containingBlockAllocation.x; }
+ inline int getNewYCB () { return widget->getAllocation()->y -
+ oofm->containingBlockAllocation.y; }
+ inline int getNewWidth () { return widget->getAllocation()->width; }
+ inline int getNewHeight () { return widget->getAllocation()->ascent +
+ widget->getAllocation()->descent; }
+
+ void update (bool wasAllocated, int xCB, int yCB, int width, int height);
+ void updateAllocation ();
+
+ inline core::Widget *getWidget () { return widget; }
+ };
+
+ class Float: public WidgetInfo
+ {
+ public:
+ class ComparePosition: public lout::object::Comparator
+ {
+ private:
+ OutOfFlowMgr *oofm;
+ Textblock *refTB;
+
+ public:
+ ComparePosition (OutOfFlowMgr *oofm, Textblock *refTB)
+ { this->oofm = oofm; this->refTB = refTB; }
+ 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;
+
+ public:
+ CompareGBAndExtIndex (OutOfFlowMgr *oofm) { this->oofm = oofm; }
+ int compare(Object *o1, Object *o2);
+ };
+
+ Textblock *generatingBlock;
+ int externalIndex;
+ int yReq, yReal; // relative to generator, not container
+ int index; /* When GB is not yet allocated: position
+ within TBInfo::leftFloatsGB or
+ TBInfo::rightFloatsGB, respectively. When GB
+ is allocated: position within leftFloatsCB
+ or rightFloatsCB, respectively, even when
+ the floats are still elements of
+ TBInfo::*FloatsGB. */
+ int sideSpanningIndex, mark;
+ core::Requisition size;
+ int cbAvailWidth; /* On which the calculation of relative sizes
+ is based. Height not yet used, and probably
+ not added before size redesign. */
+ bool dirty, sizeChangedSinceLastAllocation;
+ bool inCBList; /* Neccessary to prevent floats from being moved
+ twice from GB to CB list. */
+
+ Float (OutOfFlowMgr *oofm, core::Widget *widget,
+ Textblock *generatingBlock, int externalIndex);
+
+ 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:
+ enum Type { GB, CB } type;
+
+ private:
+ OutOfFlowMgr *oofm;
+ Side side;
+
+ public:
+ inline SortedFloatsVector (OutOfFlowMgr *oofm, Side side, Type 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 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 availWidth;
+ int index; // position within "tbInfos"
+
+ TBInfo *parent;
+ int parentExtIndex;
+
+ // 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 Textblock *getTextblock () { return (Textblock*)getWidget (); }
+ };
+
+ class AbsolutelyPositioned: public lout::object::Object
+ {
+ public:
+ core::Widget *widget;
+ int xCB, yCB; // relative to the containing block
+ int width, height;
+ bool dirty;
+
+ AbsolutelyPositioned (OutOfFlowMgr *oofm, core::Widget *widget,
+ Textblock *generatingBlock, int externalIndex);
+ };
+
+ // These two lists store all floats, in the order in which they are
+ // defined. Only used for iterators.
+ lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll;
+
+ // These two lists store all floats whose generators are already
+ // allocated.
+ SortedFloatsVector *leftFloatsCB, *rightFloatsCB;
+
+ lout::container::typed::HashTable<lout::object::TypedPointer
+ <dw::core::Widget>, Float> *floatsByWidget;
+
+ lout::container::typed::Vector<TBInfo> *tbInfos;
+ lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>,
+ TBInfo> *tbInfosByTextblock;
+
+ lout::container::typed::Vector<AbsolutelyPositioned> *absolutelyPositioned;
+
+ int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark;
+
+ /**
+ * Variant of Widget::wasAllocated(), which can also be used within
+ * OOFM::sizeAllocateEnd(), and also for the generating block.
+ */
+ inline bool wasAllocated (core::Widget *widget) {
+ return widget->wasAllocated () ||
+ (widget == (core::Widget*)containingBlock &&
+ containingBlockWasAllocated); }
+
+ /**
+ * Variant of Widget::getAllocation(), which can also be used
+ * within OOFM::sizeAllocateEnd(), and also for the generating
+ * block.
+ */
+ inline core::Allocation *getAllocation (core::Widget *widget) {
+ return widget == (core::Widget*)containingBlock ?
+ &containingBlockAllocation : widget->getAllocation (); }
+
+ void moveExternalIndices (SortedFloatsVector *list, int oldStartIndex,
+ int diff);
+ Float *findFloatByWidget (core::Widget *widget);
+
+ void moveFromGBToCB (Side side);
+ void sizeAllocateFloats (Side side);
+ int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
+ int gbAvailWidth);
+
+ 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);
+
+ bool doFloatsExceedCB (Side side);
+ bool haveExtremesChanged (Side side);
+
+ void drawFloats (SortedFloatsVector *list, core::View *view,
+ core::Rectangle *area);
+ void drawAbsolutelyPositioned (core::View *view, core::Rectangle *area);
+ core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
+ int level);
+ core::Widget *getAbsolutelyPositionedWidgetAtPoint (int x, int y, int level);
+
+ bool collidesV (Float *vloat, Float *other, int *yReal);
+ bool collidesH (Float *vloat, Float *other, int *yReal);
+
+ 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);
+
+ 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 getClearPosition (Textblock *tb, Side side);
+
+ void ensureFloatSize (Float *vloat);
+ int adjustFloatWidth (int width, core::Extremes *extremes);
+
+ void tellFloatPosition (core::Widget *widget, int yReq);
+
+ void getAbsolutelyPositionedSize (core::Requisition *cbReq, int *width,
+ int *height);
+ void getAbsolutelyPositionedExtremes (core::Extremes *cbExtr, int *minWidth,
+ int *maxWidth);
+ void ensureAbsolutelyPositionedSizeAndPosition (AbsolutelyPositioned
+ *abspos);
+ int calcValueForAbsolutelyPositioned (AbsolutelyPositioned *abspos,
+ core::style::Length styleLen,
+ int refLen);
+ void sizeAllocateAbsolutelyPositioned ();
+
+ static inline bool isWidgetFloat (core::Widget *widget)
+ { return widget->getStyle()->vloat != core::style::FLOAT_NONE; }
+ static inline bool isWidgetAbsolutelyPositioned (core::Widget *widget)
+ { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; }
+
+ /*
+ * Format for parent ref (see also below for isRefOutOfFlow,
+ * createRefNormalFlow, and getLineNoFromRef.
+ *
+ * Widget in flow:
+ *
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ * | line number | 0 |
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ *
+ * So, anything with the least signifant bit set to 1 is out of flow.
+ *
+ * Floats:
+ *
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ * | left float index | 0 | 0 | 1 |
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ *
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ * | right float index | 1 | 0 | 1 |
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ *
+ * Absolutely positioned blocks:
+ *
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ * | index | 1 | 1 |
+ * +---+ - - - +---+---+- - - - - -+---+---+---+---+
+ */
+
+ inline static bool isRefFloat (int ref)
+ { return ref != -1 && (ref & 3) == 1; }
+ inline static bool isRefLeftFloat (int ref)
+ { return ref != -1 && (ref & 7) == 1; }
+ inline static bool isRefRightFloat (int ref)
+ { return ref != -1 && (ref & 7) == 5; }
+ inline static bool isRefAbsolutelyPositioned (int ref)
+ { return ref != -1 && (ref & 3) == 3; }
+
+ inline static int createRefLeftFloat (int index)
+ { return (index << 3) | 1; }
+ inline static int createRefRightFloat (int index)
+ { return (index << 3) | 5; }
+ inline static int createRefAbsolutelyPositioned (int index)
+ { return (index << 2) | 3; }
+
+ inline static int getFloatIndexFromRef (int ref)
+ { return ref == -1 ? ref : (ref >> 3); }
+ inline static int getAbsolutelyPositionedIndexFromRef (int ref)
+ { return ref == -1 ? ref : (ref >> 2); }
+
+public:
+ OutOfFlowMgr (Textblock *containingBlock);
+ ~OutOfFlowMgr ();
+
+ void sizeAllocateStart (core::Allocation *containingBlockAllocation);
+ void sizeAllocateEnd ();
+ 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 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); }
+
+ // for iterators
+ inline int getNumWidgets () {
+ return leftFloatsAll->size() + rightFloatsAll->size() +
+ absolutelyPositioned->size(); }
+
+ inline core::Widget *getWidget (int i) {
+ if (i < leftFloatsAll->size())
+ return leftFloatsAll->get(i)->getWidget ();
+ else if (i < leftFloatsAll->size() + rightFloatsAll->size())
+ return rightFloatsAll->get(i - leftFloatsAll->size())->getWidget ();
+ else
+ return absolutelyPositioned->get(i - (leftFloatsAll->size() +
+ rightFloatsAll->size()))->widget;
+ }
+
+ inline bool affectsLeftBorder (core::Widget *widget) {
+ return widget->getStyle()->vloat == core::style::FLOAT_LEFT; }
+ inline bool affectsRightBorder (core::Widget *widget) {
+ return widget->getStyle()->vloat == core::style::FLOAT_RIGHT; }
+};
+
+} // namespace dw
+
+#endif // __DW_OUTOFFLOWMGR_HH__