00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "khtml_caret_p.h"
00023
00024 namespace khtml {
00025
00026 static InlineFlowBox *findFlowBox(DOM::NodeImpl *node, long offset,
00027 RenderArena *arena, RenderFlow *&cb, InlineBox **ibox = 0);
00028 static RenderObject *nextLeafRenderObject(RenderObject *r);
00029
00034 static inline RenderObject *nextSuitableLeafRenderObject(RenderObject *r)
00035 {
00036 do {
00037 r = nextLeafRenderObject(r);
00038 } while (r && r->isTableCol());
00039 return r;
00040 }
00041
00043 static void ensureLeafNode(NodeImpl *&node)
00044 {
00045 if (node && node->hasChildNodes()) node = node->nextLeafNode();
00046 }
00047
00056 static RenderObject* findRenderer(NodeImpl *&node)
00057 {
00058 if (!node) return 0;
00059 RenderObject *r = node->renderer();
00060 while (!r) {
00061 node = node->nextLeafNode();
00062 if (!node) break;
00063 r = node->renderer();
00064 }
00065 if (r && r->isTableCol()) r = nextSuitableLeafRenderObject(r);
00066 return r;
00067 }
00068
00070 static void sanitizeCaretState(NodeImpl *&caretNode, long &offset)
00071 {
00072 ensureLeafNode(caretNode);
00073
00074
00075
00076
00077
00078 NodeImpl *tmpNode = caretNode;
00079 if (findRenderer(tmpNode)) caretNode = tmpNode;
00080 if (!caretNode) return;
00081
00082 long max = caretNode->maxOffset();
00083 long min = caretNode->minOffset();
00084 if (offset < min) offset = min;
00085 else if (offset > max) offset = max;
00086 }
00087
00089 static RenderObject *prevLeafRenderObject(RenderObject *r)
00090 {
00091 RenderObject *n = r->objectAbove();
00092 while (n && n == r->parent()) {
00093 if (n->previousSibling()) return n->objectAbove();
00094 r = n;
00095 n = r->parent();
00096 }
00097 return n;
00098 }
00099
00101 static RenderObject *nextLeafRenderObject(RenderObject *r)
00102 {
00103 RenderObject *n = r->objectBelow();
00104 r = n;
00105 while (n) r = n, n = n->firstChild();
00106 return r;
00107 }
00108
00113 static RenderObject *prevSuitableLeafRenderObject(RenderObject *r)
00114 {
00115 do {
00116 r = prevLeafRenderObject(r);
00117 } while (r && r->isTableCol());
00118 return r;
00119 }
00120
00123 static inline InlineBox *seekLeafInlineBox(InlineBox *box)
00124 {
00125 while (box && box->isInlineFlowBox()) {
00126
00127 box = static_cast<InlineFlowBox *>(box)->firstChild();
00128
00129
00130
00131
00132 }
00133 return box;
00134 }
00135
00138 static inline InlineBox *seekLeafInlineBoxFromEnd(InlineBox *box)
00139 {
00140 while (box && box->isInlineFlowBox()) {
00141 box = static_cast<InlineFlowBox *>(box)->lastChild();
00142 }
00143 #if DEBUG_CARETMODE > 0
00144 kdDebug(6200) << "seekLeafFromEnd: box " << box << (box && box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << endl;
00145 #endif
00146 return box;
00147 }
00148
00149
00150
00151 InlineBox *LineIterator::currentBox;
00152
00153 InlineBoxIterator::InlineBoxIterator(RenderArena *arena, InlineFlowBox *flowBox, bool fromEnd)
00154 : arena(arena)
00155 {
00156 box = fromEnd ? seekLeafInlineBoxFromEnd(flowBox) : seekLeafInlineBox(flowBox);
00157 }
00158
00159 InlineBoxIterator::InlineBoxIterator(LineIterator &lit, bool fromEnd,
00160 InlineBox *initBox)
00161 : arena(lit.lines->arena)
00162 {
00163 if (initBox) box = initBox;
00164 else box = fromEnd ? seekLeafInlineBoxFromEnd(*lit) : seekLeafInlineBox(*lit);
00165 }
00166
00167
00168 InlineBoxIterator& InlineBoxIterator::operator ++()
00169 {
00170 InlineBox *newBox = box->nextOnLine();
00171
00172 if (newBox)
00173 box = seekLeafInlineBox(newBox);
00174 else {
00175 InlineFlowBox *flowBox = box->parent();
00176 box = 0;
00177 while (flowBox) {
00178 InlineBox *newBox2 = flowBox->nextOnLine();
00179 if (newBox2) {
00180 box = seekLeafInlineBox(newBox2);
00181 break;
00182 }
00183
00184 flowBox = flowBox->parent();
00185 }
00186 }
00187
00188 return *this;
00189 }
00190
00194 InlineBoxIterator& InlineBoxIterator::operator --()
00195 {
00196 InlineBox *newBox = box->prevOnLine();
00197
00198 if (newBox)
00199 box = seekLeafInlineBoxFromEnd(newBox);
00200 else {
00201 InlineFlowBox *flowBox = box->parent();
00202 box = 0;
00203 while (flowBox) {
00204 InlineBox *newBox2 = flowBox->prevOnLine();
00205 if (newBox2) {
00206 box = seekLeafInlineBoxFromEnd(newBox2);
00207 break;
00208 }
00209
00210 flowBox = flowBox->parent();
00211 }
00212 }
00213
00214 return *this;
00215 }
00216
00233 static InlineFlowBox* generateDummyFlowBox(RenderArena *arena, RenderFlow *cb,
00234 RenderObject *childNodeHint = 0)
00235 {
00236 InlineFlowBox *flowBox = new(arena) InlineFlowBox(cb);
00237 int width = cb->width();
00238
00239
00240
00241
00242
00243 int height = cb->style()->fontMetrics().height();
00244 flowBox->setWidth(0);
00245 flowBox->setHeight(height);
00246
00247
00248 InlineBox *child = new(arena) InlineBox(childNodeHint ? childNodeHint : cb);
00249
00250 switch (cb->style()->textAlign()) {
00251 case LEFT:
00252 case TAAUTO:
00253 case JUSTIFY:
00254 child->setXPos(0);
00255 break;
00256 case CENTER:
00257 case KONQ_CENTER:
00258 child->setXPos(width / 2);
00259 break;
00260 case RIGHT:
00261 child->setXPos(width);
00262 break;
00263 }
00264 child->setYPos(0);
00265 child->setWidth(1);
00266 child->setHeight(height);
00267
00268 flowBox->setXPos(child->xPos());
00269 flowBox->setYPos(child->yPos());
00270 flowBox->addToLine(child);
00271
00272 return flowBox;
00273 }
00274
00280 static RenderFlow* generateDummyBlock(RenderArena *, RenderObject *cb)
00281 {
00282
00283 RenderFlow *result = RenderFlow::createFlow(cb->element(), cb->style(), cb->renderArena());
00284 result->setParent(cb->parent());
00285 result->setPreviousSibling(cb->previousSibling());
00286 result->setNextSibling(cb->nextSibling());
00287
00288 result->setOverhangingContents(cb->overhangingContents());
00289 result->setPositioned(cb->isPositioned());
00290 result->setRelPositioned(cb->isRelPositioned());
00291 result->setFloating(cb->isFloating());
00292 result->setInline(cb->isInline());
00293 result->setMouseInside(cb->mouseInside());
00294
00295 result->setPos(cb->xPos(), cb->yPos());
00296 result->setWidth(cb->width());
00297 result->setHeight(cb->height());
00298
00299 return result;
00300 }
00301
00317 static InlineFlowBox* findFlowBox(DOM::NodeImpl *node, long offset,
00318 RenderArena *arena, RenderFlow *&cb, InlineBox **ibox)
00319 {
00320 RenderObject *r = findRenderer(node);
00321 if (!r) { cb = 0; return 0; }
00322 #if DEBUG_CARETMODE > 0
00323 kdDebug(6200) << "=================== findFlowBox" << endl;
00324 kdDebug(6200) << "node " << node << " r " << r->renderName() << "[" << r << "].node " << r->element()->nodeName().string() << "[" << r->element() << "]" << " offset: " << offset << endl;
00325 #endif
00326
00327
00328
00329
00330 if (r->isRenderBlock() && !static_cast<RenderBlock *>(r)->firstLineBox()) {
00331 cb = static_cast<RenderBlock *>(r);
00332 #if DEBUG_CARETMODE > 0
00333 kdDebug(6200) << "=================== end findFlowBox (dummy)" << endl;
00334 #endif
00335 InlineFlowBox *fb = generateDummyFlowBox(arena, cb);
00336 if (ibox) *ibox = fb;
00337 return fb;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 if (r->isText()) do {
00347 RenderText *t = static_cast<RenderText *>(r);
00348 int dummy;
00349 InlineBox *b = t->findInlineTextBox(offset, dummy, true);
00350
00351
00352
00353 if (!b) {
00354 if (t->m_lines.count() > 0)
00355 b = t->m_lines[t->m_lines.count() - 1];
00356 else
00357 break;
00358 }
00359 Q_ASSERT(b);
00360 if (ibox) *ibox = b;
00361 while (b->parent()) {
00362 b = b->parent();
00363 }
00364
00365 Q_ASSERT(b->isRootInlineBox());
00366 cb = static_cast<RenderFlow *>(b->object());
00367 Q_ASSERT(cb->isRenderBlock());
00368 #if DEBUG_CARETMODE > 0
00369 kdDebug(6200) << "=================== end findFlowBox (renderText)" << endl;
00370 #endif
00371 return static_cast<InlineFlowBox *>(b);
00372 } while(false);
00373
00374 cb = r->containingBlock();
00375 if ( !cb ) return 0L;
00376
00377 if (!cb->isRenderBlock()) {
00378 cb = generateDummyBlock(arena, cb);
00379 #if DEBUG_CARETMODE > 0
00380 kdDebug(6200) << "dummy block created: " << cb << endl;
00381 #endif
00382 }
00383
00384 InlineFlowBox *flowBox = cb->firstLineBox();
00385
00386
00387
00388 if (!flowBox) {
00389 flowBox = generateDummyFlowBox(arena, cb, r);
00390 if (ibox) *ibox = flowBox->firstChild();
00391 #if DEBUG_CARETMODE > 0
00392 kdDebug(6200) << "=================== end findFlowBox (2)" << endl;
00393 #endif
00394 return flowBox;
00395 }
00396
00397
00398
00399
00400 for (; flowBox; flowBox = static_cast<InlineFlowBox *>(flowBox->nextLineBox())) {
00401 #if DEBUG_CARETMODE > 0
00402 kdDebug(6200) << "[scan line]" << endl;
00403 #endif
00404
00405
00406 InlineBox *box;
00407 InlineBoxIterator it(arena, flowBox);
00408 for (; (box = *it) != 0; ++it) {
00409 RenderObject *br = box->object();
00410 if (!br) continue;
00411
00412 #if DEBUG_CARETMODE > 0
00413 kdDebug(6200) << "box->obj " << br->renderName() << "[" << br << "]" << " minOffset: " << box->minOffset() << " maxOffset: " << box->maxOffset() << endl;
00414 #endif
00415 if (br == r && offset >= box->minOffset() && offset <= box->maxOffset())
00416 break;
00417 }
00418 if (box) {
00419 if (ibox) *ibox = box;
00420 break;
00421 }
00422
00423 }
00424
00425
00426
00427
00428 if (!flowBox) flowBox = findFlowBox(node->nextLeafNode(), 0, arena, cb, ibox);
00429
00430 #if DEBUG_CARETMODE > 0
00431 kdDebug(6200) << "=================== end findFlowBox" << endl;
00432 #endif
00433 return flowBox;
00434 }
00435
00442 static inline RenderTable *findTableUpTo(RenderObject *r, RenderFlow *cb)
00443 {
00444 while (r && r != cb && !r->isTable()) r = r->parent();
00445 return r && r->isTable() ? static_cast<RenderTable *>(r) : 0;
00446 }
00447
00450 static inline bool isDescendant(RenderObject *r, RenderObject *cb)
00451 {
00452 while (r && r != cb) r = r->parent();
00453 return r;
00454 }
00455
00466 static bool containsEditableElement(KHTMLPart *part, RenderFlow *cb,
00467 RenderTable *&table, bool fromEnd = false)
00468 {
00469 RenderObject *r = cb;
00470 if (fromEnd)
00471 while (r->lastChild()) r = r->lastChild();
00472 else
00473 while (r->firstChild()) r = r->firstChild();
00474
00475 RenderTable *tempTable = 0;
00476 table = 0;
00477 bool withinCb;
00478 do {
00479 tempTable = findTableUpTo(r, cb);
00480 withinCb = isDescendant(r, cb);
00481
00482 #if DEBUG_CARETMODE > 1
00483 kdDebug(6201) << "r " << (r ? r->renderName() : QString::null) << "@" << r << endl;
00484 #endif
00485 if (r && withinCb && r->element() && !r->isTableCol()
00486 && (part->isCaretMode() || part->isEditable()
00487 || r->style()->userInput() == UI_ENABLED)) {
00488 table = tempTable;
00489 return true;
00490 }
00491
00492 r = fromEnd ? prevSuitableLeafRenderObject(r) : nextSuitableLeafRenderObject(r);
00493 } while (r && withinCb);
00494 return false;
00495 }
00496
00509 static bool containsEditableChildElement(KHTMLPart *part, RenderFlow *cb,
00510 RenderTable *&table, bool fromEnd, RenderObject *start)
00511 {
00512 RenderObject *r = start;
00513 if (fromEnd)
00514 while (r->firstChild()) r = r->firstChild();
00515 else
00516 while (r->lastChild()) r = r->lastChild();
00517
00518 if (!r) return false;
00519
00520 RenderTable *tempTable = 0;
00521 table = 0;
00522 bool withinCb = false;
00523 do {
00524 r = fromEnd ? prevSuitableLeafRenderObject(r) : nextSuitableLeafRenderObject(r);
00525 if (!r) break;
00526
00527 withinCb = isDescendant(r, cb) && r != cb;
00528 tempTable = findTableUpTo(r, cb);
00529
00530 #if DEBUG_CARETMODE > 1
00531 kdDebug(6201) << "r " << (r ? r->renderName() : QString::null) << "@" << r << endl;
00532 #endif
00533 if (r && withinCb && r->element() && !r->isTableCol()
00534 && (part->isCaretMode() || part->isEditable()
00535 || r->style()->userInput() == UI_ENABLED)) {
00536 table = tempTable;
00537 return true;
00538 }
00539
00540 } while (withinCb);
00541 return false;
00542 }
00543
00544
00545
00546 LinearDocument::LinearDocument(KHTMLPart *part, NodeImpl *node, long offset)
00547 : arena(0), node(node), offset(offset), m_part(part)
00548 {
00549 if (node == 0) return;
00550 sanitizeCaretState(this->node, this->offset);
00551
00552 arena = new RenderArena(512);
00553
00554 initPreBeginIterator();
00555 initEndIterator();
00556
00557 }
00558
00559 LinearDocument::~LinearDocument()
00560 {
00561 delete arena;
00562 }
00563
00564 int LinearDocument::count() const
00565 {
00566
00567 return 1;
00568 }
00569
00570 LinearDocument::Iterator LinearDocument::current()
00571 {
00572 return LineIterator(this, node, offset);
00573 }
00574
00575 LinearDocument::Iterator LinearDocument::begin()
00576 {
00577 DocumentImpl *doc = node ? node->getDocument() : 0;
00578 if (!doc) return end();
00579
00580 NodeImpl *firstLeaf = doc->nextLeafNode();
00581 if (!firstLeaf) return end();
00582 return LineIterator(this, firstLeaf, firstLeaf->minOffset());
00583 }
00584
00585 LinearDocument::Iterator LinearDocument::preEnd()
00586 {
00587 DocumentImpl *doc = node ? node->getDocument() : 0;
00588 if (!doc) return preBegin();
00589
00590 NodeImpl *lastLeaf = doc;
00591 while (lastLeaf->lastChild()) lastLeaf = lastLeaf->lastChild();
00592
00593 if (!lastLeaf) return preBegin();
00594 return LineIterator(this, lastLeaf, lastLeaf->maxOffset());
00595 }
00596
00597 void LinearDocument::initPreBeginIterator()
00598 {
00599 _preBegin = LineIterator(this, 0, 0);
00600 }
00601
00602 void LinearDocument::initEndIterator()
00603 {
00604 _end = LineIterator(this, 0, 1);
00605 }
00606
00607
00608
00609 LineIterator::LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset)
00610 : lines(l)
00611 {
00612
00613 flowBox = findFlowBox(node, offset, lines->arena, cb, ¤tBox);
00614 if (!flowBox) {
00615 #if DEBUG_CARETMODE > 0
00616 kdDebug(6200) << "LineIterator: findFlowBox failed" << endl;
00617 #endif
00618 cb = 0;
00619 }
00620 }
00621
00622 void LineIterator::nextBlock()
00623 {
00624 RenderObject *r = cb;
00625 RenderObject *n = r->lastChild();
00626 while (n) r = n, n = r->lastChild();
00627 r = nextSuitableLeafRenderObject(r);
00628 #if DEBUG_CARETMODE > 0
00629 kdDebug(6200) << "++: r " << r << "[" << (r?r->renderName():QString::null) << "]" << endl;
00630 #endif
00631 if (!r) {
00632 cb = 0;
00633 return;
00634 }
00635
00636
00637
00638 if (r->isRenderBlock()) {
00639 cb = static_cast<RenderBlock *>(r);
00640 #if DEBUG_CARETMODE > 0
00641 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;
00642 #endif
00643
00644
00645
00646
00647 RenderFlow *flow = static_cast<RenderFlow *>(cb->element()
00648 ? cb->element()->renderer() : 0);
00649 if (cb->continuation() || flow && flow->isRenderBlock() && flow != cb
00650 && flow->continuation()) {
00651 nextBlock();
00652 return;
00653 }
00654 } else {
00655 cb = static_cast<RenderFlow *>(r->containingBlock());
00656 if (!cb->isRenderBlock()) {
00657 #if DEBUG_CARETMODE > 0
00658 kdDebug(6200) << "dummy cb created " << cb << endl;
00659 #endif
00660 cb = generateDummyBlock(lines->arena, r);
00661 }
00662 }
00663 flowBox = cb->firstLineBox();
00664 #if DEBUG_CARETMODE > 0
00665 kdDebug(6200) << "++: flowBox " << flowBox << endl;
00666 #endif
00667
00668 if (!flowBox) flowBox = generateDummyFlowBox(lines->arena, cb, r);
00669 #if DEBUG_CARETMODE > 0
00670 if (!cb->firstLineBox()) kdDebug(6200) << "++: dummy flowBox " << flowBox << endl;
00671 #endif
00672 }
00673
00674 inline LineIterator &LineIterator::operator ++()
00675 {
00676 flowBox = static_cast<InlineFlowBox *>(flowBox->nextLineBox());
00677
00678
00679
00680 if (!flowBox) nextBlock();
00681
00682 return *this;
00683 }
00684
00685 inline LineIterator LineIterator::operator ++(int)
00686 {
00687 LineIterator it(*this);
00688 operator ++();
00689 return it;
00690 }
00691
00692 void LineIterator::prevBlock()
00693 {
00694 RenderObject *r = cb;
00695 RenderObject *n = r->firstChild();
00696 while (n) r = n, n = r->firstChild();
00697 r = prevSuitableLeafRenderObject(r);
00698 if (!r) {
00699 cb = 0;
00700 return;
00701 }
00702
00703
00704
00705 if (r->isRenderBlock()) {
00706 cb = static_cast<RenderFlow *>(r);
00707 #if DEBUG_CARETMODE > 0
00708 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;
00709 #endif
00710
00711
00712
00713
00714 RenderFlow *flow = static_cast<RenderFlow *>(cb->element()
00715 ? cb->element()->renderer() : 0);
00716 if (cb->continuation() || flow && flow->isRenderBlock() && flow != cb
00717 && flow->continuation()) {
00718 prevBlock();
00719 return;
00720 }
00721 } else {
00722 cb = static_cast<RenderFlow *>(r->containingBlock());
00723 if (!cb->isRenderBlock()) {
00724 #if DEBUG_CARETMODE > 0
00725 kdDebug(6200) << "dummy cb created " << cb << endl;
00726 #endif
00727 cb = generateDummyBlock(lines->arena, r);
00728 }
00729 }
00730 flowBox = cb->lastLineBox();
00731
00732 if (!flowBox) flowBox = generateDummyFlowBox(lines->arena, cb, r);
00733 }
00734
00735 inline LineIterator &LineIterator::operator --()
00736 {
00737 flowBox = static_cast<InlineFlowBox *>(flowBox->prevLineBox());
00738
00739
00740
00741 if (!flowBox) prevBlock();
00742
00743 return *this;
00744 }
00745
00746 inline LineIterator LineIterator::operator --(int)
00747 {
00748 LineIterator it(*this);
00749 operator --();
00750 return it;
00751 }
00752
00753 #if 0 // not implemented because it's not needed
00754 LineIterator LineIterator::operator +(int ) const
00755 {
00756
00757 return LineIterator();
00758 }
00759
00760 LineIterator LineIterator::operator -(int ) const
00761 {
00762
00763 return LineIterator();
00764 }
00765 #endif
00766
00767 LineIterator &LineIterator::operator +=(int summand)
00768 {
00769 if (summand > 0)
00770 while (summand-- && *this != lines->end()) ++*this;
00771 else if (summand < 0)
00772 operator -=(-summand);
00773 return *this;
00774 }
00775
00776 LineIterator &LineIterator::operator -=(int summand)
00777 {
00778 if (summand > 0)
00779 while (summand-- && *this != lines->preBegin()) --*this;
00780 else if (summand < 0)
00781 operator +=(-summand);
00782 return *this;
00783 }
00784
00785
00786
00787 void EditableCharacterIterator::initFirstChar()
00788 {
00789 InlineBox *b = *ebit;
00790 if (b) {
00791 if (_offset == b->maxOffset())
00792 peekNext();
00793 else if (b->isInlineTextBox())
00794 _char = static_cast<RenderText *>(b->object())->str->s[_offset].unicode();
00795 else
00796 _char = -1;
00797 }
00798 }
00799
00800 EditableCharacterIterator &EditableCharacterIterator::operator ++()
00801 {
00802 _offset++;
00803
00804 InlineBox *b = *ebit;
00805 RenderObject *r = b->object();
00806
00807
00808
00809 long maxofs = r->isBR() || r->isRenderBlock() ? b->minOffset() : b->maxOffset();
00810 #if DEBUG_CARETMODE > 0
00811 kdDebug(6200) << "b->maxOffset() " << b->maxOffset() << " b->minOffset() " << b->minOffset() << endl;
00812 #endif
00813 if (_offset == maxofs) {
00814 #if DEBUG_CARETMODE > 2
00815 kdDebug(6200) << "_offset == maxofs: " << _offset << " == " << maxofs << endl;
00816 #endif
00817
00818 peekNext();
00819 } else if (_offset > maxofs) {
00820 #if DEBUG_CARETMODE > 2
00821 kdDebug(6200) << "_offset > maxofs: " << _offset << " > " << maxofs << endl;
00822 #endif
00823 if (true) {
00824 if (*ebit)
00825 ++ebit;
00826 if (!*ebit) {
00827 ++_it;
00828 #if DEBUG_CARETMODE > 3
00829 kdDebug(6200) << "++_it" << endl;
00830 #endif
00831 if (_it != ld->end()) {
00832 ebit = _it;
00833 b = *ebit;
00834 #if DEBUG_CARETMODE > 3
00835 kdDebug(6200) << "b " << b << " isText " << b->isInlineTextBox() << endl;
00836 #endif
00837 _node = b->object()->element();
00838 #if DEBUG_CARETMODE > 3
00839 kdDebug(6200) << "_node " << _node << ":" << _node->nodeName().string() << endl;
00840 #endif
00841 _offset = b->minOffset();
00842 #if DEBUG_CARETMODE > 3
00843 kdDebug(6200) << "_offset " << _offset << endl;
00844 #endif
00845 } else {
00846 _node = 0;
00847 b = 0;
00848 }
00849 goto readchar;
00850 }
00851 }
00852 bool adjacent = ebit.isAdjacent();
00853
00854 if (adjacent && !(*ebit)->isInlineTextBox()) {
00855 EditableInlineBoxIterator copy = ebit;
00856 ++ebit;
00857 if (*ebit && (*ebit)->isInlineTextBox()) adjacent = false;
00858 else ebit = copy;
00859 }
00860 _node = (*ebit)->object()->element();
00861 _offset = (*ebit)->minOffset() + adjacent;
00862
00863 b = *ebit;
00864 goto readchar;
00865 } else {
00866 readchar:
00867
00868 if (b && b->isInlineTextBox() && _offset < b->maxOffset())
00869 _char = static_cast<RenderText *>(b->object())->str->s[_offset].unicode();
00870 else
00871 _char = -1;
00872 }
00873 #if DEBUG_CARETMODE > 2
00874 kdDebug(6200) << "_offset: " << _offset << " char '" << (char)_char << "'" << endl;
00875 #endif
00876
00877 #if DEBUG_CARETMODE > 0
00878 if (*ebit) {
00879 InlineBox *box = *ebit;
00880 kdDebug(6200) << "echit++(1): box " << box << (box && box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << " node " << (_node ? _node->nodeName().string() : QString("<nil>")) << endl;
00881 }
00882 #endif
00883 return *this;
00884 }
00885
00886 EditableCharacterIterator &EditableCharacterIterator::operator --()
00887 {
00888 _offset--;
00889
00890
00891 InlineBox *b = *ebit;
00892 InlineBox *_peekPrev = 0;
00893 InlineBox *_peekNext = 0;
00894 long minofs = b ? b->minOffset() : _offset + 1;
00895 #if DEBUG_CARETMODE > 0
00896 kdDebug(6200) << "b->maxOffset() " << b->maxOffset() << " b->minOffset() " << b->minOffset() << endl;
00897 #endif
00898 if (_offset == minofs) {
00899 #if DEBUG_CARETMODE > 2
00900 kdDebug(6200) << "_offset == minofs: " << _offset << " == " << minofs << endl;
00901 #endif
00902 _peekNext = b;
00903
00904 if (b && b->isInlineTextBox())
00905 _char = static_cast<RenderText *>(b->object())->text()[_offset].unicode();
00906 else
00907 _char = -1;
00908
00909
00910 bool do_prev = false;
00911 {
00912 EditableInlineBoxIterator copy = ebit;
00913 --ebit;
00914 _peekPrev = *ebit;
00915
00916 if (ebit.isAdjacent() && *ebit && (*ebit)->isInlineTextBox())
00917
00918 do_prev = true;
00919 else
00920 ebit = copy;
00921 }
00922 if (do_prev) goto prev;
00923 } else if (_offset < minofs) {
00924 prev:
00925 #if DEBUG_CARETMODE > 2
00926 kdDebug(6200) << "_offset < minofs: " << _offset << " < " << minofs << endl;
00927 #endif
00928 if (!_peekPrev) {
00929 _peekNext = *ebit;
00930 if (*ebit)
00931 --ebit;
00932 if (!*ebit) {
00933 --_it;
00934 #if DEBUG_CARETMODE > 3
00935 kdDebug(6200) << "--_it" << endl;
00936 #endif
00937 if (_it != ld->preBegin()) {
00938
00939 ebit = EditableInlineBoxIterator(_it, true);
00940 RenderObject *r = (*ebit)->object();
00941 #if DEBUG_CARETMODE > 3
00942 kdDebug(6200) << "b " << *ebit << " isText " << (*ebit)->isInlineTextBox() << endl;
00943 #endif
00944 _node = r->element();
00945 _offset = r->isBR() ? (*ebit)->minOffset() : (*ebit)->maxOffset();
00946 _char = -1;
00947 #if DEBUG_CARETMODE > 0
00948 {InlineBox *box = *ebit; kdDebug(6200) << "echit--(2): box " << box << (box && box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << endl;}
00949 #endif
00950 } else
00951 _node = 0;
00952 return *this;
00953 }
00954 }
00955
00956 bool adjacent = ebit.isAdjacent();
00957
00958 #if DEBUG_CARETMODE > 0
00959 kdDebug(6200) << "adjacent " << adjacent << " _peekNext " << _peekNext << " _peekNext->isInlineTextBox: " << (_peekNext ? _peekNext->isInlineTextBox() : false) << " !((*ebit)->isInlineTextBox): " << (*ebit ? !(*ebit)->isInlineTextBox() : true) << endl;
00960 #endif
00961 if (adjacent && _peekNext && _peekNext->isInlineTextBox()
00962 && !(*ebit)->isInlineTextBox()) {
00963 EditableInlineBoxIterator copy = ebit;
00964 --ebit;
00965 if (!*ebit)
00966 ebit = copy;
00967 }
00968 #if DEBUG_CARETMODE > 0
00969 kdDebug(6200) << "(*ebit)->obj " << (*ebit)->object()->renderName() << "[" << (*ebit)->object() << "]" << " minOffset: " << (*ebit)->minOffset() << " maxOffset: " << (*ebit)->maxOffset() << endl;
00970 #endif
00971 _node = (*ebit)->object()->element();
00972 #if DEBUG_CARETMODE > 3
00973 kdDebug(6200) << "_node " << _node << ":" << _node->nodeName().string() << endl;
00974 #endif
00975 _offset = (*ebit)->maxOffset();
00976 #if DEBUG_CARETMODE > 3
00977 kdDebug(6200) << "_offset " << _offset << endl;
00978 #endif
00979 _peekPrev = 0;
00980 } else {
00981 #if DEBUG_CARETMODE > 0
00982 kdDebug(6200) << "_offset: " << _offset << " _peekNext: " << _peekNext << endl;
00983 #endif
00984
00985 if (_peekNext && _offset >= b->maxOffset() && _peekNext->isInlineTextBox())
00986 _char = static_cast<RenderText *>(_peekNext->object())->text()[_peekNext->minOffset()].unicode();
00987 else if (b && _offset < b->maxOffset() && b->isInlineTextBox())
00988 _char = static_cast<RenderText *>(b->object())->text()[_offset].unicode();
00989 else
00990 _char = -1;
00991 }
00992
00993 #if DEBUG_CARETMODE > 0
00994 if (*ebit) {
00995 InlineBox *box = *ebit;
00996 kdDebug(6200) << "echit--(1): box " << box << (box && box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << endl;
00997 }
00998 #endif
00999 return *this;
01000 }
01001
01002
01003
01004 TableRowIterator::TableRowIterator(RenderTable *table, bool fromEnd,
01005 RenderTableSection::RowStruct *row)
01006 : sec(table, fromEnd)
01007 {
01008
01009 if (*sec) {
01010 if (fromEnd) index = (*sec)->grid.size() - 1;
01011 else index = 0;
01012 }
01013
01014
01015 if (row && *sec) {
01016 while (operator *() != row)
01017 if (fromEnd) operator --(); else operator ++();
01018 }
01019 }
01020
01021 TableRowIterator &TableRowIterator::operator ++()
01022 {
01023 index++;
01024
01025 if (index >= (int)(*sec)->grid.size()) {
01026 ++sec;
01027
01028 if (*sec) index = 0;
01029 }
01030 return *this;
01031 }
01032
01033 TableRowIterator &TableRowIterator::operator --()
01034 {
01035 index--;
01036
01037 if (index < 0) {
01038 --sec;
01039
01040 if (*sec) index = (*sec)->grid.size() - 1;
01041 }
01042 return *this;
01043 }
01044
01045
01046
01047
01048 static RenderTableCell *findNearestTableCellInRow(KHTMLPart *part, int x,
01049 RenderTableSection::RowStruct *row, bool fromEnd);
01050
01064 static inline RenderTableCell *findNearestTableCell(KHTMLPart *part, int x,
01065 TableRowIterator &it, bool fromEnd)
01066 {
01067 RenderTableCell *result = 0;
01068
01069 while (*it) {
01070 result = findNearestTableCellInRow(part, x, *it, fromEnd);
01071 if (result) break;
01072
01073 if (fromEnd) --it; else ++it;
01074 }
01075
01076 return result;
01077 }
01078
01092 static RenderTableCell *findNearestTableCellInRow(KHTMLPart *part, int x,
01093 RenderTableSection::RowStruct *row, bool fromEnd)
01094 {
01095
01096 int n = (int)row->row->size();
01097 int i;
01098 for (i = 0; i < n; i++) {
01099 RenderTableCell *cell = row->row->at(i);
01100 if (!cell || (int)cell == -1) continue;
01101
01102 int absx, absy;
01103 cell->absolutePosition(absx, absy, false);
01104 #if DEBUG_CARETMODE > 1
01105 kdDebug(6201) << "i/n " << i << "/" << n << " absx " << absx << " absy " << absy << endl;
01106 #endif
01107
01108
01109
01110 #if DEBUG_CARETMODE > 1
01111 kdDebug(6201) << "x " << x << " < " << (absx + cell->width()) << "?" << endl;
01112 #endif
01113 if (x < absx + cell->width()) break;
01114 }
01115 if (i >= n) i = n - 1;
01116
01117
01118
01119 for (int cnt = 0; cnt < 2*n; cnt++) {
01120 int index = i - ((cnt >> 1) + 1)*(cnt & 1) + (cnt >> 1)*!(cnt & 1);
01121 if (index < 0 || index >= n) continue;
01122
01123 RenderTableCell *cell = row->row->at(index);
01124 if (!cell || (int)cell == -1) continue;
01125
01126 #if DEBUG_CARETMODE > 1
01127 kdDebug(6201) << "index " << index << " cell " << cell << endl;
01128 #endif
01129 RenderTable *nestedTable;
01130 if (containsEditableElement(part, cell, nestedTable, fromEnd)) {
01131
01132 if (nestedTable) {
01133 TableRowIterator it(nestedTable, fromEnd);
01134 while (*it) {
01135 cell = findNearestTableCell(part, x, it, fromEnd);
01136 if (cell) break;
01137 if (fromEnd) --it; else ++it;
01138 }
01139 }
01140
01141 return cell;
01142 }
01143 }
01144 return 0;
01145 }
01146
01153 static RenderObject *commonAncestorTableSectionOrCell(RenderObject *r1,
01154 RenderObject *r2)
01155 {
01156 if (!r1 || !r2) return 0;
01157 RenderTableSection *sec = 0;
01158 int start_depth=0, end_depth=0;
01159
01160 RenderObject *n = r1;
01161 while (n->parent()) {
01162 n = n->parent();
01163 start_depth++;
01164 }
01165 n = r2;
01166 while( n->parent()) {
01167 n = n->parent();
01168 end_depth++;
01169 }
01170
01171 while (end_depth > start_depth) {
01172 r2 = r2->parent();
01173 end_depth--;
01174 }
01175 while (start_depth > end_depth) {
01176 r1 = r1->parent();
01177
01178 start_depth--;
01179 }
01180
01181 while (r1 != r2){
01182 r1 = r1->parent();
01183 if (r1->isTableSection()) sec = static_cast<RenderTableSection *>(r1);
01184 r2 = r2->parent();
01185 }
01186
01187
01188
01189 while (r1 && !r1->isTableCell() && !r1->isTableSection() && !r1->isTable())
01190 r1 = r1->parent();
01191
01192 return r1 && r1->isTable() ? sec : r1;
01193 }
01194
01202 static int findRowInSection(RenderTableSection *section, RenderTableCell *cell,
01203 RenderTableSection::RowStruct *&row, RenderTableCell *&directCell)
01204 {
01205
01206 RenderObject *r = cell;
01207 while (r != section) {
01208 if (r->isTableCell()) directCell = static_cast<RenderTableCell *>(r);
01209 r = r->parent();
01210 }
01211
01212
01213
01214
01215 int n = section->numRows();
01216 for (int i = 0; i < n; i++) {
01217 row = §ion->grid[i];
01218
01219
01220 int m = row->row->size();
01221 for (int j = 0; j < m; j++) {
01222 RenderTableCell *c = row->row->at(j);
01223 if (c == directCell) return i;
01224 }
01225
01226 }
01227 Q_ASSERT(false);
01228 return -1;
01229 }
01230
01236 static inline RenderTable *findFirstDescendantTable(RenderObject *leaf, RenderFlow *block)
01237 {
01238 RenderTable *result = 0;
01239 while (leaf && leaf != block) {
01240 if (leaf->isTable()) result = static_cast<RenderTable *>(leaf);
01241 leaf = leaf->parent();
01242 }
01243 return result;
01244 }
01245
01249 static inline RenderTableCell *containingTableCell(RenderObject *r)
01250 {
01251 while (r && !r->isTableCell()) r = r->parent();
01252 return static_cast<RenderTableCell *>(r);
01253 }
01254
01255 inline void ErgonomicEditableLineIterator::calcAndStoreNewLine(
01256 RenderFlow *newBlock, bool toBegin)
01257 {
01258
01259
01260 cb = newBlock;
01261 if (toBegin) prevBlock(); else nextBlock();
01262
01263 if (!cb) {
01264 flowBox = 0;
01265 return;
01266 }
01267
01268 if (!isEditable(*this)) {
01269 if (toBegin) EditableLineIterator::operator --();
01270 else EditableLineIterator::operator ++();
01271 }
01272 }
01273
01274 void ErgonomicEditableLineIterator::determineTopologicalElement(
01275 RenderTableCell *oldCell, RenderObject *newObject, bool toBegin)
01276 {
01277
01278
01279
01280
01281
01282 TableRowIterator it;
01283
01284 RenderObject *commonAncestor = commonAncestorTableSectionOrCell(oldCell, newObject);
01285 #if DEBUG_CARETMODE > 1
01286 kdDebug(6201) << " ancestor " << commonAncestor << endl;
01287 #endif
01288
01289
01290 if (!commonAncestor || commonAncestor->isTableCell()) {
01291
01292 RenderTableCell *cell = static_cast<RenderTableCell *>(commonAncestor);
01293 RenderTable *table = findFirstDescendantTable(newObject, cell);
01294
01295 #if DEBUG_CARETMODE > 0
01296 kdDebug(6201) << "table cell: " << cell << endl;
01297 #endif
01298
01299
01300
01301 if (!table) return;
01302
01303 it = TableRowIterator(table, toBegin);
01304
01305 } else if (commonAncestor->isTableSection()) {
01306
01307 RenderTableSection *section = static_cast<RenderTableSection *>(commonAncestor);
01308 RenderTableSection::RowStruct *row;
01309 int idx = findRowInSection(section, oldCell, row, oldCell);
01310 #if DEBUG_CARETMODE > 1
01311 kdDebug(6201) << "table section: row idx " << idx << endl;
01312 #endif
01313
01314 it = TableRowIterator(section, idx);
01315
01316
01317 int rowspan = oldCell->rowSpan();
01318 while (*it && rowspan--) {
01319 if (toBegin) --it; else ++it;
01320 }
01321
01322 } else {
01323 kdError(6201) << "Neither common cell nor section! " << commonAncestor->renderName() << endl;
01324
01325 }
01326
01327 RenderTableCell *cell = findNearestTableCell(lines->m_part, xCoor, it, toBegin);
01328 #if DEBUG_CARETMODE > 1
01329 kdDebug(6201) << "findNearestTableCell result: " << cell << endl;
01330 #endif
01331
01332 RenderFlow *newBlock = cell;
01333 if (!cell) {
01334 Q_ASSERT(commonAncestor->isTableSection());
01335 RenderTableSection *section = static_cast<RenderTableSection *>(commonAncestor);
01336 cell = containingTableCell(section);
01337 #if DEBUG_CARETMODE > 1
01338 kdDebug(6201) << "containing cell: " << cell << endl;
01339 #endif
01340
01341 RenderTable *nestedTable;
01342 bool editableChild = cell && containsEditableChildElement(lines->m_part,
01343 cell, nestedTable, toBegin, section->table());
01344
01345 if (cell && !editableChild) {
01346 #if DEBUG_CARETMODE > 1
01347 kdDebug(6201) << "========= recursive invocation outer =========" << endl;
01348 #endif
01349 determineTopologicalElement(cell, cell->section(), toBegin);
01350 #if DEBUG_CARETMODE > 1
01351 kdDebug(6201) << "========= end recursive invocation outer =========" << endl;
01352 #endif
01353 return;
01354
01355 } else if (cell && nestedTable) {
01356 #if DEBUG_CARETMODE > 1
01357 kdDebug(6201) << "========= recursive invocation inner =========" << endl;
01358 #endif
01359 determineTopologicalElement(cell, nestedTable, toBegin);
01360 #if DEBUG_CARETMODE > 1
01361 kdDebug(6201) << "========= end recursive invocation inner =========" << endl;
01362 #endif
01363 return;
01364
01365 } else {
01366 #if DEBUG_CARETMODE > 1
01367 kdDebug(6201) << "newBlock is table: " << section->table() << endl;
01368 #endif
01369 newBlock = section->table();
01370
01371 }
01372 } else {
01373
01374 RenderObject *r = cell;
01375 if (toBegin) {
01376 while (r->lastChild()) r = r->lastChild();
01377 r = nextSuitableLeafRenderObject(r);
01378 } else
01379 r = prevSuitableLeafRenderObject(r);
01380 newBlock = static_cast<RenderFlow *>(!r || r->isRenderBlock() ? r : r->containingBlock());
01381 }
01382
01383 calcAndStoreNewLine(newBlock, toBegin);
01384 }
01385
01386 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator ++()
01387 {
01388 RenderTableCell *oldCell = containingTableCell(cb);
01389
01390 EditableLineIterator::operator ++();
01391 if (*this == lines->end() || *this == lines->preBegin()) return *this;
01392
01393 RenderTableCell *newCell = containingTableCell(cb);
01394
01395 if (!newCell || newCell == oldCell) return *this;
01396
01397 determineTopologicalElement(oldCell, newCell, false);
01398
01399 return *this;
01400 }
01401
01402 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator --()
01403 {
01404 RenderTableCell *oldCell = containingTableCell(cb);
01405
01406 EditableLineIterator::operator --();
01407 if (*this == lines->end() || *this == lines->preBegin()) return *this;
01408
01409 RenderTableCell *newCell = containingTableCell(cb);
01410
01411 if (!newCell || newCell == oldCell) return *this;
01412
01413 determineTopologicalElement(oldCell, newCell, true);
01414
01415 return *this;
01416 }
01417
01418
01419
01429 static InlineBox *nearestInlineBox(LineIterator &it, CaretViewContext *cv,
01430 int &x, int &absx, int &absy)
01431 {
01432 InlineFlowBox *fbox = *it;
01433
01434
01435 RenderObject *cb = fbox->object();
01436
01437 if (cb) cb->absolutePosition(absx, absy);
01438 else absx = absy = 0;
01439
01440
01441
01442
01443 x = cv->origX - absx;
01444 InlineBox *caretBox = 0;
01445
01446 int xPos;
01447 int oldXPos = -1;
01448 EditableInlineBoxIterator fbit = it;
01449 #if DEBUG_CARETMODE > 0
01450 kdDebug(6200) << "*fbit = " << *fbit << endl;
01451 #endif
01452
01453
01454 for (InlineBox *b; *fbit != 0; ++fbit) {
01455 b = *fbit;
01456
01457
01458 #if DEBUG_CARETMODE > 0
01459 if (b->isInlineFlowBox()) kdDebug(6200) << "b is inline flow box" << endl;
01460
01461 #endif
01462
01463 xPos = b->xPos();
01464
01465
01466 if (x < xPos) {
01467
01468 if (oldXPos < 0 || x - (oldXPos + caretBox->width()) > xPos - x) {
01469 caretBox = b;
01470
01471 }
01472 break;
01473 }
01474
01475 caretBox = b;
01476
01477
01478
01479 if (x >= xPos && x < xPos + caretBox->width())
01480 break;
01481 oldXPos = xPos;
01482
01483
01484
01485
01486 if (b == fbox) break;
01487 }
01488
01489 return caretBox;
01490 }
01491
01497 static void moveItToNextWord(EditableCharacterIterator &it)
01498 {
01499 #if DEBUG_CARETMODE > 0
01500 kdDebug(6200) << "%%%%%%%%%%%%%%%%%%%%% moveItToNextWord" << endl;
01501 #endif
01502 EditableCharacterIterator copy;
01503 while (it.node() && !(*it).isSpace() && !(*it).isPunct()) {
01504 #if DEBUG_CARETMODE > 2
01505 kdDebug(6200) << "reading1 '" << (*it).latin1() << "'" << endl;
01506 #endif
01507 copy = it;
01508 ++it;
01509 }
01510
01511 if (!it.node()) {
01512 it = copy;
01513 return;
01514 }
01515
01516 while (it.node() && ((*it).isSpace() || (*it).isPunct())) {
01517 #if DEBUG_CARETMODE > 2
01518 kdDebug(6200) << "reading2 '" << (*it).latin1() << "'" << endl;
01519 #endif
01520 copy = it;
01521 ++it;
01522 }
01523
01524 if (!it.node()) it = copy;
01525 }
01526
01532 static void moveItToPrevWord(EditableCharacterIterator &it)
01533 {
01534 if (!it.node()) return;
01535
01536 #if DEBUG_CARETMODE > 0
01537 kdDebug(6200) << "%%%%%%%%%%%%%%%%%%%%% moveItToPrevWord" << endl;
01538 #endif
01539 EditableCharacterIterator copy;
01540
01541
01542 do {
01543 copy = it;
01544 --it;
01545 #if DEBUG_CARETMODE > 2
01546 if (it.node()) kdDebug(6200) << "reading1 '" << (*it).latin1() << "'" << endl;
01547 #endif
01548 } while (it.node() && ((*it).isSpace() || (*it).isPunct()));
01549
01550 if (!it.node()) {
01551 it = copy;
01552 return;
01553 }
01554
01555 do {
01556 copy = it;
01557 --it;
01558 #if DEBUG_CARETMODE > 0
01559 if (it.node()) kdDebug(6200) << "reading2 '" << (*it).latin1() << "'" << endl;
01560 #endif
01561 } while (it.node() && !(*it).isSpace() && !(*it).isPunct());
01562
01563 it = copy;
01564 }
01565
01566
01574 static void moveIteratorByPage(LinearDocument &ld,
01575 ErgonomicEditableLineIterator &it, int mindist, bool next)
01576 {
01577 if (it == ld.end() || it == ld.preBegin()) return;
01578
01579 ErgonomicEditableLineIterator copy = it;
01580 #if DEBUG_CARETMODE > 0
01581 kdDebug(6200) << " mindist: " << mindist << endl;
01582 #endif
01583
01584 InlineFlowBox *flowBox = *copy;
01585 int absx = 0, absy = 0;
01586
01587 RenderFlow *lastcb = static_cast<RenderFlow *>(flowBox->object());
01588 Q_ASSERT(lastcb->isRenderBlock());
01589 lastcb->absolutePosition(absx, absy, false);
01590
01591
01592
01593 int lastfby = flowBox->firstChild()->yPos();
01594 int lastheight = 0;
01595 do {
01596 if (next) ++copy; else --copy;
01597 if (copy == ld.end() || copy == ld.preBegin()) break;
01598
01599
01600 flowBox = static_cast<InlineFlowBox *>(*copy);
01601 Q_ASSERT(flowBox->isInlineFlowBox());
01602
01603 RenderFlow *cb = static_cast<RenderFlow *>(flowBox->object());
01604 Q_ASSERT(cb->isRenderBlock());
01605
01606 int diff = 0;
01607
01608
01609 int fby = flowBox->firstChild()->yPos();
01610 if (cb != lastcb) {
01611 if (next) {
01612 diff = absy + lastfby + lastheight;
01613 cb->absolutePosition(absx, absy, false);
01614 diff = absy - diff + fby;
01615 lastfby = 0;
01616 } else {
01617 diff = absy;
01618 cb->absolutePosition(absx, absy, false);
01619 diff -= absy + fby + lastheight;
01620 lastfby = fby - lastheight;
01621 }
01622 #if DEBUG_CARETMODE > 2
01623 kdDebug(6200) << "absdiff " << diff << endl;
01624 #endif
01625 } else {
01626 diff = QABS(fby - lastfby);
01627 }
01628 #if DEBUG_CARETMODE > 2
01629 kdDebug(6200) << "flowBox->firstChild->yPos: " << fby << " diff " << diff << endl;
01630 #endif
01631
01632 mindist -= diff;
01633
01634 lastheight = QABS(fby - lastfby);
01635 lastfby = fby;
01636 lastcb = cb;
01637 it = copy;
01638 #if DEBUG_CARETMODE > 0
01639 kdDebug(6200) << " mindist: " << mindist << endl;
01640 #endif
01641
01642
01643
01644
01645 } while (mindist - lastheight > 0);
01646 }
01647
01648
01649 }