File indexing completed on 2024-04-28 11:39:44

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2003-2004 Leo Savernik <l.savernik@aon.at>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #ifndef KHTML_CARET_P_H
0022 #define KHTML_CARET_P_H
0023 
0024 #include "rendering/render_table.h"
0025 
0026 #define DEBUG_CARETMODE 0
0027 
0028 class QFontMetrics;
0029 
0030 namespace DOM
0031 {
0032 class NodeImpl;
0033 class ElementImpl;
0034 }
0035 
0036 namespace khtml
0037 {
0038 
0039 /** caret advance policy.
0040  *
0041  * Used to determine which elements are taken into account when the caret is
0042  * advanced. Later policies pose refinements of all former
0043  * policies.
0044  * @param LeafsOnly advance from leave render object to leaf render object
0045  *  (It will allow outside flow positions if a flow wouldn't be reachable
0046  *  otherwise).
0047  * @param IndicatedFlows place caret also at the beginning/end of flows
0048  *  that have at least one visible border at any side.
0049  *  (It will allow not indicated flow positions if a flow wouldn't
0050  *  be reachable otherwise).
0051  * @param VisibleFlows place caret also at the beginning/end of any flow
0052  *  that has a renderer.
0053  */
0054 enum CaretAdvancePolicy {
0055     LeafsOnly, IndicatedFlows, VisibleFlows
0056 };
0057 
0058 /** contextual information about the caret which is related to the view.
0059  * An object of this class is only instantiated when it is needed.
0060  */
0061 struct CaretViewContext {
0062     int freqTimerId;        // caret blink frequency timer id
0063     int x, y;           // caret position in viewport coordinates
0064     // (y specifies the top, not the baseline)
0065     int width;          // width of caret in pixels
0066     int height;         // height of caret in pixels
0067     bool visible;       // true if currently visible.
0068     bool displayed;     // true if caret is to be displayed at all.
0069     bool caretMoved;        // set to true once caret has been moved in page
0070     // how to display the caret when view is not focused
0071     KHTMLPart::CaretDisplayPolicy displayNonFocused;
0072 
0073     /** For natural traversal of lines, the original x position is saved, and
0074      * the actual x is set to the first character whose x position is
0075      * greater than origX.
0076      *
0077      * origX is reset to x whenever the caret is moved horizontally or placed
0078      * by the mouse.
0079      */
0080     int origX;
0081 
0082     bool keyReleasePending; // true if keypress under caret mode awaits
0083     // corresponding release event
0084     CaretViewContext() : freqTimerId(-1), x(0), y(0), width(1), height(16),
0085         visible(true), displayed(false), caretMoved(false),
0086         displayNonFocused(KHTMLPart::CaretInvisible), origX(0),
0087         keyReleasePending(false)
0088     {}
0089 };
0090 
0091 class LinearDocument;
0092 
0093 /**
0094  * Stores objects of a certain type, and calls delete on each of them
0095  * when this data structure is destroyed.
0096  *
0097  * As this structure merely consists of a vector of pointers, all objects
0098  * allocated can be traversed as seen fit.
0099  *
0100  * @author Leo Savernik
0101  * @internal
0102  */
0103 template<class T> class MassDeleter : public QVector<T *>
0104 {
0105 public:
0106     MassDeleter(size_t reserved = 1)
0107     {
0108         this->reserve(reserved);
0109     }
0110     ~MassDeleter()
0111     {
0112         typename QVector<T *>::Iterator nd = this->end();
0113         for (typename QVector<T *>::Iterator it = this->begin(); it != nd; ++it) {
0114             delete *it;
0115         }
0116     }
0117 };
0118 
0119 class CaretBoxLine;
0120 
0121 /**
0122  * Represents a rectangular box within which the caret is located.
0123  *
0124  * The caret box serves as a wrapper for inline boxes of all kind. It either
0125  * wraps an InlineBox, InlineTextBox, or InlineFlowBox, or if no such boxes
0126  * exist for a certain context, it contains the relevant information directly.
0127  *
0128  * This class will be constructed whenever a caret position has to be described.
0129  * @author Leo Savernik
0130  * @internal
0131  */
0132 class CaretBox
0133 {
0134 protected:
0135     InlineBox *_box;      // associated inline box if available.
0136     short _w;         // width of box in pixels
0137     int _h;           // height of box in pixels
0138     int _x;           // x coordinate relative to containing block
0139     int _y;           // y coordinate relative to containing block
0140     RenderBox *cb;        // containing block
0141     bool _outside: 1;     // true when representing the outside of the element
0142     bool outside_end: 1;      // at ending outside of element rather than at beginning
0143     // 29 bits unused
0144 
0145 public:
0146     /** empty constructor for later assignment */
0147     CaretBox() {}
0148     /** initializes the caret box from the given inline box */
0149     CaretBox(InlineBox *ibox, bool outside, bool outsideEnd) : _box(ibox),
0150         _w((short)ibox->width()), _h(ibox->height()), _x(ibox->xPos()),
0151         _y(ibox->yPos()), cb(0), _outside(outside), outside_end(outsideEnd)
0152     {
0153         RenderObject *r = ibox->object();
0154         if (r) {
0155             cb = r->containingBlock();
0156         }
0157     }
0158     /** initializes the caret box from scratch */
0159     CaretBox(int x, int y, int w, int h, RenderBox *cb, bool outside, bool outsideEnd) :
0160         _box(0), _w((short)w), _h(h), _x(x), _y(y), cb(cb), _outside(outside),
0161         outside_end(outsideEnd)
0162     {}
0163 
0164     int width() const
0165     {
0166         return _w;
0167     }
0168     int height() const
0169     {
0170         return _h;
0171     }
0172     int xPos() const
0173     {
0174         return _x;
0175     }
0176     int yPos() const
0177     {
0178         return _y;
0179     }
0180     RenderBox *enclosingObject() const
0181     {
0182         return cb;
0183     }
0184     InlineBox *inlineBox() const
0185     {
0186         return _box;
0187     }
0188 
0189     /** returns the containing block of this caret box. If the caret box
0190      * resembles a block itself, its containing block is returned.
0191      */
0192     RenderBlock *containingBlock() const
0193     {
0194         return _box ? static_cast<RenderBlock *>(cb) : cb->containingBlock();
0195     }
0196 
0197     /** returns the replaced render object if this caret box represents one,
0198      * 0 otherwise.
0199      */
0200 
0201     /** returns true if this caret box represents an inline element, or text box,
0202      * otherwise false.
0203      */
0204     bool isInline() const
0205     {
0206         return _box;
0207     }
0208     /** returns true if this caret box represents an inline text box.
0209      */
0210     bool isInlineTextBox() const
0211     {
0212         return _box && _box->isInlineTextBox();
0213     }
0214     /** returns true if this caret box represents a line break
0215      */
0216     bool isLineBreak() const
0217     {
0218         return _box && _box->object() && _box->object()->isBR();
0219     }
0220     /** returns true when this caret box represents an ouside position of an
0221      * element.
0222      */
0223     bool isOutside() const
0224     {
0225         return _outside;
0226     }
0227     /** returns the position at which the outside is targeted at.
0228      *
0229      * This method's return value is meaningless if isOutside() is not true.
0230      * @return true if the outside end is meant, false if the outside beginning
0231      *    is meant.
0232      */
0233     bool isOutsideEnd() const
0234     {
0235         return outside_end;
0236     }
0237     /** returns the associated render object. */
0238     RenderObject *object() const
0239     {
0240         return _box ? _box->object() : cb;
0241     }
0242 
0243     /** returns the minimum offset for this caret box.
0244      */
0245     long minOffset() const
0246     {
0247         return _box && !isLineBreak() ? _box->minOffset() : 0;
0248     }
0249     /** returns the maximum offset for this caret box.
0250      */
0251     long maxOffset() const
0252     {
0253         return _box && !isLineBreak() ? _box->maxOffset() : 0;
0254     }
0255 
0256 #if DEBUG_CARETMODE > 0
0257     void dump(QTextStream &ts, const QString &ind) const;
0258 #endif
0259 
0260     friend class CaretBoxLine;
0261 };
0262 
0263 typedef MassDeleter<CaretBox> CaretBoxDeleter;
0264 
0265 /**
0266  * Iterates over the elements of a caret box line.
0267  *
0268  * @author Leo Savernik
0269  * @internal
0270  */
0271 class CaretBoxIterator
0272 {
0273 protected:
0274     CaretBoxLine *cbl;        // associated caret box line
0275     int index;            // current index
0276 
0277 public:
0278     // Let standard constructor/copy constructor/destructor/assignment operator
0279     // be defined by the compiler. They do exactly what we want.
0280     CaretBoxIterator()
0281         : cbl(0), index(0)
0282     {
0283     }
0284 
0285     bool operator ==(const CaretBoxIterator &it) const
0286     {
0287         return cbl == it.cbl && index == it.index;
0288     }
0289 
0290     bool operator !=(const CaretBoxIterator &it) const
0291     {
0292         return !operator ==(it);
0293     }
0294 
0295     /** returns the current caret box.
0296      * @return current caret box
0297      */
0298     CaretBox *data() const;
0299     /** shortcut for \c data
0300      * @return current caret box
0301      */
0302     CaretBox *operator *() const
0303     {
0304         return data();
0305     }
0306 
0307     /** increments the iterator to point to the next caret box.
0308      */
0309     CaretBoxIterator &operator ++()
0310     {
0311         index++;
0312         return *this;
0313     }
0314     /** decrements the iterator to point to the previous caret box.
0315      */
0316     CaretBoxIterator &operator --()
0317     {
0318         index--;
0319         return *this;
0320     }
0321 
0322     friend class CaretBoxLine;
0323     friend class EditableCaretBoxIterator;
0324 };
0325 
0326 /**
0327  * Resembles a line consisting of caret boxes.
0328  *
0329  * To the contrary of InlineFlowBoxes which are nested as needed to map the
0330  * DOM to the rendered representation, it is sufficient for caret navigation
0331  * to provide a linear list of unnested caret boxes.
0332  *
0333  * \code
0334  * Example: The document fragment <p>a <i><b>c</b> f</i> g</p> will be
0335  * represented by three caret box lines which each one consists of caret boxes
0336  * as follows:
0337  * CaretBoxLine 1:
0338  *   CaretBox(cb=<p>, _box=0, _outside=true, outside_end=false)
0339  * CaretBoxLine 2:
0340  *   CaretBox(cb=<p>, _box=InlineTextBox("a "), _outside=false)
0341  *   CaretBox(cb=<p>, _box=InlineFlowBox(<i>), _outside=true, outside_end=false)
0342  *   CaretBox(cb=<p>, _box=InlineFlowBox(<b>), _outside=true, outside_end=false)
0343  *   CaretBox(cb=<p>, _box=InlineTextBox("c"), _outside=false)
0344  *   CaretBox(cb=<p>, _box=InlineFlowBox(<b>), _outside=true, outside_end=true)
0345  *   CaretBox(cb=<p>, _box=InlineTextBox(" f"), _outside=false)
0346  *   CaretBox(cb=<p>, _box=InlineFlowBox(<i>), _outside=true, outside_end=true)
0347  *   CaretBox(cb=<p>, _box=InlineTextBox(" g"), _outside=true, outside_end=true)
0348  * CaretBoxLine 3:
0349  *   CaretBox(cb=<p>, _box=0, _outside=true, outside_end=true)
0350  * \endcode
0351  */
0352 class CaretBoxLine
0353 {
0354 protected:
0355     CaretBoxDeleter caret_boxes;
0356     // base flow box which caret boxes have been constructed for
0357     InlineFlowBox *basefb;
0358 
0359     CaretBoxLine() : caret_boxes(8), basefb(0) {}
0360     CaretBoxLine(InlineFlowBox *basefb) : caret_boxes(8), basefb(basefb) {}
0361 public:
0362 #if DEBUG_CARETMODE > 3
0363     ~CaretBoxLine()
0364     {
0365         qCDebug(KHTML_LOG) << "called";
0366     }
0367 #endif
0368 
0369     CaretBoxIterator begin()
0370     {
0371         CaretBoxIterator it;
0372         it.cbl = this;
0373         it.index = 0;
0374         return it;
0375     }
0376     CaretBoxIterator end()
0377     {
0378         CaretBoxIterator it;
0379         it.cbl = this;
0380         it.index = caret_boxes.size();
0381         return it;
0382     }
0383     CaretBoxIterator preBegin()
0384     {
0385         CaretBoxIterator it;
0386         it.cbl = this;
0387         it.index = -1;
0388         return it;
0389     }
0390     CaretBoxIterator preEnd()
0391     {
0392         CaretBoxIterator it;
0393         it.cbl = this;
0394         it.index = caret_boxes.size() - 1;
0395         return it;
0396     }
0397 
0398     /** returns the base inline flow box which the caret boxes of this
0399      * caret box line have been constructed from.
0400      *
0401      * This is generally a root line box, but may be an inline flow box when the
0402      * base is restricted to an inline element.
0403      */
0404     InlineFlowBox *baseFlowBox() const
0405     {
0406         return basefb;
0407     }
0408 
0409     /** returns the containing block */
0410     RenderBlock *containingBlock() const
0411     {
0412         return caret_boxes[0]->containingBlock();
0413     }
0414     /** returns the enclosing object */
0415     RenderBox *enclosingObject() const
0416     {
0417         return caret_boxes[0]->enclosingObject();
0418     }
0419 
0420     /** returns whether this caret box line is outside.
0421      * @return true if this caret box represents an outside position of this
0422      *    line box' containing block, false otherwise.
0423      */
0424     bool isOutside() const
0425     {
0426         const CaretBox *cbox = caret_boxes[0];
0427         return !cbox->isInline() && cbox->isOutside();
0428     }
0429 
0430     /** returns whether this caret box line is at the outside end.
0431      *
0432      * The result cannot be relied upon unless isOutside() returns true.
0433      */
0434     bool isOutsideEnd() const
0435     {
0436         return caret_boxes[0]->isOutsideEnd();
0437     }
0438 
0439     /** constructs a new caret box line out of the given inline flow box
0440      * @param deleter deleter which handles alloc+dealloc of the object
0441      * @param baseFlowBox basic flow box which to create a caret line box from
0442      * @param seekBox seek this box within the constructed line
0443      * @param seekOutside denoting whether position is outside of seekBox
0444      * @param seekOutsideEnd whether at the outside end of seekBox
0445      * @param iter returns an iterator that corresponds to seekBox. If no suitable
0446      *    caret box exists, it will return end()
0447      * @param seekObject seek this render object within the constructed line.
0448      *    It will only be regarded if \c seekBox is 0. \c iter will then point
0449      *    to the first caret box whose render object matches.
0450      */
0451     static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter,
0452             InlineFlowBox *baseFlowBox, InlineBox *seekBox, bool seekOutside,
0453             bool seekOutsideEnd, CaretBoxIterator &iter,
0454             RenderObject *seekObject = 0) /*KHTML_NO_EXPORT*/;
0455 
0456     /** constructs a new caret box line for the given render block.
0457      * @param deleter deleter which handles alloc+dealloc of the object
0458      * @param cb render block or render replaced
0459      * @param outside true when line is to be constructed outside
0460      * @param outsideEnd true when the ending outside is meant
0461      * @param iter returns the iterator to the caret box representing the given
0462      *    position for \c cb
0463      */
0464     static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter,
0465             RenderBox *cb, bool outside, bool outsideEnd, CaretBoxIterator &iter) /*KHTML_NO_EXPORT*/;
0466 
0467 #if DEBUG_CARETMODE > 0
0468     void dump(QTextStream &ts, const QString &ind) const;
0469     QString information() const
0470     {
0471         QString result;
0472         QTextStream ts(&result, QIODevice::WriteOnly);
0473         dump(ts, QString());
0474         return result;
0475     }
0476 #endif
0477 
0478 protected:
0479     /** contains the seek parameters */
0480     struct SeekBoxParams {
0481         InlineBox *box;
0482         bool outside;
0483         bool outsideEnd;
0484         bool found;
0485         RenderObject *r;    // if box is 0, seek for equal render objects instead
0486         CaretBoxIterator &it;
0487 
0488         SeekBoxParams(InlineBox *box, bool outside, bool outsideEnd, RenderObject *obj, CaretBoxIterator &it)
0489             : box(box), outside(outside), outsideEnd(outsideEnd), found(false), r(obj), it(it)
0490         {}
0491 
0492         /** compares whether this seek box matches the given specification */
0493         bool equalsBox(const InlineBox *box, bool outside, bool outsideEnd) const
0494         {
0495             return (this->box && this->box == box
0496                     || this->r == box->object())
0497                    && this->outside == outside
0498                    && (!this->outside || this->outsideEnd == outsideEnd);
0499         }
0500         /** compares whether this seek box matches the given caret box */
0501         bool operator ==(const CaretBox *cbox) const
0502         {
0503             return equalsBox(cbox->inlineBox(), cbox->isOutside(), cbox->isOutsideEnd());
0504         }
0505         /** checks whether this box matches the given iterator.
0506          *
0507          * On success, it sets \c found, and assigns the iterator to \c it.
0508          * @return true on match
0509          */
0510         bool check(const CaretBoxIterator &chit)
0511         {
0512             if (*this == *chit) {
0513                 Q_ASSERT(!found);
0514                 found = true;
0515                 it = chit;
0516             }
0517             return found;
0518         }
0519     };
0520 
0521     /** recursively converts the given inline box into caret boxes and adds them
0522      * to this caret box line.
0523      *
0524      * It will additionally look for the caret box specified in SeekBoxParams.
0525      */
0526     void addConvertedInlineBox(InlineBox *, SeekBoxParams &) /*KHTML_NO_EXPORT*/;
0527 
0528     /** creates and adds the edge of a generic inline box
0529      * @param box inline box
0530      * @param fm font metrics of inline box
0531      * @param left true to add left edge, false to add right edge
0532      * @param rtl true if direction is rtl
0533      */
0534     void addCreatedInlineBoxEdge(InlineBox *box, const QFontMetrics &fm,
0535                                  bool left, bool rtl) /*KHTML_NO_EXPORT*/;
0536     /** creates and adds the edge of an inline flow box
0537      * @param flowBox inline flow box
0538      * @param fm font metrics of inline flow box
0539      * @param left true to add left edge, false to add right edge
0540      * @param rtl true if direction is rtl
0541      */
0542     void addCreatedFlowBoxEdge(InlineFlowBox *flowBox, const QFontMetrics &fm,
0543                                bool left, bool rtl) /*KHTML_NO_EXPORT*/;
0544     /** creates and adds the inside of an inline flow box
0545      * @param flowBox inline flow box
0546      * @param fm font metrics of inline flow box
0547      */
0548     void addCreatedFlowBoxInside(InlineFlowBox *flowBox, const QFontMetrics &fm) /*KHTML_NO_EXPORT*/;
0549 
0550     friend class CaretBoxIterator;
0551 };
0552 
0553 typedef MassDeleter<CaretBoxLine> CaretBoxLineDeleter;
0554 
0555 inline CaretBox *CaretBoxIterator::data() const
0556 {
0557     return cbl->caret_boxes[index];
0558 }
0559 
0560 /**
0561  * Iterates through the lines of a document.
0562  *
0563  * The line iterator becomes invalid when the associated LinearDocument object
0564  * is destroyed.
0565  * @internal
0566  * @author Leo Savernik
0567  */
0568 class LineIterator
0569 {
0570 protected:
0571     LinearDocument *lines;    // associated document
0572     CaretBoxLine *cbl;        // current caret box line
0573 
0574     static CaretBoxIterator currentBox;   // current inline box
0575     static long currentOffset;
0576 
0577     // Note: cbl == 0 indicates a position beyond the beginning or the
0578     // end of a document.
0579 
0580     /** Default constructor, only for internal use
0581      */
0582     LineIterator() {}
0583 
0584     /** Initializes a new iterator.
0585      *
0586      * Note: This constructor neither cares about the correctness of @p node
0587      * nor about @p offset. It is the responsibility of the caller to ensure
0588      * that both point to valid places.
0589      */
0590     LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset);
0591 
0592 public:
0593     /** dereferences current caret box line.
0594      *
0595      * @returns the caret line box or 0 if end of document
0596      */
0597     CaretBoxLine *operator *() const
0598     {
0599         return cbl;
0600     }
0601 
0602     /** returns the associated linear document
0603      */
0604     LinearDocument *linearDocument() const
0605     {
0606         return lines;
0607     }
0608 
0609     /** seek next line
0610      *
0611      * Guaranteed to crash if beyond beginning/end of document.
0612      */
0613     LineIterator &operator ++()
0614     {
0615         advance(false);
0616         return *this;
0617     }
0618 
0619     /** seek previous line.
0620      *
0621      * Guaranteed to crash if beyond beginning/end of document.
0622      */
0623     LineIterator &operator --()
0624     {
0625         advance(true);
0626         return *this;
0627     }
0628 
0629     /** compares two iterators. The comparator actually works only for
0630      * comparing arbitrary iterators to begin() and end().
0631      */
0632     bool operator ==(const LineIterator &it) const
0633     {
0634         return lines == it.lines && cbl == it.cbl;
0635     }
0636 
0637     /** compares two iterators
0638      */
0639     bool operator !=(const LineIterator &it) const
0640     {
0641         return !operator ==(it);
0642     }
0643 
0644     /** Returns whether this line represents the outside end of the containing
0645      * block.
0646      *
0647      * This result can only be relied on when isOutside is true.
0648      */
0649     bool isOutsideEnd()
0650     {
0651         return cbl->isOutsideEnd();
0652     }
0653 
0654     /** Tells whether the offset is meant to be outside or inside the
0655      * containing block.
0656      */
0657     bool isOutside() const
0658     {
0659         return cbl->isOutside();
0660     }
0661 
0662     /** advances to the line to come.
0663      * @param toBegin true, move to previous line, false, move to next line.
0664      */
0665     void advance(bool toBegin);
0666 
0667     /** Whenever a new line iterator is created, it gets a caret box created.
0668      * For memory reasons, it's saved in a static instance,
0669      * thus making this function not thread-safe.
0670      *
0671      * This value can only be trusted immediately after having instantiated
0672      * a line iterator or one of its derivatives.
0673      * @return an iterator onto the corresponing caret box within the
0674      *    line represented by the last instantiation of a line iterator,
0675      *    or 0 if there was none.
0676      */
0677     static CaretBoxIterator &currentCaretBox()
0678     {
0679         return currentBox;
0680     }
0681 
0682     /** Whenever a new line iterator is created, it calculates a modified offset
0683      * that is to be used with respect to the current render object.
0684      * This offset can be queried with this function.
0685      *
0686      * This value can only be trusted immediately after having instantiated
0687      * a line iterator or one of its derivatives.
0688      * @return the modified offset.
0689      */
0690     static long currentModifiedOffset()
0691     {
0692         return currentOffset;
0693     }
0694 
0695 protected:
0696     /** seeks next block.
0697      */
0698     void nextBlock();
0699     /** seeks previous block.
0700      */
0701     void prevBlock();
0702 
0703     friend class CaretBoxIterator;
0704     friend class EditableLineIterator;
0705     friend class EditableCaretBoxIterator;
0706     friend class EditableCharacterIterator;
0707     friend class LinearDocument;
0708 };
0709 
0710 /**
0711  * Represents the whole document in terms of lines.
0712  *
0713  * SGML documents are trees. But for navigation, this representation is
0714  * not practical. Therefore this class serves as a helper to represent the
0715  * document as a linear list of lines. Its usage somewhat resembles STL
0716  * semantics like begin and end as well as iterators.
0717  *
0718  * The lines itself are represented as caret line boxes.
0719  *
0720  * LinearDocument instances are not meant to be kept over the lifetime of their
0721  * associated document, but constructed from (node, offset) pairs whenever line
0722  * traversal is needed. This is because the underlying InlineFlowBox objects
0723  * may be destroyed and recreated (e. g. by resizing the window, adding/removing
0724  * elements).
0725  *
0726  * @author Leo Savernik
0727  * @internal
0728  */
0729 class LinearDocument
0730 {
0731 public:
0732     typedef LineIterator Iterator;
0733 
0734     /**
0735      * Creates a new instance, and initializes it to the line specified by
0736      * the parameters below.
0737      *
0738      * Creation will fail if @p node is invisible or defect.
0739      * @param part part within which everything is taking place.
0740      * @param node document node with which to start
0741      * @param offset zero-based offset within this node.
0742      * @param advancePolicy caret advance policy
0743      * @param baseElem base element which the caret must not advance beyond
0744      *    (0 means whole document). The base element will be ignored if it
0745      *    cannot serve as a base (to see if this is the case, check whether
0746      *    LinearDocument::baseFlow()->element() != base)
0747      */
0748     LinearDocument(KHTMLPart *part, DOM::NodeImpl *node, long offset,
0749                    CaretAdvancePolicy advancePolicy, DOM::ElementImpl *baseElem);
0750 
0751     virtual ~LinearDocument();
0752 
0753     /**
0754      * Tells whether this list contains any lines.
0755      *
0756      * @returns @p true if this document contains lines, @p false otherwise. Note
0757      *    that an empty document contains at least one line, so this method
0758      *    only returns @p false if the document could not be initialised for
0759      *    some reason.
0760      */
0761     bool isValid() const      // FIXME: not yet impl'd
0762     {
0763         return true;
0764     }
0765 
0766     /**
0767      * Returns the count of lines.
0768      *
0769      * Warning: This function is expensive. Call it once and cache the value.
0770      *
0771      * FIXME: It's not implemented yet (and maybe never will)
0772      */
0773     int count() const;
0774 
0775     /**
0776      * Returns a line iterator containing the current position as its starting
0777      * value.
0778      */
0779     Iterator current();
0780 
0781     /**
0782      * Returns a line iterator pointing right after the end of the document.
0783      */
0784     const Iterator &end() const
0785     {
0786         return _end;
0787     }
0788 
0789     /**
0790      * Returns a line iterator pointing to the very last line of the document.
0791      */
0792     Iterator preEnd();
0793 
0794     /**
0795      * Returns a line iterator pointing to the very first line of the document.
0796      */
0797     Iterator begin();
0798 
0799     /**
0800      * Returns a line iterator pointing just before the very first line of the
0801      * document (this is somewhat an emulation of reverse iterators).
0802      */
0803     const Iterator &preBegin() const
0804     {
0805         return _preBegin;
0806     }
0807 
0808     /**
0809      * Returns the current caret advance policy
0810      */
0811     CaretAdvancePolicy advancePolicy() const
0812     {
0813         return advPol;
0814     }
0815 
0816     /**
0817      * Returns the base render object which the caret must not advance beyond.
0818      *
0819      * Note that HTML documents are usually restricted to the body element.
0820      *
0821      * @return the base render object or 0 if the whole document is valid.
0822      */
0823     RenderObject *baseObject() const
0824     {
0825         return base;
0826     }
0827 
0828 protected:
0829     void initPreBeginIterator();
0830     void initEndIterator();
0831 
0832 protected:
0833     CaretBoxLineDeleter cblDeleter;   // mass deleter for caret box lines
0834     DOM::NodeImpl *node;
0835     long offset;
0836 
0837     Iterator _preBegin;
0838     Iterator _end;
0839 
0840     KHTMLPart *m_part;
0841     CaretAdvancePolicy advPol;
0842     RenderObject *base;
0843 
0844     friend class LineIterator;
0845     friend class EditableLineIterator;
0846     friend class ErgonomicEditableLineIterator;
0847     friend class CaretBoxIterator;
0848     friend class EditableCaretBoxIterator;
0849     friend class EditableCharacterIterator;
0850 };
0851 
0852 /**
0853  * Iterates over the editable inner elements of a caret line box.
0854  *
0855  * The incrementor will traverse all caret boxes according to the associated
0856  * linear document's caret advance policy. In contrast to \c CaretBoxIterator
0857  * this iterator only regards caret boxes which are editable.
0858  *
0859  * @author Leo Savernik
0860  * @internal
0861  */
0862 class EditableCaretBoxIterator : public CaretBoxIterator
0863 {
0864     KHTMLPart *m_part;
0865     bool adjacent;
0866     CaretAdvancePolicy advpol;    // caret advance policy
0867 
0868 public:
0869     /** initializes a new iterator from the given line iterator,
0870      * beginning with the given caret box iterator, if specified
0871      */
0872     EditableCaretBoxIterator(LineIterator &lit, bool fromEnd = false,
0873                              CaretBoxIterator *it = 0)
0874         : CaretBoxIterator(it ? *it : (fromEnd ? (*lit)->end() : (*lit)->preBegin())),
0875           m_part(lit.lines->m_part), adjacent(false),
0876           advpol(lit.lines->advancePolicy())
0877     {
0878         if (!it) {
0879             if (fromEnd) {
0880                 --*this;
0881             } else {
0882                 ++*this;
0883             }
0884         }
0885     }
0886 
0887     /** empty constructor. Use only to copy another iterator into this one.
0888      */
0889     EditableCaretBoxIterator() {}
0890 
0891     /** returns @p true when the current caret box is adjacent to the
0892      * previously iterated caret box, i. e. no intervening caret boxes.
0893      */
0894     bool isAdjacent() const
0895     {
0896         return adjacent;
0897     }
0898 
0899     /** increments the iterator to point to the next editable caret box.
0900      */
0901     EditableCaretBoxIterator &operator ++()
0902     {
0903         advance(false);
0904         return *this;
0905     }
0906 
0907     /** decrements the iterator to point to the previous editable caret box.
0908      */
0909     EditableCaretBoxIterator &operator --()
0910     {
0911         advance(true);
0912         return *this;
0913     }
0914 
0915     /** advances to the editable caret box to come
0916      * @param toBegin true, move towards beginning, false, move towards end.
0917      */
0918     void advance(bool toBegin);
0919 
0920 protected:
0921     /** finds out if the given box is editable.
0922      * @param boxit iterator to given caret box
0923      * @param fromEnd true when advancing towards the beginning
0924      * @return @p true if box is editable
0925      */
0926     bool isEditable(const CaretBoxIterator &boxit, bool fromEnd);
0927 };
0928 
0929 /**
0930  * Iterates through the editable lines of a document.
0931  *
0932  * This iterator, opposing to @p LineIterator, only regards editable lines.
0933  * Additionally, this iterator enforces the caret advance policy.
0934  *
0935  * The iterator can be compared to normal LineIterators, especially to
0936  * @ref LinearDocument::preBegin and @ref LinearDocument::end
0937  *
0938  * The line iterator becomes invalid when the associated LinearDocument object
0939  * is destroyed.
0940  * @internal
0941  * @author Leo Savernik
0942  */
0943 class EditableLineIterator : public LineIterator
0944 {
0945 public:
0946     /** Initializes a new iterator.
0947      *
0948      * The iterator is set to the first following editable line or to the
0949      * end if no editable line follows.
0950      * @param it a line iterator to initialize this from
0951      * @param fromEnd @p true, traverse towards the beginning in search of an
0952      *    editable line
0953      */
0954     EditableLineIterator(const LineIterator &it, bool fromEnd = false)
0955         : LineIterator(it)
0956     {
0957         if (!cbl) {
0958             return;
0959         }
0960         if (!isEditable(*this)) {
0961             advance(fromEnd);
0962         }
0963     }
0964 
0965     /** empty constructor.
0966      *
0967      * Only use if you want to copy another iterator onto it later.
0968      */
0969     EditableLineIterator() {}
0970 
0971     /** seek next line
0972      *
0973      * Guaranteed to crash if beyond beginning/end of document.
0974      */
0975     EditableLineIterator &operator ++()
0976     {
0977         advance(false);
0978         return *this;
0979     }
0980 
0981     /** seek previous line.
0982      *
0983      * Guaranteed to crash if beyond beginning/end of document.
0984      */
0985     EditableLineIterator &operator --()
0986     {
0987         advance(true);
0988         return *this;
0989     }
0990 
0991     /** advances to the line to come.
0992      * @param toBegin true, move to previous line, false, move to next line.
0993      */
0994     void advance(bool toBegin);
0995 
0996 protected:
0997     /** finds out if the current line is editable.
0998      *
0999      * @param it check caret box line iterator points to
1000      * @return @p true if line is editable
1001      */
1002     bool isEditable(LineIterator &it)
1003     {
1004         EditableCaretBoxIterator fbit = it;
1005         return fbit != (*it)->end();
1006     }
1007 
1008 };
1009 
1010 /** Represents a render table as a linear list of rows.
1011  *
1012  * This iterator abstracts from table sections and treats tables as a linear
1013  * representation of all rows they contain.
1014  * @author Leo Savernik
1015  * @internal
1016  */
1017 class TableRowIterator
1018 {
1019 protected:
1020     TableSectionIterator sec; // current section
1021     int index;            // index of row within section
1022 public:
1023     /** Constructs a new iterator.
1024      * @param table table to iterate through.
1025      * @param fromEnd @p true to iterate towards the beginning
1026      * @param row pointer to row to start with, 0 starts at the first/last
1027      *    row.
1028      */
1029     TableRowIterator(RenderTable *table, bool fromEnd = false,
1030                      RenderTableSection::RowStruct *row = 0);
1031 
1032     /** Constructs a new iterator.
1033      * @param section table section to begin with
1034      * @param index index within table section
1035      */
1036     TableRowIterator(RenderTableSection *section, int index)
1037         : sec(section), index(index)
1038     {}
1039 
1040     /** empty constructor. This must be assigned another iterator before it is
1041      * useable.
1042      */
1043     TableRowIterator() {}
1044 
1045     /** returns the current table row.
1046      * @return the row or 0 if the end of the table has been reached.
1047      */
1048     RenderTableSection::RowStruct *operator *()
1049     {
1050         if (!*sec) {
1051             return 0;
1052         }
1053         return &(*sec)->grid[index];
1054     }
1055 
1056     /** advances to the next row
1057      */
1058     TableRowIterator &operator ++();
1059 
1060     /** advances to the previous row
1061      */
1062     TableRowIterator &operator --();
1063 
1064 protected:
1065 };
1066 
1067 /** Iterates through the editable lines of a document, in a topological order.
1068  *
1069  * The differences between this and the EditableLineIterator lies in the way
1070  * lines are inquired. While the latter steps through the lines in document
1071  * order, the former takes into consideration ergonomics.
1072  *
1073  * This is especially useful for tables. EditableLineIterator traverses all
1074  * table cells from left to right, top to bottom, while this one will
1075  * actually snap to the cell in the right position, and traverse only
1076  * upwards/downwards, thus providing a more intuitive navigation.
1077  *
1078  * @author Leo Savernik
1079  * @internal
1080  */
1081 class ErgonomicEditableLineIterator : public EditableLineIterator
1082 {
1083 protected:
1084     int xCoor;        // x-coordinate to determine cell position
1085 public:
1086     /** Initializes a new ergonomic editable line iterator from the given one.
1087      * @param it line iterator
1088      * @param x absolute x-coordinate for cell determination
1089      */
1090     ErgonomicEditableLineIterator(const LineIterator &it, int x)
1091         : EditableLineIterator(it), xCoor(x) {}
1092 
1093     /** Constructs an uninitialized iterator which must be assigned a line iterator before
1094      * it can be used.
1095      */
1096     ErgonomicEditableLineIterator() {}
1097 
1098     /** seek next line.
1099      *
1100      * The next line will be one that is visually situated below this line.
1101      */
1102     ErgonomicEditableLineIterator &operator ++();
1103 
1104     /** seek previous line.
1105      *
1106      * The previous line will be one that is visually situated above this line.
1107      */
1108     ErgonomicEditableLineIterator &operator --();
1109 
1110 protected:
1111     /** determines the topologically next render object.
1112      * @param oldCell table cell the original object was under.
1113      * @param newObject object to determine whether and which transition
1114      *    between cells is to be handled. It does not have to be an object in the correct
1115      *    topological cell, a simple delivery from an editable line iterator suffices.
1116      * @param toBegin if @p true, iterate towards the beginning
1117      */
1118     void determineTopologicalElement(RenderTableCell *oldCell,
1119                                      RenderObject *newObject, bool toBegin);
1120 
1121     /** initializes the iterator to point to the first previous/following editable
1122      * line.
1123      * @param newBlock take this as base block.
1124      * @param toBegin @p true, iterate towards beginning.
1125      */
1126     void calcAndStoreNewLine(RenderBlock *newBlock, bool toBegin);
1127 
1128 };
1129 
1130 /**
1131  * Provides iterating through the document in terms of characters. Only the
1132  * editable characters are regarded.
1133  *
1134  * This iterator represents the document, which is structured as a tree itself,
1135  * as a linear stream of characters.
1136  */
1137 class EditableCharacterIterator
1138 {
1139 protected:
1140     EditableLineIterator _it;
1141     EditableCaretBoxIterator ebit;
1142     long _offset;     // offset within current caret box.
1143     int _char;
1144     bool _end: 1;     // true when end of document has been reached
1145 
1146 public:
1147 
1148     /** empty constructor.
1149      *
1150      * Only use if you want to assign another iterator as no fields will
1151      * be initialized.
1152      */
1153     EditableCharacterIterator() {}
1154 
1155     /** constructs a new iterator from the given linear document.
1156      *
1157      * @param ld linear representation of document.
1158      */
1159     EditableCharacterIterator(LinearDocument *ld)
1160         : _it(ld->current()),
1161           ebit(_it, false, &_it.currentCaretBox()),
1162           _offset(_it.currentModifiedOffset()), _char(-1), _end(false)
1163     {
1164         // ### temporary fix for illegal nodes
1165         if (_it == ld->end()) {
1166             _end = true;
1167             return;
1168         }
1169         initFirstChar();
1170     }
1171 
1172     /** returns the current character, or -1 if not on a text node, or beyond
1173      * the end.
1174      */
1175     int chr() const
1176     {
1177         return _char;
1178     }
1179 
1180     /** returns the current character as a unicode symbol, substituting
1181      * a blank for a non-text node.
1182      */
1183     QChar operator *() const
1184     {
1185         return QChar(_char >= 0 ? _char : ' ');
1186     }
1187 
1188     /** returns true when the end of the document has been reached.
1189      */
1190     bool isEnd() const
1191     {
1192         return _end;
1193     }
1194     /** returns the current offset
1195      */
1196     long offset() const
1197     {
1198         return _offset;
1199     }
1200     /** returns the current render object.
1201      */
1202     RenderObject *renderer() const
1203     {
1204         return (*ebit)->object();
1205     }
1206     /** returns the current caret box.
1207      *
1208      * Will crash if beyond end.
1209      */
1210     CaretBox *caretBox() const
1211     {
1212         return *ebit;
1213     }
1214     /** returns the current inline box.
1215      *
1216      * May be 0 if the current element has none, or if the end has been reached.
1217      * Therefore, do *not* use this to test for the end condition, use node()
1218      * instead.
1219      */
1220     InlineBox *inlineBox() const
1221     {
1222         return (*ebit)->inlineBox();
1223     }
1224     /** returns whether the current line box represents the outside of its
1225      * render object.
1226      */
1227 //  bool boxIsOutside() const { return _it.isOutside(); }
1228 
1229     /** moves to the next editable character.
1230      */
1231     EditableCharacterIterator &operator ++();
1232 
1233     /** moves to the previous editable character.
1234      */
1235     EditableCharacterIterator &operator --();
1236 
1237 protected:
1238     /** initializes the _char member by reading the character at the current
1239      * offset, peeking ahead as necessary.
1240      */
1241     void initFirstChar();
1242     /** reads ahead the next node and updates the data structures accordingly
1243      */
1244     void peekNext()
1245     {
1246         EditableCaretBoxIterator copy = ebit;
1247         ++copy;
1248         if (copy == (*_it)->end()) {
1249             _char = -1;
1250             return;
1251         }
1252 
1253         CaretBox *box = *copy;
1254         InlineBox *b = box->inlineBox();
1255         if (b && !box->isOutside() && b->isInlineTextBox()) {
1256             _char = static_cast<RenderText *>(b->object())->str->s[b->minOffset()].unicode();
1257         } else {
1258             _char = -1;
1259         }
1260     }
1261     /** reads ahead the previous node and updates the data structures accordingly
1262      */
1263     void peekPrev()
1264     {
1265         --ebit;
1266     }
1267 
1268 };
1269 
1270 }/*namespace khtml*/
1271 
1272 #endif