Warning: That file was not part of the compilation database. It may have many parsing errors.

1/* This file is part of the KDE project
2 *
3 * Copyright (C) 2003-2004 Leo Savernik <l.savernik@aon.at>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifndef KHTML_CARET_P_H
22#define KHTML_CARET_P_H
23
24#include "rendering/render_table.h"
25
26
27#define DEBUG_CARETMODE 0
28
29class QFontMetrics;
30
31namespace DOM {
32 class NodeImpl;
33 class ElementImpl;
34}
35
36namespace khtml {
37
38/** caret advance policy.
39 *
40 * Used to determine which elements are taken into account when the caret is
41 * advanced. Later policies pose refinements of all former
42 * policies.
43 * @param LeafsOnly advance from leave render object to leaf render object
44 * (It will allow outside flow positions if a flow wouldn't be reachable
45 * otherwise).
46 * @param IndicatedFlows place caret also at the beginning/end of flows
47 * that have at least one visible border at any side.
48 * (It will allow not indicated flow positions if a flow wouldn't
49 * be reachable otherwise).
50 * @param VisibleFlows place caret also at the beginning/end of any flow
51 * that has a renderer.
52 */
53enum CaretAdvancePolicy {
54 LeafsOnly, IndicatedFlows, VisibleFlows
55};
56
57/** contextual information about the caret which is related to the view.
58 * An object of this class is only instantiated when it is needed.
59 */
60struct CaretViewContext {
61 int freqTimerId; // caret blink frequency timer id
62 int x, y; // caret position in viewport coordinates
63 // (y specifies the top, not the baseline)
64 int width; // width of caret in pixels
65 int height; // height of caret in pixels
66 bool visible; // true if currently visible.
67 bool displayed; // true if caret is to be displayed at all.
68 bool caretMoved; // set to true once caret has been moved in page
69 // how to display the caret when view is not focused
70 KHTMLPart::CaretDisplayPolicy displayNonFocused;
71
72 /** For natural traversal of lines, the original x position is saved, and
73 * the actual x is set to the first character whose x position is
74 * greater than origX.
75 *
76 * origX is reset to x whenever the caret is moved horizontally or placed
77 * by the mouse.
78 */
79 int origX;
80
81 bool keyReleasePending; // true if keypress under caret mode awaits
82 // corresponding release event
83 CaretViewContext() : freqTimerId(-1), x(0), y(0), width(1), height(16),
84 visible(true), displayed(false), caretMoved(false),
85 displayNonFocused(KHTMLPart::CaretInvisible), origX(0),
86 keyReleasePending(false)
87 {}
88};
89
90class LinearDocument;
91
92/**
93 * Stores objects of a certain type, and calls delete on each of them
94 * when this data structure is destroyed.
95 *
96 * As this structure merely consists of a vector of pointers, all objects
97 * allocated can be traversed as seen fit.
98 *
99 * @author Leo Savernik
100 * @internal
101 */
102template<class T> class MassDeleter : public QVector<T *> {
103public:
104 MassDeleter(size_t reserved = 1) { this->reserve(reserved); }
105 ~MassDeleter()
106 {
107 typename QVector<T *>::Iterator nd = this->end();
108 for (typename QVector<T *>::Iterator it = this->begin(); it != nd; ++it)
109 delete *it;
110 }
111};
112
113class CaretBoxLine;
114
115/**
116 * Represents a rectangular box within which the caret is located.
117 *
118 * The caret box serves as a wrapper for inline boxes of all kind. It either
119 * wraps an InlineBox, InlineTextBox, or InlineFlowBox, or if no such boxes
120 * exist for a certain context, it contains the relevant information directly.
121 *
122 * This class will be constructed whenever a caret position has to be described.
123 * @author Leo Savernik
124 * @internal
125 */
126class CaretBox {
127protected:
128 InlineBox *_box; // associated inline box if available.
129 short _w; // width of box in pixels
130 int _h; // height of box in pixels
131 int _x; // x coordinate relative to containing block
132 int _y; // y coordinate relative to containing block
133 RenderBox *cb; // containing block
134 bool _outside:1; // true when representing the outside of the element
135 bool outside_end:1; // at ending outside of element rather than at beginning
136 // 29 bits unused
137
138public:
139 /** empty constructor for later assignment */
140 CaretBox() {}
141 /** initializes the caret box from the given inline box */
142 CaretBox(InlineBox *ibox, bool outside, bool outsideEnd) : _box(ibox),
143 _w((short)ibox->width()), _h(ibox->height()), _x(ibox->xPos()),
144 _y(ibox->yPos()), cb(0), _outside(outside), outside_end(outsideEnd)
145 {
146 RenderObject *r = ibox->object();
147 if (r) cb = r->containingBlock();
148 }
149 /** initializes the caret box from scratch */
150 CaretBox(int x, int y, int w, int h, RenderBox *cb, bool outside, bool outsideEnd) :
151 _box(0), _w((short)w), _h(h), _x(x), _y(y), cb(cb), _outside(outside),
152 outside_end(outsideEnd)
153 {}
154
155 int width() const { return _w; }
156 int height() const { return _h; }
157 int xPos() const { return _x; }
158 int yPos() const { return _y; }
159 RenderBox *enclosingObject() const { return cb; }
160 InlineBox *inlineBox() const { return _box; }
161
162 /** returns the containing block of this caret box. If the caret box
163 * resembles a block itself, its containing block is returned.
164 */
165 RenderBlock *containingBlock() const { return _box ? static_cast<RenderBlock *>(cb) : cb->containingBlock(); }
166
167 /** returns the replaced render object if this caret box represents one,
168 * 0 otherwise.
169 */
170
171
172 /** returns true if this caret box represents an inline element, or text box,
173 * otherwise false.
174 */
175 bool isInline() const { return _box; }
176 /** returns true if this caret box represents an inline text box.
177 */
178 bool isInlineTextBox() const { return _box && _box->isInlineTextBox(); }
179 /** returns true if this caret box represents a line break
180 */
181 bool isLineBreak() const
182 {
183 return _box && _box->object() && _box->object()->isBR();
184 }
185 /** returns true when this caret box represents an ouside position of an
186 * element.
187 */
188 bool isOutside() const { return _outside; }
189 /** returns the position at which the outside is targeted at.
190 *
191 * This method's return value is meaningless if isOutside() is not true.
192 * @return true if the outside end is meant, false if the outside beginning
193 * is meant.
194 */
195 bool isOutsideEnd() const { return outside_end; }
196 /** returns the associated render object. */
197 RenderObject *object() const { return _box ? _box->object() : cb; }
198
199 /** returns the minimum offset for this caret box.
200 */
201 long minOffset() const { return _box && !isLineBreak() ? _box->minOffset() : 0; }
202 /** returns the maximum offset for this caret box.
203 */
204 long maxOffset() const { return _box && !isLineBreak() ? _box->maxOffset() : 0; }
205
206#if DEBUG_CARETMODE > 0
207 void dump(QTextStream &ts, const QString &ind) const;
208#endif
209
210 friend class CaretBoxLine;
211};
212
213typedef MassDeleter<CaretBox> CaretBoxDeleter;
214
215/**
216 * Iterates over the elements of a caret box line.
217 *
218 * @author Leo Savernik
219 * @internal
220 */
221class CaretBoxIterator {
222protected:
223 CaretBoxLine *cbl; // associated caret box line
224 int index; // current index
225
226public:
227 // Let standard constructor/copy constructor/destructor/assignment operator
228 // be defined by the compiler. They do exactly what we want.
229 CaretBoxIterator()
230 : cbl( 0 ), index( 0 )
231 {
232 }
233
234 bool operator ==(const CaretBoxIterator &it) const
235 {
236 return cbl == it.cbl && index == it.index;
237 }
238
239 bool operator !=(const CaretBoxIterator &it) const
240 {
241 return !operator ==(it);
242 }
243
244 /** returns the current caret box.
245 * @return current caret box
246 */
247 CaretBox *data() const;
248 /** shortcut for \c data
249 * @return current caret box
250 */
251 CaretBox *operator *() const { return data(); }
252
253 /** increments the iterator to point to the next caret box.
254 */
255 CaretBoxIterator &operator ++() { index++; return *this; }
256 /** decrements the iterator to point to the previous caret box.
257 */
258 CaretBoxIterator &operator --() { index--; return *this; }
259
260 friend class CaretBoxLine;
261 friend class EditableCaretBoxIterator;
262};
263
264/**
265 * Resembles a line consisting of caret boxes.
266 *
267 * To the contrary of InlineFlowBoxes which are nested as needed to map the
268 * DOM to the rendered representation, it is sufficient for caret navigation
269 * to provide a linear list of unnested caret boxes.
270 *
271 * \code
272 * Example: The document fragment <p>a <i><b>c</b> f</i> g</p> will be
273 * represented by three caret box lines which each one consists of caret boxes
274 * as follows:
275 * CaretBoxLine 1:
276 * CaretBox(cb=<p>, _box=0, _outside=true, outside_end=false)
277 * CaretBoxLine 2:
278 * CaretBox(cb=<p>, _box=InlineTextBox("a "), _outside=false)
279 * CaretBox(cb=<p>, _box=InlineFlowBox(<i>), _outside=true, outside_end=false)
280 * CaretBox(cb=<p>, _box=InlineFlowBox(<b>), _outside=true, outside_end=false)
281 * CaretBox(cb=<p>, _box=InlineTextBox("c"), _outside=false)
282 * CaretBox(cb=<p>, _box=InlineFlowBox(<b>), _outside=true, outside_end=true)
283 * CaretBox(cb=<p>, _box=InlineTextBox(" f"), _outside=false)
284 * CaretBox(cb=<p>, _box=InlineFlowBox(<i>), _outside=true, outside_end=true)
285 * CaretBox(cb=<p>, _box=InlineTextBox(" g"), _outside=true, outside_end=true)
286 * CaretBoxLine 3:
287 * CaretBox(cb=<p>, _box=0, _outside=true, outside_end=true)
288 * \endcode
289 */
290class CaretBoxLine {
291protected:
292 CaretBoxDeleter caret_boxes;
293 // base flow box which caret boxes have been constructed for
294 InlineFlowBox *basefb;
295
296 CaretBoxLine() : caret_boxes(8), basefb(0) {}
297 CaretBoxLine(InlineFlowBox *basefb) : caret_boxes(8), basefb(basefb) {}
298public:
299#if DEBUG_CARETMODE > 3
300 ~CaretBoxLine() { kDebug(6200) << "called"; }
301#endif
302
303 CaretBoxIterator begin()
304 {
305 CaretBoxIterator it;
306 it.cbl = this;
307 it.index = 0;
308 return it;
309 }
310 CaretBoxIterator end()
311 {
312 CaretBoxIterator it;
313 it.cbl = this;
314 it.index = caret_boxes.size();
315 return it;
316 }
317 CaretBoxIterator preBegin()
318 {
319 CaretBoxIterator it;
320 it.cbl = this;
321 it.index = -1;
322 return it;
323 }
324 CaretBoxIterator preEnd()
325 {
326 CaretBoxIterator it;
327 it.cbl = this;
328 it.index = caret_boxes.size() - 1;
329 return it;
330 }
331
332 /** returns the base inline flow box which the caret boxes of this
333 * caret box line have been constructed from.
334 *
335 * This is generally a root line box, but may be an inline flow box when the
336 * base is restricted to an inline element.
337 */
338 InlineFlowBox *baseFlowBox() const { return basefb; }
339
340 /** returns the containing block */
341 RenderBlock *containingBlock() const { return caret_boxes[0]->containingBlock(); }
342 /** returns the enclosing object */
343 RenderBox *enclosingObject() const { return caret_boxes[0]->enclosingObject(); }
344
345 /** returns whether this caret box line is outside.
346 * @return true if this caret box represents an outside position of this
347 * line box' containing block, false otherwise.
348 */
349 bool isOutside() const
350 {
351 const CaretBox *cbox = caret_boxes[0];
352 return !cbox->isInline() && cbox->isOutside();
353 }
354
355 /** returns whether this caret box line is at the outside end.
356 *
357 * The result cannot be relied upon unless isOutside() returns true.
358 */
359 bool isOutsideEnd() const { return caret_boxes[0]->isOutsideEnd(); }
360
361 /** constructs a new caret box line out of the given inline flow box
362 * @param deleter deleter which handles alloc+dealloc of the object
363 * @param baseFlowBox basic flow box which to create a caret line box from
364 * @param seekBox seek this box within the constructed line
365 * @param seekOutside denoting whether position is outside of seekBox
366 * @param seekOutsideEnd whether at the outside end of seekBox
367 * @param iter returns an iterator that corresponds to seekBox. If no suitable
368 * caret box exists, it will return end()
369 * @param seekObject seek this render object within the constructed line.
370 * It will only be regarded if \c seekBox is 0. \c iter will then point
371 * to the first caret box whose render object matches.
372 */
373 static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter,
374 InlineFlowBox *baseFlowBox, InlineBox *seekBox, bool seekOutside,
375 bool seekOutsideEnd, CaretBoxIterator &iter,
376 RenderObject *seekObject = 0) /*KDE_NO_EXPORT*/;
377
378 /** constructs a new caret box line for the given render block.
379 * @param deleter deleter which handles alloc+dealloc of the object
380 * @param cb render block or render replaced
381 * @param outside true when line is to be constructed outside
382 * @param outsideEnd true when the ending outside is meant
383 * @param iter returns the iterator to the caret box representing the given
384 * position for \c cb
385 */
386 static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter,
387 RenderBox *cb, bool outside, bool outsideEnd, CaretBoxIterator &iter) /*KDE_NO_EXPORT*/;
388
389#if DEBUG_CARETMODE > 0
390 void dump(QTextStream &ts, const QString &ind) const;
391 QString information() const
392 {
393 QString result;
394 QTextStream ts(&result, QIODevice::WriteOnly);
395 dump(ts, QString());
396 return result;
397 }
398#endif
399
400protected:
401 /** contains the seek parameters */
402 struct SeekBoxParams {
403 InlineBox *box;
404 bool outside;
405 bool outsideEnd;
406 bool found;
407 RenderObject *r; // if box is 0, seek for equal render objects instead
408 CaretBoxIterator &it;
409
410 SeekBoxParams(InlineBox *box, bool outside, bool outsideEnd, RenderObject *obj, CaretBoxIterator &it)
411 : box(box), outside(outside), outsideEnd(outsideEnd), found(false), r(obj), it(it)
412 {}
413
414 /** compares whether this seek box matches the given specification */
415 bool equalsBox(const InlineBox *box, bool outside, bool outsideEnd) const
416 {
417 return (this->box && this->box == box
418 || this->r == box->object())
419 && this->outside == outside
420 && (!this->outside || this->outsideEnd == outsideEnd);
421 }
422 /** compares whether this seek box matches the given caret box */
423 bool operator ==(const CaretBox *cbox) const
424 {
425 return equalsBox(cbox->inlineBox(), cbox->isOutside(), cbox->isOutsideEnd());
426 }
427 /** checks whether this box matches the given iterator.
428 *
429 * On success, it sets \c found, and assigns the iterator to \c it.
430 * @return true on match
431 */
432 bool check(const CaretBoxIterator &chit)
433 {
434 if (*this == *chit) {
435 Q_ASSERT(!found);
436 found = true;
437 it = chit;
438 }
439 return found;
440 }
441 };
442
443 /** recursively converts the given inline box into caret boxes and adds them
444 * to this caret box line.
445 *
446 * It will additionally look for the caret box specified in SeekBoxParams.
447 */
448 void addConvertedInlineBox(InlineBox *, SeekBoxParams &) /*KDE_NO_EXPORT*/;
449
450 /** creates and adds the edge of a generic inline box
451 * @param box inline box
452 * @param fm font metrics of inline box
453 * @param left true to add left edge, false to add right edge
454 * @param rtl true if direction is rtl
455 */
456 void addCreatedInlineBoxEdge(InlineBox *box, const QFontMetrics &fm,
457 bool left, bool rtl) /*KDE_NO_EXPORT*/;
458 /** creates and adds the edge of an inline flow box
459 * @param flowBox inline flow box
460 * @param fm font metrics of inline flow box
461 * @param left true to add left edge, false to add right edge
462 * @param rtl true if direction is rtl
463 */
464 void addCreatedFlowBoxEdge(InlineFlowBox *flowBox, const QFontMetrics &fm,
465 bool left, bool rtl) /*KDE_NO_EXPORT*/;
466 /** creates and adds the inside of an inline flow box
467 * @param flowBox inline flow box
468 * @param fm font metrics of inline flow box
469 */
470 void addCreatedFlowBoxInside(InlineFlowBox *flowBox, const QFontMetrics &fm) /*KDE_NO_EXPORT*/;
471
472 friend class CaretBoxIterator;
473};
474
475typedef MassDeleter<CaretBoxLine> CaretBoxLineDeleter;
476
477inline CaretBox *CaretBoxIterator::data() const { return cbl->caret_boxes[index]; }
478
479/**
480 * Iterates through the lines of a document.
481 *
482 * The line iterator becomes invalid when the associated LinearDocument object
483 * is destroyed.
484 * @internal
485 * @author Leo Savernik
486 */
487class LineIterator
488{
489protected:
490 LinearDocument *lines; // associated document
491 CaretBoxLine *cbl; // current caret box line
492
493 static CaretBoxIterator currentBox; // current inline box
494 static long currentOffset;
495
496 // Note: cbl == 0 indicates a position beyond the beginning or the
497 // end of a document.
498
499 /** Default constructor, only for internal use
500 */
501 LineIterator() {}
502
503 /** Initializes a new iterator.
504 *
505 * Note: This constructor neither cares about the correctness of @p node
506 * nor about @p offset. It is the responsibility of the caller to ensure
507 * that both point to valid places.
508 */
509 LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset);
510
511public:
512 /** dereferences current caret box line.
513 *
514 * @returns the caret line box or 0 if end of document
515 */
516 CaretBoxLine *operator *() const { return cbl; }
517
518 /** returns the associated linear document
519 */
520 LinearDocument *linearDocument() const { return lines; }
521
522 /** seek next line
523 *
524 * Guaranteed to crash if beyond beginning/end of document.
525 */
526 LineIterator &operator ++() { advance(false); return *this; }
527
528 /** seek previous line.
529 *
530 * Guaranteed to crash if beyond beginning/end of document.
531 */
532 LineIterator &operator --() { advance(true); return *this; }
533
534 /** compares two iterators. The comparator actually works only for
535 * comparing arbitrary iterators to begin() and end().
536 */
537 bool operator ==(const LineIterator &it) const
538 {
539 return lines == it.lines && cbl == it.cbl;
540 }
541
542 /** compares two iterators
543 */
544 bool operator !=(const LineIterator &it) const
545 {
546 return !operator ==(it);
547 }
548
549 /** Returns whether this line represents the outside end of the containing
550 * block.
551 *
552 * This result can only be relied on when isOutside is true.
553 */
554 bool isOutsideEnd() { return cbl->isOutsideEnd(); }
555
556 /** Tells whether the offset is meant to be outside or inside the
557 * containing block.
558 */
559 bool isOutside() const { return cbl->isOutside(); }
560
561 /** advances to the line to come.
562 * @param toBegin true, move to previous line, false, move to next line.
563 */
564 void advance(bool toBegin);
565
566 /** Whenever a new line iterator is created, it gets a caret box created.
567 * For memory reasons, it's saved in a static instance,
568 * thus making this function not thread-safe.
569 *
570 * This value can only be trusted immediately after having instantiated
571 * a line iterator or one of its derivatives.
572 * @return an iterator onto the corresponing caret box within the
573 * line represented by the last instantiation of a line iterator,
574 * or 0 if there was none.
575 */
576 static CaretBoxIterator &currentCaretBox() { return currentBox; }
577
578 /** Whenever a new line iterator is created, it calculates a modified offset
579 * that is to be used with respect to the current render object.
580 * This offset can be queried with this function.
581 *
582 * This value can only be trusted immediately after having instantiated
583 * a line iterator or one of its derivatives.
584 * @return the modified offset.
585 */
586 static long currentModifiedOffset() { return currentOffset; }
587
588protected:
589 /** seeks next block.
590 */
591 void nextBlock();
592 /** seeks previous block.
593 */
594 void prevBlock();
595
596 friend class CaretBoxIterator;
597 friend class EditableLineIterator;
598 friend class EditableCaretBoxIterator;
599 friend class EditableCharacterIterator;
600 friend class LinearDocument;
601};
602
603/**
604 * Represents the whole document in terms of lines.
605 *
606 * SGML documents are trees. But for navigation, this representation is
607 * not practical. Therefore this class serves as a helper to represent the
608 * document as a linear list of lines. Its usage somewhat resembles STL
609 * semantics like begin and end as well as iterators.
610 *
611 * The lines itself are represented as caret line boxes.
612 *
613 * LinearDocument instances are not meant to be kept over the lifetime of their
614 * associated document, but constructed from (node, offset) pairs whenever line
615 * traversal is needed. This is because the underlying InlineFlowBox objects
616 * may be destroyed and recreated (e. g. by resizing the window, adding/removing
617 * elements).
618 *
619 * @author Leo Savernik
620 * @internal
621 */
622class LinearDocument {
623public:
624 typedef LineIterator Iterator;
625
626 /**
627 * Creates a new instance, and initializes it to the line specified by
628 * the parameters below.
629 *
630 * Creation will fail if @p node is invisible or defect.
631 * @param part part within which everything is taking place.
632 * @param node document node with which to start
633 * @param offset zero-based offset within this node.
634 * @param advancePolicy caret advance policy
635 * @param baseElem base element which the caret must not advance beyond
636 * (0 means whole document). The base element will be ignored if it
637 * cannot serve as a base (to see if this is the case, check whether
638 * LinearDocument::baseFlow()->element() != base)
639 */
640 LinearDocument(KHTMLPart *part, DOM::NodeImpl *node, long offset,
641 CaretAdvancePolicy advancePolicy, DOM::ElementImpl *baseElem);
642
643 virtual ~LinearDocument();
644
645 /**
646 * Tells whether this list contains any lines.
647 *
648 * @returns @p true if this document contains lines, @p false otherwise. Note
649 * that an empty document contains at least one line, so this method
650 * only returns @p false if the document could not be initialised for
651 * some reason.
652 */
653 bool isValid() const // FIXME: not yet impl'd
654 {
655 return true;
656 }
657
658 /**
659 * Returns the count of lines.
660 *
661 * Warning: This function is expensive. Call it once and cache the value.
662 *
663 * FIXME: It's not implemented yet (and maybe never will)
664 */
665 int count() const;
666
667 /**
668 * Returns a line iterator containing the current position as its starting
669 * value.
670 */
671 Iterator current();
672
673 /**
674 * Returns a line iterator pointing right after the end of the document.
675 */
676 const Iterator &end() const { return _end; }
677
678 /**
679 * Returns a line iterator pointing to the very last line of the document.
680 */
681 Iterator preEnd();
682
683 /**
684 * Returns a line iterator pointing to the very first line of the document.
685 */
686 Iterator begin();
687
688 /**
689 * Returns a line iterator pointing just before the very first line of the
690 * document (this is somewhat an emulation of reverse iterators).
691 */
692 const Iterator &preBegin() const { return _preBegin; }
693
694 /**
695 * Returns the current caret advance policy
696 */
697 CaretAdvancePolicy advancePolicy() const { return advPol; }
698
699 /**
700 * Returns the base render object which the caret must not advance beyond.
701 *
702 * Note that HTML documents are usually restricted to the body element.
703 *
704 * @return the base render object or 0 if the whole document is valid.
705 */
706 RenderObject *baseObject() const { return base; }
707
708protected:
709 void initPreBeginIterator();
710 void initEndIterator();
711
712protected:
713 CaretBoxLineDeleter cblDeleter; // mass deleter for caret box lines
714 DOM::NodeImpl *node;
715 long offset;
716
717 Iterator _preBegin;
718 Iterator _end;
719
720 KHTMLPart *m_part;
721 CaretAdvancePolicy advPol;
722 RenderObject *base;
723
724 friend class LineIterator;
725 friend class EditableLineIterator;
726 friend class ErgonomicEditableLineIterator;
727 friend class CaretBoxIterator;
728 friend class EditableCaretBoxIterator;
729 friend class EditableCharacterIterator;
730};
731
732/**
733 * Iterates over the editable inner elements of a caret line box.
734 *
735 * The incrementor will traverse all caret boxes according to the associated
736 * linear document's caret advance policy. In contrast to \c CaretBoxIterator
737 * this iterator only regards caret boxes which are editable.
738 *
739 * @author Leo Savernik
740 * @internal
741 */
742class EditableCaretBoxIterator : public CaretBoxIterator {
743 KHTMLPart *m_part;
744 bool adjacent;
745 CaretAdvancePolicy advpol; // caret advance policy
746
747public:
748 /** initializes a new iterator from the given line iterator,
749 * beginning with the given caret box iterator, if specified
750 */
751 EditableCaretBoxIterator(LineIterator &lit, bool fromEnd = false,
752 CaretBoxIterator *it = 0)
753 : CaretBoxIterator(it ? *it : (fromEnd ? (*lit)->end() : (*lit)->preBegin())),
754 m_part(lit.lines->m_part), adjacent(false),
755 advpol(lit.lines->advancePolicy())
756 {
757 if (!it) {
758 if (fromEnd) --*this; else ++*this;
759 }
760 }
761
762 /** empty constructor. Use only to copy another iterator into this one.
763 */
764 EditableCaretBoxIterator() {}
765
766 /** returns @p true when the current caret box is adjacent to the
767 * previously iterated caret box, i. e. no intervening caret boxes.
768 */
769 bool isAdjacent() const { return adjacent; }
770
771 /** increments the iterator to point to the next editable caret box.
772 */
773 EditableCaretBoxIterator &operator ++() { advance(false); return *this; }
774
775 /** decrements the iterator to point to the previous editable caret box.
776 */
777 EditableCaretBoxIterator &operator --() { advance(true); return *this; }
778
779 /** advances to the editable caret box to come
780 * @param toBegin true, move towards beginning, false, move towards end.
781 */
782 void advance(bool toBegin);
783
784protected:
785 /** finds out if the given box is editable.
786 * @param boxit iterator to given caret box
787 * @param fromEnd true when advancing towards the beginning
788 * @return @p true if box is editable
789 */
790 bool isEditable(const CaretBoxIterator &boxit, bool fromEnd);
791};
792
793/**
794 * Iterates through the editable lines of a document.
795 *
796 * This iterator, opposing to @p LineIterator, only regards editable lines.
797 * Additionally, this iterator enforces the caret advance policy.
798 *
799 * The iterator can be compared to normal LineIterators, especially to
800 * @ref LinearDocument::preBegin and @ref LinearDocument::end
801 *
802 * The line iterator becomes invalid when the associated LinearDocument object
803 * is destroyed.
804 * @internal
805 * @author Leo Savernik
806 */
807class EditableLineIterator : public LineIterator {
808public:
809 /** Initializes a new iterator.
810 *
811 * The iterator is set to the first following editable line or to the
812 * end if no editable line follows.
813 * @param it a line iterator to initialize this from
814 * @param fromEnd @p true, traverse towards the beginning in search of an
815 * editable line
816 */
817 EditableLineIterator(const LineIterator &it, bool fromEnd = false)
818 : LineIterator(it)
819 {
820 if (!cbl) return;
821 if (!isEditable(*this)) advance(fromEnd);
822 }
823
824 /** empty constructor.
825 *
826 * Only use if you want to copy another iterator onto it later.
827 */
828 EditableLineIterator() {}
829
830 /** seek next line
831 *
832 * Guaranteed to crash if beyond beginning/end of document.
833 */
834 EditableLineIterator &operator ++() { advance(false); return *this; }
835
836 /** seek previous line.
837 *
838 * Guaranteed to crash if beyond beginning/end of document.
839 */
840 EditableLineIterator &operator --() { advance(true); return *this; }
841
842 /** advances to the line to come.
843 * @param toBegin true, move to previous line, false, move to next line.
844 */
845 void advance(bool toBegin);
846
847protected:
848 /** finds out if the current line is editable.
849 *
850 * @param it check caret box line iterator points to
851 * @return @p true if line is editable
852 */
853 bool isEditable(LineIterator &it)
854 {
855 EditableCaretBoxIterator fbit = it;
856 return fbit != (*it)->end();
857 }
858
859};
860
861/** Represents a render table as a linear list of rows.
862 *
863 * This iterator abstracts from table sections and treats tables as a linear
864 * representation of all rows they contain.
865 * @author Leo Savernik
866 * @internal
867 */
868class TableRowIterator {
869protected:
870 TableSectionIterator sec; // current section
871 int index; // index of row within section
872public:
873 /** Constructs a new iterator.
874 * @param table table to iterate through.
875 * @param fromEnd @p true to iterate towards the beginning
876 * @param row pointer to row to start with, 0 starts at the first/last
877 * row.
878 */
879 TableRowIterator(RenderTable *table, bool fromEnd = false,
880 RenderTableSection::RowStruct *row = 0);
881
882 /** Constructs a new iterator.
883 * @param section table section to begin with
884 * @param index index within table section
885 */
886 TableRowIterator(RenderTableSection *section, int index)
887 : sec(section), index(index)
888 {}
889
890 /** empty constructor. This must be assigned another iterator before it is
891 * useable.
892 */
893 TableRowIterator() {}
894
895 /** returns the current table row.
896 * @return the row or 0 if the end of the table has been reached.
897 */
898 RenderTableSection::RowStruct *operator *()
899 {
900 if (!*sec) return 0;
901 return &(*sec)->grid[index];
902 }
903
904 /** advances to the next row
905 */
906 TableRowIterator &operator ++();
907
908 /** advances to the previous row
909 */
910 TableRowIterator &operator --();
911
912protected:
913};
914
915/** Iterates through the editable lines of a document, in a topological order.
916 *
917 * The differences between this and the EditableLineIterator lies in the way
918 * lines are inquired. While the latter steps through the lines in document
919 * order, the former takes into consideration ergonomics.
920 *
921 * This is especially useful for tables. EditableLineIterator traverses all
922 * table cells from left to right, top to bottom, while this one will
923 * actually snap to the cell in the right position, and traverse only
924 * upwards/downwards, thus providing a more intuitive navigation.
925 *
926 * @author Leo Savernik
927 * @internal
928 */
929class ErgonomicEditableLineIterator : public EditableLineIterator {
930protected:
931 int xCoor; // x-coordinate to determine cell position
932public:
933 /** Initializes a new ergonomic editable line iterator from the given one.
934 * @param it line iterator
935 * @param x absolute x-coordinate for cell determination
936 */
937 ErgonomicEditableLineIterator(const LineIterator &it, int x)
938 : EditableLineIterator(it), xCoor(x) {}
939
940 /** Constructs an uninitialized iterator which must be assigned a line iterator before
941 * it can be used.
942 */
943 ErgonomicEditableLineIterator() {}
944
945 /** seek next line.
946 *
947 * The next line will be one that is visually situated below this line.
948 */
949 ErgonomicEditableLineIterator &operator ++();
950
951 /** seek previous line.
952 *
953 * The previous line will be one that is visually situated above this line.
954 */
955 ErgonomicEditableLineIterator &operator --();
956
957protected:
958 /** determines the topologically next render object.
959 * @param oldCell table cell the original object was under.
960 * @param newObject object to determine whether and which transition
961 * between cells is to be handled. It does not have to be an object in the correct
962 * topological cell, a simple delivery from an editable line iterator suffices.
963 * @param toBegin if @p true, iterate towards the beginning
964 */
965 void determineTopologicalElement(RenderTableCell *oldCell,
966 RenderObject *newObject, bool toBegin);
967
968 /** initializes the iterator to point to the first previous/following editable
969 * line.
970 * @param newBlock take this as base block.
971 * @param toBegin @p true, iterate towards beginning.
972 */
973 void calcAndStoreNewLine(RenderBlock *newBlock, bool toBegin);
974
975};
976
977/**
978 * Provides iterating through the document in terms of characters. Only the
979 * editable characters are regarded.
980 *
981 * This iterator represents the document, which is structured as a tree itself,
982 * as a linear stream of characters.
983 */
984class EditableCharacterIterator {
985protected:
986 EditableLineIterator _it;
987 EditableCaretBoxIterator ebit;
988 long _offset; // offset within current caret box.
989 int _char;
990 bool _end:1; // true when end of document has been reached
991
992public:
993
994 /** empty constructor.
995 *
996 * Only use if you want to assign another iterator as no fields will
997 * be initialized.
998 */
999 EditableCharacterIterator() {}
1000
1001 /** constructs a new iterator from the given linear document.
1002 *
1003 * @param ld linear representation of document.
1004 */
1005 EditableCharacterIterator(LinearDocument *ld)
1006 : _it(ld->current()),
1007 ebit(_it, false, &_it.currentCaretBox()),
1008 _offset(_it.currentModifiedOffset()), _char(-1), _end(false)
1009 {
1010 // ### temporary fix for illegal nodes
1011 if (_it == ld->end()) { _end = true; return; }
1012 initFirstChar();
1013 }
1014
1015 /** returns the current character, or -1 if not on a text node, or beyond
1016 * the end.
1017 */
1018 int chr() const { return _char; }
1019
1020 /** returns the current character as a unicode symbol, substituting
1021 * a blank for a non-text node.
1022 */
1023 QChar operator *() const { return QChar(_char >= 0 ? _char : ' '); }
1024
1025 /** returns true when the end of the document has been reached.
1026 */
1027 bool isEnd() const { return _end; }
1028 /** returns the current offset
1029 */
1030 long offset() const { return _offset; }
1031 /** returns the current render object.
1032 */
1033 RenderObject *renderer() const { return (*ebit)->object(); }
1034 /** returns the current caret box.
1035 *
1036 * Will crash if beyond end.
1037 */
1038 CaretBox *caretBox() const { return *ebit; }
1039 /** returns the current inline box.
1040 *
1041 * May be 0 if the current element has none, or if the end has been reached.
1042 * Therefore, do *not* use this to test for the end condition, use node()
1043 * instead.
1044 */
1045 InlineBox *inlineBox() const { return (*ebit)->inlineBox(); }
1046 /** returns whether the current line box represents the outside of its
1047 * render object.
1048 */
1049// bool boxIsOutside() const { return _it.isOutside(); }
1050
1051 /** moves to the next editable character.
1052 */
1053 EditableCharacterIterator &operator ++();
1054
1055 /** moves to the previous editable character.
1056 */
1057 EditableCharacterIterator &operator --();
1058
1059protected:
1060 /** initializes the _char member by reading the character at the current
1061 * offset, peeking ahead as necessary.
1062 */
1063 void initFirstChar();
1064 /** reads ahead the next node and updates the data structures accordingly
1065 */
1066 void peekNext()
1067 {
1068 EditableCaretBoxIterator copy = ebit;
1069 ++copy;
1070 if (copy == (*_it)->end()) { _char = -1; return; }
1071
1072 CaretBox *box = *copy;
1073 InlineBox *b = box->inlineBox();
1074 if (b && !box->isOutside() && b->isInlineTextBox())
1075 _char = static_cast<RenderText *>(b->object())->str->s[b->minOffset()].unicode();
1076 else
1077 _char = -1;
1078 }
1079 /** reads ahead the previous node and updates the data structures accordingly
1080 */
1081 void peekPrev()
1082 {
1083 --ebit;
1084 }
1085
1086};
1087
1088
1089}/*namespace khtml*/
1090
1091
1092#endif
1093

Warning: That file was not part of the compilation database. It may have many parsing errors.