KHTML
khtml_caret_p.h
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2003-2004 Leo Savernik <l.savernik@aon.at> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #ifndef KHTML_CARET_P_H 00022 #define KHTML_CARET_P_H 00023 00024 #include "rendering/render_table.h" 00025 00026 00027 #define DEBUG_CARETMODE 0 00028 00029 class QFontMetrics; 00030 00031 namespace DOM { 00032 class NodeImpl; 00033 class ElementImpl; 00034 } 00035 00036 namespace khtml { 00037 00053 enum CaretAdvancePolicy { 00054 LeafsOnly, IndicatedFlows, VisibleFlows 00055 }; 00056 00060 struct CaretViewContext { 00061 int freqTimerId; // caret blink frequency timer id 00062 int x, y; // caret position in viewport coordinates 00063 // (y specifies the top, not the baseline) 00064 int width; // width of caret in pixels 00065 int height; // height of caret in pixels 00066 bool visible; // true if currently visible. 00067 bool displayed; // true if caret is to be displayed at all. 00068 bool caretMoved; // set to true once caret has been moved in page 00069 // how to display the caret when view is not focused 00070 KHTMLPart::CaretDisplayPolicy displayNonFocused; 00071 00079 int origX; 00080 00081 bool keyReleasePending; // true if keypress under caret mode awaits 00082 // corresponding release event 00083 CaretViewContext() : freqTimerId(-1), x(0), y(0), width(1), height(16), 00084 visible(true), displayed(false), caretMoved(false), 00085 displayNonFocused(KHTMLPart::CaretInvisible), origX(0), 00086 keyReleasePending(false) 00087 {} 00088 }; 00089 00090 class LinearDocument; 00091 00102 template<class T> class MassDeleter : public QVector<T *> { 00103 public: 00104 MassDeleter(size_t reserved = 1) { this->reserve(reserved); } 00105 ~MassDeleter() 00106 { 00107 typename QVector<T *>::Iterator nd = this->end(); 00108 for (typename QVector<T *>::Iterator it = this->begin(); it != nd; ++it) 00109 delete *it; 00110 } 00111 }; 00112 00113 class CaretBoxLine; 00114 00126 class CaretBox { 00127 protected: 00128 InlineBox *_box; // associated inline box if available. 00129 short _w; // width of box in pixels 00130 int _h; // height of box in pixels 00131 int _x; // x coordinate relative to containing block 00132 int _y; // y coordinate relative to containing block 00133 RenderBox *cb; // containing block 00134 bool _outside:1; // true when representing the outside of the element 00135 bool outside_end:1; // at ending outside of element rather than at beginning 00136 // 29 bits unused 00137 00138 public: 00140 CaretBox() {} 00142 CaretBox(InlineBox *ibox, bool outside, bool outsideEnd) : _box(ibox), 00143 _w((short)ibox->width()), _h(ibox->height()), _x(ibox->xPos()), 00144 _y(ibox->yPos()), cb(0), _outside(outside), outside_end(outsideEnd) 00145 { 00146 RenderObject *r = ibox->object(); 00147 if (r) cb = r->containingBlock(); 00148 } 00150 CaretBox(int x, int y, int w, int h, RenderBox *cb, bool outside, bool outsideEnd) : 00151 _box(0), _w((short)w), _h(h), _x(x), _y(y), cb(cb), _outside(outside), 00152 outside_end(outsideEnd) 00153 {} 00154 00155 int width() const { return _w; } 00156 int height() const { return _h; } 00157 int xPos() const { return _x; } 00158 int yPos() const { return _y; } 00159 RenderBox *enclosingObject() const { return cb; } 00160 InlineBox *inlineBox() const { return _box; } 00161 00165 RenderBlock *containingBlock() const { return _box ? static_cast<RenderBlock *>(cb) : cb->containingBlock(); } 00166 00175 bool isInline() const { return _box; } 00178 bool isInlineTextBox() const { return _box && _box->isInlineTextBox(); } 00181 bool isLineBreak() const 00182 { 00183 return _box && _box->object() && _box->object()->isBR(); 00184 } 00188 bool isOutside() const { return _outside; } 00195 bool isOutsideEnd() const { return outside_end; } 00197 RenderObject *object() const { return _box ? _box->object() : cb; } 00198 00201 long minOffset() const { return _box && !isLineBreak() ? _box->minOffset() : 0; } 00204 long maxOffset() const { return _box && !isLineBreak() ? _box->maxOffset() : 0; } 00205 00206 #if DEBUG_CARETMODE > 0 00207 void dump(QTextStream &ts, const QString &ind) const; 00208 #endif 00209 00210 friend class CaretBoxLine; 00211 }; 00212 00213 typedef MassDeleter<CaretBox> CaretBoxDeleter; 00214 00221 class CaretBoxIterator { 00222 protected: 00223 CaretBoxLine *cbl; // associated caret box line 00224 int index; // current index 00225 00226 public: 00227 // Let standard constructor/copy constructor/destructor/assignment operator 00228 // be defined by the compiler. They do exactly what we want. 00229 CaretBoxIterator() 00230 : cbl( 0 ), index( 0 ) 00231 { 00232 } 00233 00234 bool operator ==(const CaretBoxIterator &it) const 00235 { 00236 return cbl == it.cbl && index == it.index; 00237 } 00238 00239 bool operator !=(const CaretBoxIterator &it) const 00240 { 00241 return !operator ==(it); 00242 } 00243 00247 CaretBox *data() const; 00251 CaretBox *operator *() const { return data(); } 00252 00255 CaretBoxIterator &operator ++() { index++; return *this; } 00258 CaretBoxIterator &operator --() { index--; return *this; } 00259 00260 friend class CaretBoxLine; 00261 friend class EditableCaretBoxIterator; 00262 }; 00263 00290 class CaretBoxLine { 00291 protected: 00292 CaretBoxDeleter caret_boxes; 00293 // base flow box which caret boxes have been constructed for 00294 InlineFlowBox *basefb; 00295 00296 CaretBoxLine() : caret_boxes(8), basefb(0) {} 00297 CaretBoxLine(InlineFlowBox *basefb) : caret_boxes(8), basefb(basefb) {} 00298 public: 00299 #if DEBUG_CARETMODE > 3 00300 ~CaretBoxLine() { kDebug(6200) << "called"; } 00301 #endif 00302 00303 CaretBoxIterator begin() 00304 { 00305 CaretBoxIterator it; 00306 it.cbl = this; 00307 it.index = 0; 00308 return it; 00309 } 00310 CaretBoxIterator end() 00311 { 00312 CaretBoxIterator it; 00313 it.cbl = this; 00314 it.index = caret_boxes.size(); 00315 return it; 00316 } 00317 CaretBoxIterator preBegin() 00318 { 00319 CaretBoxIterator it; 00320 it.cbl = this; 00321 it.index = -1; 00322 return it; 00323 } 00324 CaretBoxIterator preEnd() 00325 { 00326 CaretBoxIterator it; 00327 it.cbl = this; 00328 it.index = caret_boxes.size() - 1; 00329 return it; 00330 } 00331 00338 InlineFlowBox *baseFlowBox() const { return basefb; } 00339 00341 RenderBlock *containingBlock() const { return caret_boxes[0]->containingBlock(); } 00343 RenderBox *enclosingObject() const { return caret_boxes[0]->enclosingObject(); } 00344 00349 bool isOutside() const 00350 { 00351 const CaretBox *cbox = caret_boxes[0]; 00352 return !cbox->isInline() && cbox->isOutside(); 00353 } 00354 00359 bool isOutsideEnd() const { return caret_boxes[0]->isOutsideEnd(); } 00360 00373 static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter, 00374 InlineFlowBox *baseFlowBox, InlineBox *seekBox, bool seekOutside, 00375 bool seekOutsideEnd, CaretBoxIterator &iter, 00376 RenderObject *seekObject = 0) /*KDE_NO_EXPORT*/; 00377 00386 static CaretBoxLine *constructCaretBoxLine(MassDeleter<CaretBoxLine> *deleter, 00387 RenderBox *cb, bool outside, bool outsideEnd, CaretBoxIterator &iter) /*KDE_NO_EXPORT*/; 00388 00389 #if DEBUG_CARETMODE > 0 00390 void dump(QTextStream &ts, const QString &ind) const; 00391 QString information() const 00392 { 00393 QString result; 00394 QTextStream ts(&result, QIODevice::WriteOnly); 00395 dump(ts, QString()); 00396 return result; 00397 } 00398 #endif 00399 00400 protected: 00402 struct SeekBoxParams { 00403 InlineBox *box; 00404 bool outside; 00405 bool outsideEnd; 00406 bool found; 00407 RenderObject *r; // if box is 0, seek for equal render objects instead 00408 CaretBoxIterator ⁢ 00409 00410 SeekBoxParams(InlineBox *box, bool outside, bool outsideEnd, RenderObject *obj, CaretBoxIterator &it) 00411 : box(box), outside(outside), outsideEnd(outsideEnd), found(false), r(obj), it(it) 00412 {} 00413 00415 bool equalsBox(const InlineBox *box, bool outside, bool outsideEnd) const 00416 { 00417 return (this->box && this->box == box 00418 || this->r == box->object()) 00419 && this->outside == outside 00420 && (!this->outside || this->outsideEnd == outsideEnd); 00421 } 00423 bool operator ==(const CaretBox *cbox) const 00424 { 00425 return equalsBox(cbox->inlineBox(), cbox->isOutside(), cbox->isOutsideEnd()); 00426 } 00432 bool check(const CaretBoxIterator &chit) 00433 { 00434 if (*this == *chit) { 00435 Q_ASSERT(!found); 00436 found = true; 00437 it = chit; 00438 } 00439 return found; 00440 } 00441 }; 00442 00448 void addConvertedInlineBox(InlineBox *, SeekBoxParams &) /*KDE_NO_EXPORT*/; 00449 00456 void addCreatedInlineBoxEdge(InlineBox *box, const QFontMetrics &fm, 00457 bool left, bool rtl) /*KDE_NO_EXPORT*/; 00464 void addCreatedFlowBoxEdge(InlineFlowBox *flowBox, const QFontMetrics &fm, 00465 bool left, bool rtl) /*KDE_NO_EXPORT*/; 00470 void addCreatedFlowBoxInside(InlineFlowBox *flowBox, const QFontMetrics &fm) /*KDE_NO_EXPORT*/; 00471 00472 friend class CaretBoxIterator; 00473 }; 00474 00475 typedef MassDeleter<CaretBoxLine> CaretBoxLineDeleter; 00476 00477 inline CaretBox *CaretBoxIterator::data() const { return cbl->caret_boxes[index]; } 00478 00487 class LineIterator 00488 { 00489 protected: 00490 LinearDocument *lines; // associated document 00491 CaretBoxLine *cbl; // current caret box line 00492 00493 static CaretBoxIterator currentBox; // current inline box 00494 static long currentOffset; 00495 00496 // Note: cbl == 0 indicates a position beyond the beginning or the 00497 // end of a document. 00498 00501 LineIterator() {} 00502 00509 LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset); 00510 00511 public: 00516 CaretBoxLine *operator *() const { return cbl; } 00517 00520 LinearDocument *linearDocument() const { return lines; } 00521 00526 LineIterator &operator ++() { advance(false); return *this; } 00527 00532 LineIterator &operator --() { advance(true); return *this; } 00533 00537 bool operator ==(const LineIterator &it) const 00538 { 00539 return lines == it.lines && cbl == it.cbl; 00540 } 00541 00544 bool operator !=(const LineIterator &it) const 00545 { 00546 return !operator ==(it); 00547 } 00548 00554 bool isOutsideEnd() { return cbl->isOutsideEnd(); } 00555 00559 bool isOutside() const { return cbl->isOutside(); } 00560 00564 void advance(bool toBegin); 00565 00576 static CaretBoxIterator ¤tCaretBox() { return currentBox; } 00577 00586 static long currentModifiedOffset() { return currentOffset; } 00587 00588 protected: 00591 void nextBlock(); 00594 void prevBlock(); 00595 00596 friend class CaretBoxIterator; 00597 friend class EditableLineIterator; 00598 friend class EditableCaretBoxIterator; 00599 friend class EditableCharacterIterator; 00600 friend class LinearDocument; 00601 }; 00602 00622 class LinearDocument { 00623 public: 00624 typedef LineIterator Iterator; 00625 00640 LinearDocument(KHTMLPart *part, DOM::NodeImpl *node, long offset, 00641 CaretAdvancePolicy advancePolicy, DOM::ElementImpl *baseElem); 00642 00643 virtual ~LinearDocument(); 00644 00653 bool isValid() const // FIXME: not yet impl'd 00654 { 00655 return true; 00656 } 00657 00665 int count() const; 00666 00671 Iterator current(); 00672 00676 const Iterator &end() const { return _end; } 00677 00681 Iterator preEnd(); 00682 00686 Iterator begin(); 00687 00692 const Iterator &preBegin() const { return _preBegin; } 00693 00697 CaretAdvancePolicy advancePolicy() const { return advPol; } 00698 00706 RenderObject *baseObject() const { return base; } 00707 00708 protected: 00709 void initPreBeginIterator(); 00710 void initEndIterator(); 00711 00712 protected: 00713 CaretBoxLineDeleter cblDeleter; // mass deleter for caret box lines 00714 DOM::NodeImpl *node; 00715 long offset; 00716 00717 Iterator _preBegin; 00718 Iterator _end; 00719 00720 KHTMLPart *m_part; 00721 CaretAdvancePolicy advPol; 00722 RenderObject *base; 00723 00724 friend class LineIterator; 00725 friend class EditableLineIterator; 00726 friend class ErgonomicEditableLineIterator; 00727 friend class CaretBoxIterator; 00728 friend class EditableCaretBoxIterator; 00729 friend class EditableCharacterIterator; 00730 }; 00731 00742 class EditableCaretBoxIterator : public CaretBoxIterator { 00743 KHTMLPart *m_part; 00744 bool adjacent; 00745 CaretAdvancePolicy advpol; // caret advance policy 00746 00747 public: 00751 EditableCaretBoxIterator(LineIterator &lit, bool fromEnd = false, 00752 CaretBoxIterator *it = 0) 00753 : CaretBoxIterator(it ? *it : (fromEnd ? (*lit)->end() : (*lit)->preBegin())), 00754 m_part(lit.lines->m_part), adjacent(false), 00755 advpol(lit.lines->advancePolicy()) 00756 { 00757 if (!it) { 00758 if (fromEnd) --*this; else ++*this; 00759 } 00760 } 00761 00764 EditableCaretBoxIterator() {} 00765 00769 bool isAdjacent() const { return adjacent; } 00770 00773 EditableCaretBoxIterator &operator ++() { advance(false); return *this; } 00774 00777 EditableCaretBoxIterator &operator --() { advance(true); return *this; } 00778 00782 void advance(bool toBegin); 00783 00784 protected: 00790 bool isEditable(const CaretBoxIterator &boxit, bool fromEnd); 00791 }; 00792 00807 class EditableLineIterator : public LineIterator { 00808 public: 00817 EditableLineIterator(const LineIterator &it, bool fromEnd = false) 00818 : LineIterator(it) 00819 { 00820 if (!cbl) return; 00821 if (!isEditable(*this)) advance(fromEnd); 00822 } 00823 00828 EditableLineIterator() {} 00829 00834 EditableLineIterator &operator ++() { advance(false); return *this; } 00835 00840 EditableLineIterator &operator --() { advance(true); return *this; } 00841 00845 void advance(bool toBegin); 00846 00847 protected: 00853 bool isEditable(LineIterator &it) 00854 { 00855 EditableCaretBoxIterator fbit = it; 00856 return fbit != (*it)->end(); 00857 } 00858 00859 }; 00860 00868 class TableRowIterator { 00869 protected: 00870 TableSectionIterator sec; // current section 00871 int index; // index of row within section 00872 public: 00879 TableRowIterator(RenderTable *table, bool fromEnd = false, 00880 RenderTableSection::RowStruct *row = 0); 00881 00886 TableRowIterator(RenderTableSection *section, int index) 00887 : sec(section), index(index) 00888 {} 00889 00893 TableRowIterator() {} 00894 00898 RenderTableSection::RowStruct *operator *() 00899 { 00900 if (!*sec) return 0; 00901 return &(*sec)->grid[index]; 00902 } 00903 00906 TableRowIterator &operator ++(); 00907 00910 TableRowIterator &operator --(); 00911 00912 protected: 00913 }; 00914 00929 class ErgonomicEditableLineIterator : public EditableLineIterator { 00930 protected: 00931 int xCoor; // x-coordinate to determine cell position 00932 public: 00937 ErgonomicEditableLineIterator(const LineIterator &it, int x) 00938 : EditableLineIterator(it), xCoor(x) {} 00939 00943 ErgonomicEditableLineIterator() {} 00944 00949 ErgonomicEditableLineIterator &operator ++(); 00950 00955 ErgonomicEditableLineIterator &operator --(); 00956 00957 protected: 00965 void determineTopologicalElement(RenderTableCell *oldCell, 00966 RenderObject *newObject, bool toBegin); 00967 00973 void calcAndStoreNewLine(RenderBlock *newBlock, bool toBegin); 00974 00975 }; 00976 00984 class EditableCharacterIterator { 00985 protected: 00986 EditableLineIterator _it; 00987 EditableCaretBoxIterator ebit; 00988 long _offset; // offset within current caret box. 00989 int _char; 00990 bool _end:1; // true when end of document has been reached 00991 00992 public: 00993 00999 EditableCharacterIterator() {} 01000 01005 EditableCharacterIterator(LinearDocument *ld) 01006 : _it(ld->current()), 01007 ebit(_it, false, &_it.currentCaretBox()), 01008 _offset(_it.currentModifiedOffset()), _char(-1), _end(false) 01009 { 01010 // ### temporary fix for illegal nodes 01011 if (_it == ld->end()) { _end = true; return; } 01012 initFirstChar(); 01013 } 01014 01018 int chr() const { return _char; } 01019 01023 QChar operator *() const { return QChar(_char >= 0 ? _char : ' '); } 01024 01027 bool isEnd() const { return _end; } 01030 long offset() const { return _offset; } 01033 RenderObject *renderer() const { return (*ebit)->object(); } 01038 CaretBox *caretBox() const { return *ebit; } 01045 InlineBox *inlineBox() const { return (*ebit)->inlineBox(); } 01049 // bool boxIsOutside() const { return _it.isOutside(); } 01050 01053 EditableCharacterIterator &operator ++(); 01054 01057 EditableCharacterIterator &operator --(); 01058 01059 protected: 01063 void initFirstChar(); 01066 void peekNext() 01067 { 01068 EditableCaretBoxIterator copy = ebit; 01069 ++copy; 01070 if (copy == (*_it)->end()) { _char = -1; return; } 01071 01072 CaretBox *box = *copy; 01073 InlineBox *b = box->inlineBox(); 01074 if (b && !box->isOutside() && b->isInlineTextBox()) 01075 _char = static_cast<RenderText *>(b->object())->str->s[b->minOffset()].unicode(); 01076 else 01077 _char = -1; 01078 } 01081 void peekPrev() 01082 { 01083 --ebit; 01084 } 01085 01086 }; 01087 01088 01089 }/*namespace khtml*/ 01090 01091 01092 #endif
KDE 4.6 API Reference