summaryrefslogtreecommitdiff
path: root/dw/outofflowmgr.hh
blob: 0f07c264ce50d56cf83f3f296afac65f69117d6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#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 isTextblockCoveredByFloat (Float *vloat, Textblock *tb,
                                   int tbx, int tby, int tbWidth, int tbHeight,
                                   int *floatPos);

   void checkChangedFloatSizes ();
   void checkChangedFloatSizes (SortedFloatsVector *list);
   
   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 collides (Float *vloat, Float *other, int *yReal);

   void getFloatsListsAndSide (Float *vloat, SortedFloatsVector **listSame,
                               SortedFloatsVector **listOpp, Side *side);

   void getFloatsSize (SortedFloatsVector *list, Side side, int *width,
                       int *height);
   void accumExtremes (SortedFloatsVector *list, Side side, int *oofMinWidth,
                       int *oofMaxWidth);
   int getMinBorderDiff (Float *vloat, Side side);
   int getMaxBorderDiff (Float *vloat, Side side);

   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);

   void tellFloatPosition (core::Widget *widget, int yReq);

   void getAbsolutelyPositionedSize (int *oofWidthAbsPos, int *oofHeightAbsPos);
   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 (int cbWidth, int cbHeight, int *oofWidth, int *oofHeight);
   void getExtremes (int cbMinWidth, int cbMaxWidth, 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__