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 #include "html/html_documentimpl.h"
00025
00026 namespace khtml {
00027
00035 enum ObjectAdvanceState {
00036 LeftObject = 0x01, AdvancedToSibling = 0x02, EnteredObject = 0x04
00037 };
00038
00047 enum ObjectTraversalState {
00048 OutsideDescending, InsideDescending, InsideAscending, OutsideAscending
00049 };
00050
00060 static RenderObject* traverseRenderObjects(RenderObject *obj,
00061 ObjectTraversalState &trav, bool toBegin, RenderObject *base,
00062 int &state)
00063 {
00064 RenderObject *r;
00065 switch (trav) {
00066 case OutsideDescending:
00067 trav = InsideDescending;
00068 break;
00069 case InsideDescending:
00070 r = toBegin ? obj->lastChild() : obj->firstChild();
00071 if (r) {
00072 trav = OutsideDescending;
00073 obj = r;
00074 state |= EnteredObject;
00075 } else {
00076 trav = InsideAscending;
00077 }
00078 break;
00079 case InsideAscending:
00080 trav = OutsideAscending;
00081 break;
00082 case OutsideAscending:
00083 r = toBegin ? obj->previousSibling() : obj->nextSibling();
00084 if (r) {
00085 trav = OutsideDescending;
00086 state |= AdvancedToSibling;
00087 } else {
00088 r = obj->parent();
00089 if (r == base) r = 0;
00090 trav = InsideAscending;
00091 state |= LeftObject;
00092 }
00093 obj = r;
00094 break;
00095 }
00096
00097 return obj;
00098 }
00099
00105 static inline RenderObject *renderObjectBelow(RenderObject *obj, ObjectTraversalState &trav, RenderObject *base)
00106 {
00107 trav = InsideDescending;
00108 int state;
00109 RenderObject *r = obj;
00110 while (r && trav != OutsideDescending) {
00111 r = traverseRenderObjects(r, trav, false, base, state);
00112 #if DEBUG_CARETMODE > 3
00113 kdDebug(6200) << "renderObjectBelow: r " << r << " trav " << trav << endl;
00114 #endif
00115 }
00116 trav = InsideDescending;
00117 return r;
00118 }
00119
00125 static inline RenderObject *renderObjectAbove(RenderObject *obj, ObjectTraversalState &trav, RenderObject *base)
00126 {
00127 trav = OutsideAscending;
00128 int state;
00129 RenderObject *r = obj;
00130 while (r && trav != InsideAscending) {
00131 r = traverseRenderObjects(r, trav, true, base, state);
00132 #if DEBUG_CARETMODE > 3
00133 kdDebug(6200) << "renderObjectAbove: r " << r << " trav " << trav << endl;
00134 #endif
00135 }
00136 trav = InsideAscending;
00137 return r;
00138 }
00139
00144 static inline bool isIndicatedInlineBox(InlineBox *box)
00145 {
00146
00147 if (box->isInlineTextBox()) return false;
00148 RenderStyle *s = box->object()->style();
00149 return s->borderLeftWidth() || s->borderRightWidth()
00150 || s->borderTopWidth() || s->borderBottomWidth()
00151 || s->paddingLeft().value() || s->paddingRight().value()
00152 || s->paddingTop().value() || s->paddingBottom().value()
00153
00154
00155 || s->marginLeft().value() || s->marginRight().value();
00156 }
00157
00162 static inline bool isIndicatedFlow(RenderObject *r)
00163 {
00164 RenderStyle *s = r->style();
00165 return s->borderLeftStyle() != BNONE || s->borderRightStyle() != BNONE
00166 || s->borderTopStyle() != BNONE || s->borderBottomStyle() != BNONE
00167
00168
00169
00170 || s->hasClip() || s->hidesOverflow()
00171 || s->backgroundColor().isValid() || s->backgroundImage();
00172 }
00173
00187 static RenderObject *advanceObject(RenderObject *r,
00188 ObjectTraversalState &trav, bool toBegin,
00189 RenderObject *base, int &state)
00190 {
00191
00192 ObjectTraversalState origtrav = trav;
00193 RenderObject *a = traverseRenderObjects(r, trav, toBegin, base, state);
00194
00195 bool ignoreOutsideDesc = toBegin && origtrav == OutsideAscending;
00196
00197
00198 RenderObject *la = 0;
00199 ObjectTraversalState latrav = trav;
00200 ObjectTraversalState lasttrav = origtrav;
00201
00202 while (a) {
00203 #if DEBUG_CARETMODE > 5
00204 kdDebug(6200) << "a " << a << " trav " << trav << endl;
00205 #endif
00206 if (a->element()) {
00207 #if DEBUG_CARETMODE > 4
00208 kdDebug(6200) << "a " << a << " trav " << trav << " origtrav " << origtrav << " ignoreOD " << ignoreOutsideDesc << endl;
00209 #endif
00210 if (toBegin) {
00211
00212 switch (origtrav) {
00213 case OutsideDescending:
00214 if (trav == InsideAscending) return a;
00215 if (trav == OutsideDescending) return a;
00216 break;
00217 case InsideDescending:
00218 if (trav == OutsideDescending) return a;
00219
00220 case InsideAscending:
00221 if (trav == OutsideAscending) return a;
00222 break;
00223 case OutsideAscending:
00224 if (trav == OutsideAscending) return a;
00225 if (trav == InsideAscending && lasttrav == InsideDescending) return a;
00226 if (trav == OutsideDescending && !ignoreOutsideDesc) return a;
00227
00228
00229
00230 la = a; latrav = trav;
00231 ignoreOutsideDesc = false;
00232 break;
00233 }
00234
00235 } else {
00236
00237 switch (origtrav) {
00238 case OutsideDescending:
00239 if (trav == InsideAscending) return a;
00240 if (trav == OutsideDescending) return a;
00241 break;
00242 case InsideDescending:
00243
00244
00245 case InsideAscending:
00246
00247
00248 case OutsideAscending:
00249
00250
00251
00252
00253 if (trav == OutsideDescending) return a;
00254 if (trav == OutsideAscending) {
00255 if (la) return la;
00256
00257
00258 la = a; latrav = trav;
00259 }
00260 break;
00261 }
00262
00263 }
00264 }
00265
00266 lasttrav = trav;
00267 a = traverseRenderObjects(a, trav, toBegin, base, state);
00268 }
00269
00270 if (la) trav = latrav, a = la;
00271 return a;
00272
00273 }
00274
00283 static inline bool isUnsuitable(RenderObject *r, ObjectTraversalState trav)
00284 {
00285 if (!r) return false;
00286 return r->isTableCol() || r->isTableSection() || r->isTableRow()
00287 || (r->isText() && static_cast<RenderText *>(r)->inlineTextBoxCount() == 0);
00288 ;
00289 Q_UNUSED(trav);
00290 }
00291
00305 static inline RenderObject *advanceSuitableObject(RenderObject *r,
00306 ObjectTraversalState &trav, bool toBegin,
00307 RenderObject *base, int &state)
00308 {
00309 do {
00310 r = advanceObject(r, trav, toBegin, base, state);
00311 #if DEBUG_CARETMODE > 2
00312 kdDebug(6200) << "after advanceSWP: r " << r << " trav " << trav << " toBegin " << toBegin << endl;
00313 #endif
00314 } while (isUnsuitable(r, trav));
00315 return r;
00316 }
00317
00327 static NodeImpl *nextLeafNode(NodeImpl *r, NodeImpl *baseElem)
00328 {
00329 NodeImpl *n = r->firstChild();
00330 if (n) {
00331 while (n) { r = n; n = n->firstChild(); }
00332 return const_cast<NodeImpl *>(r);
00333 }
00334 n = r->nextSibling();
00335 if (n) {
00336 r = n;
00337 while (n) { r = n; n = n->firstChild(); }
00338 return const_cast<NodeImpl *>(r);
00339 }
00340
00341 n = r->parentNode();
00342 if (n == baseElem) n = 0;
00343 while (n) {
00344 r = n;
00345 n = r->nextSibling();
00346 if (n) {
00347 r = n;
00348 n = r->firstChild();
00349 while (n) { r = n; n = n->firstChild(); }
00350 return const_cast<NodeImpl *>(r);
00351 }
00352 n = r->parentNode();
00353 if (n == baseElem) n = 0;
00354 }
00355 return 0;
00356 }
00357
00358 #if 0 // currently not used
00359
00368 static NodeImpl *prevLeafNode(NodeImpl *r, NodeImpl *baseElem)
00369 {
00370 NodeImpl *n = r->firstChild();
00371 if (n) {
00372 while (n) { r = n; n = n->firstChild(); }
00373 return const_cast<NodeImpl *>(r);
00374 }
00375 n = r->previousSibling();
00376 if (n) {
00377 r = n;
00378 while (n) { r = n; n = n->firstChild(); }
00379 return const_cast<NodeImpl *>(r);
00380 }
00381
00382 n = r->parentNode();
00383 if (n == baseElem) n = 0;
00384 while (n) {
00385 r = n;
00386 n = r->previousSibling();
00387 if (n) {
00388 r = n;
00389 n = r->lastChild();
00390 while (n) { r = n; n = n->lastChild(); }
00391 return const_cast<NodeImpl *>(r);
00392 }
00393 n = r->parentNode();
00394 if (n == baseElem) n = 0;
00395 }
00396 return 0;
00397 }
00398 #endif
00399
00411 void mapDOMPosToRenderPos(NodeImpl *node, long offset,
00412 RenderObject *&r, long &r_ofs, bool &outside, bool &outsideEnd)
00413 {
00414 if (node->nodeType() == Node::TEXT_NODE) {
00415 outside = false;
00416 outsideEnd = false;
00417 r = node->renderer();
00418 r_ofs = offset;
00419 } else if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE) {
00420
00421
00422
00423 if (node->firstChild()) {
00424 outside = true;
00425 NodeImpl *child = offset <= 0 ? node->firstChild()
00426
00427 : node->childNode((unsigned long)offset);
00428
00429 bool atEnd = !child;
00430 #if DEBUG_CARETMODE > 5
00431 kdDebug(6200) << "mapDTR: child " << child << "@" << (child ? child->nodeName().string() : QString::null) << " atEnd " << atEnd << endl;
00432 #endif
00433 if (atEnd) child = node->lastChild();
00434
00435 r = child->renderer();
00436 r_ofs = 0;
00437 outsideEnd = atEnd;
00438
00439
00440
00441 if (r && child->nodeType() == Node::TEXT_NODE) {
00442 r = r->parent();
00443 RenderObject *o = node->renderer();
00444 while (o->continuation() && o->continuation() != r)
00445 o = o->continuation();
00446 if (!r || o->continuation() != r) {
00447 r = child->renderer();
00448 }
00449 }
00450
00451
00452
00453 if (r && r->isBR()) {
00454 r = r->objectAbove();
00455 outsideEnd = true;
00456 }
00457
00458 } else {
00459
00460 outside = false;
00461 outsideEnd = false;
00462 r = node->renderer();
00463 r_ofs = 0;
00464 }
00465
00466 } else {
00467 r = 0;
00468 kdWarning() << k_funcinfo << "Mapping from nodes of type " << node->nodeType()
00469 << " not supported!" << endl;
00470 }
00471 }
00472
00483 void mapRenderPosToDOMPos(RenderObject *r, long r_ofs,
00484 bool outside, bool outsideEnd, NodeImpl *&node, long &offset)
00485 {
00486 node = r->element();
00487 Q_ASSERT(node);
00488 #if DEBUG_CARETMODE > 5
00489 kdDebug(6200) << "mapRTD: r " << r << "@" << (r ? r->renderName() : QString::null) << (r && r->element() ? QString(".node ") + QString::number((unsigned)r->element(),16) + "@" + r->element()->nodeName().string() : QString::null) << " outside " << outside << " outsideEnd " << outsideEnd << endl;
00490 #endif
00491 if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::TEXT_NODE) {
00492
00493 if (outside) {
00494 NodeImpl *parent = node->parent();
00495
00496
00497
00498 if (r != node->renderer()) {
00499 RenderObject *o = node->renderer();
00500 while (o->continuation() && o->continuation() != r)
00501 o = o->continuation();
00502 if (o->continuation() == r) {
00503 parent = node;
00504
00505
00506 node = r->firstChild() ? r->firstChild()->element() : node;
00507 }
00508 }
00509
00510 if (!parent) goto inside;
00511
00512 offset = (long)node->nodeIndex() + outsideEnd;
00513 node = parent;
00514 #if DEBUG_CARETMODE > 5
00515 kdDebug(6200) << node << "@" << (node ? node->nodeName().string() : QString::null) << " offset " << offset << endl;
00516 #endif
00517 } else {
00518 inside:
00519 offset = r_ofs;
00520 }
00521
00522 } else {
00523 offset = 0;
00524 kdWarning() << k_funcinfo << "Mapping to nodes of type " << node->nodeType()
00525 << " not supported!" << endl;
00526 }
00527 }
00528
00530 static inline void ensureLeafNode(NodeImpl *&node, NodeImpl *base)
00531 {
00532 if (node && node->hasChildNodes()) node = nextLeafNode(node, base);
00533 }
00534
00541 static inline void mapRenderPosToTraversalState(bool outside, bool atEnd,
00542 bool toBegin, ObjectTraversalState &trav)
00543 {
00544 if (!outside) atEnd = !toBegin;
00545 if (!atEnd ^ toBegin)
00546 trav = outside ? OutsideDescending : InsideDescending;
00547 else
00548 trav = outside ? OutsideAscending : InsideAscending;
00549 }
00550
00557 static inline void mapTraversalStateToRenderPos(ObjectTraversalState trav,
00558 bool toBegin, bool &outside, bool &atEnd)
00559 {
00560 outside = false;
00561 switch (trav) {
00562 case OutsideDescending: outside = true;
00563 case InsideDescending: atEnd = toBegin; break;
00564 case OutsideAscending: outside = true;
00565 case InsideAscending: atEnd = !toBegin; break;
00566 }
00567 }
00568
00584 static RenderObject* findRenderer(NodeImpl *&node, long offset,
00585 RenderObject *base, long &r_ofs,
00586 bool &outside, bool &outsideEnd)
00587 {
00588 if (!node) return 0;
00589 RenderObject *r;
00590 mapDOMPosToRenderPos(node, offset, r, r_ofs, outside, outsideEnd);
00591 #if DEBUG_CARETMODE > 2
00592 kdDebug(6200) << "findRenderer: node " << node << " " << (node ? node->nodeName().string() : QString::null) << " offset " << offset << " r " << r << "[" << (r ? r->renderName() : QString::null) << "] r_ofs " << r_ofs << " outside " << outside << " outsideEnd " << outsideEnd << endl;
00593 #endif
00594 if (r) return r;
00595 NodeImpl *baseElem = base ? base->element() : 0;
00596 while (!r) {
00597 node = nextLeafNode(node, baseElem);
00598 if (!node) break;
00599 r = node->renderer();
00600 if (r) r_ofs = offset;
00601 }
00602 #if DEBUG_CARETMODE > 3
00603 kdDebug(6200) << "1r " << r << endl;
00604 #endif
00605 ObjectTraversalState trav;
00606 int state;
00607 mapRenderPosToTraversalState(outside, outsideEnd, false, trav);
00608 if (r && isUnsuitable(r, trav)) {
00609 r = advanceSuitableObject(r, trav, false, base, state);
00610 mapTraversalStateToRenderPos(trav, false, outside, outsideEnd);
00611 if (r) r_ofs = r->minOffset();
00612 }
00613 #if DEBUG_CARETMODE > 3
00614 kdDebug(6200) << "2r " << r << endl;
00615 #endif
00616 return r;
00617 }
00618
00622 static ElementImpl *determineBaseElement(NodeImpl *caretNode)
00623 {
00624
00625
00626
00627 DocumentImpl *doc = caretNode->getDocument();
00628 if (!doc) return 0;
00629
00630 if (doc->isHTMLDocument())
00631 return static_cast<HTMLDocumentImpl *>(doc)->body();
00632
00633 return 0;
00634 }
00635
00636
00637
00638 #if DEBUG_CARETMODE > 0
00639 void CaretBox::dump(QTextStream &ts, const QString &ind) const
00640 {
00641 ts << ind << "b@" << _box;
00642
00643 if (_box) {
00644 ts << "<" << _box->object() << ":" << _box->object()->renderName() << ">";
00645 }
00646
00647 ts << " " << _x << "+" << _y << "+" << _w << "*" << _h;
00648
00649 ts << " cb@" << cb;
00650 if (cb) ts << ":" << cb->renderName();
00651
00652 ts << " " << (_outside ? (outside_end ? "oe" : "o-") : "i-");
00653
00654 }
00655 #endif
00656
00657
00658
00659 #if DEBUG_CARETMODE > 0
00660 # define DEBUG_ACIB 1
00661 #else
00662 # define DEBUG_ACIB DEBUG_CARETMODE
00663 #endif
00664 void CaretBoxLine::addConvertedInlineBox(InlineBox *box, SeekBoxParams &sbp)
00665 {
00666
00667
00668 bool coalesceOutsideBoxes = false;
00669 CaretBoxIterator lastCoalescedBox;
00670 for (; box; box = box->nextOnLine()) {
00671 #if DEBUG_ACIB
00672 kdDebug(6200) << "box " << box << endl;
00673 kdDebug(6200) << "box->object " << box->object() << endl;
00674 kdDebug(6200) << "x " << box->m_x << " y " << box->m_y << " w " << box->m_width << " h " << box->m_height << " baseline " << box->m_baseline << " ifb " << box->isInlineFlowBox() << " itb " << box->isInlineTextBox() << " rlb " << box->isRootInlineBox() << endl;
00675 #endif
00676
00677 if (!box->object()) continue;
00678
00679 RenderStyle *s = box->object()->style(box->m_firstLine);
00680
00681 RenderStyle *ps = box->parent() && box->parent()->object()
00682 ? box->parent()->object()->style(box->parent()->m_firstLine)
00683 : s;
00684
00685 if (box->isInlineFlowBox()) {
00686 #if DEBUG_ACIB
00687 kdDebug(6200) << "isinlineflowbox " << box << endl;
00688 #endif
00689 InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(box);
00690 bool rtl = ps->direction() == RTL;
00691 const QFontMetrics &pfm = ps->fontMetrics();
00692
00693 if (flowBox->includeLeftEdge()) {
00694
00695
00696
00697 if (coalesceOutsideBoxes) {
00698 if (sbp.equalsBox(flowBox, true, false)) {
00699 sbp.it = lastCoalescedBox;
00700 Q_ASSERT(!sbp.found);
00701 sbp.found = true;
00702 }
00703 } else {
00704 addCreatedFlowBoxEdge(flowBox, pfm, true, rtl);
00705 sbp.check(preEnd());
00706 }
00707 }
00708
00709 if (flowBox->firstChild()) {
00710 #if DEBUG_ACIB
00711 kdDebug(6200) << "this " << this << " flowBox " << flowBox << " firstChild " << flowBox->firstChild() << endl;
00712 kdDebug(6200) << "== recursive invocation" << endl;
00713 #endif
00714 addConvertedInlineBox(flowBox->firstChild(), sbp);
00715 #if DEBUG_ACIB
00716 kdDebug(6200) << "== recursive invocation end" << endl;
00717 #endif
00718 }
00719 else {
00720 addCreatedFlowBoxInside(flowBox, s->fontMetrics());
00721 sbp.check(preEnd());
00722 }
00723
00724 if (flowBox->includeRightEdge()) {
00725 addCreatedFlowBoxEdge(flowBox, pfm, false, rtl);
00726 lastCoalescedBox = preEnd();
00727 sbp.check(lastCoalescedBox);
00728 coalesceOutsideBoxes = true;
00729 }
00730
00731 } else if (box->isInlineTextBox()) {
00732 #if DEBUG_ACIB
00733 kdDebug(6200) << "isinlinetextbox " << box << (box->object() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), kMin(box->maxOffset() - box->minOffset(), 15L)).string()) : QString::null) << endl;
00734 #endif
00735 caret_boxes.append(new CaretBox(box, false, false));
00736 sbp.check(preEnd());
00737
00738 coalesceOutsideBoxes = false;
00739
00740 } else {
00741 #if DEBUG_ACIB
00742 kdDebug(6200) << "some replaced or what " << box << endl;
00743 #endif
00744
00745 bool rtl = ps->direction() == RTL;
00746 const QFontMetrics &pfm = ps->fontMetrics();
00747
00748 if (coalesceOutsideBoxes) {
00749 if (sbp.equalsBox(box, true, false)) {
00750 sbp.it = lastCoalescedBox;
00751 Q_ASSERT(!sbp.found);
00752 sbp.found = true;
00753 }
00754 } else {
00755 addCreatedInlineBoxEdge(box, pfm, true, rtl);
00756 sbp.check(preEnd());
00757 }
00758
00759 caret_boxes.append(new CaretBox(box, false, false));
00760 sbp.check(preEnd());
00761
00762 addCreatedInlineBoxEdge(box, pfm, false, rtl);
00763 lastCoalescedBox = preEnd();
00764 sbp.check(lastCoalescedBox);
00765 coalesceOutsideBoxes = true;
00766 }
00767 }
00768 }
00769 #undef DEBUG_ACIB
00770
00771 void CaretBoxLine::addCreatedFlowBoxInside(InlineFlowBox *flowBox, const QFontMetrics &fm)
00772 {
00773
00774 CaretBox *caretBox = new CaretBox(flowBox, false, false);
00775 caret_boxes.append(caretBox);
00776
00777
00778
00779
00780
00781 caretBox->_y += flowBox->baseline() - fm.ascent();
00782 caretBox->_h = fm.height();
00783 }
00784
00785 void CaretBoxLine::addCreatedFlowBoxEdge(InlineFlowBox *flowBox, const QFontMetrics &fm, bool left, bool rtl)
00786 {
00787 CaretBox *caretBox = new CaretBox(flowBox, true, !left);
00788 caret_boxes.append(caretBox);
00789
00790 if (left ^ rtl) caretBox->_x -= flowBox->paddingLeft() + flowBox->borderLeft() + 1;
00791 else caretBox->_x += caretBox->_w + flowBox->paddingRight() + flowBox->borderRight();
00792
00793 caretBox->_y += flowBox->baseline() - fm.ascent();
00794 caretBox->_h = fm.height();
00795 caretBox->_w = 1;
00796 }
00797
00798 void CaretBoxLine::addCreatedInlineBoxEdge(InlineBox *box, const QFontMetrics &fm, bool left, bool rtl)
00799 {
00800 CaretBox *caretBox = new CaretBox(box, true, !left);
00801 caret_boxes.append(caretBox);
00802
00803 if (left ^ rtl) caretBox->_x--;
00804 else caretBox->_x += caretBox->_w;
00805
00806 caretBox->_y += box->baseline() - fm.ascent();
00807 caretBox->_h = fm.height();
00808 caretBox->_w = 1;
00809 }
00810
00811 CaretBoxLine *CaretBoxLine::constructCaretBoxLine(CaretBoxLineDeleter *deleter,
00812 InlineFlowBox *basicFlowBox, InlineBox *seekBox, bool seekOutside,
00813 bool seekOutsideEnd, CaretBoxIterator &iter, RenderObject *seekObject)
00814
00815 {
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 CaretBoxLine *result = new CaretBoxLine(basicFlowBox);
00827 deleter->append(result);
00828
00829 SeekBoxParams sbp(seekBox, seekOutside, seekOutsideEnd, seekObject, iter);
00830
00831
00832 result->addConvertedInlineBox(basicFlowBox, sbp);
00833
00834 if (!sbp.found) sbp.it = result->end();
00835
00836 return result;
00837 }
00838
00839 CaretBoxLine *CaretBoxLine::constructCaretBoxLine(CaretBoxLineDeleter *deleter,
00840 RenderBox *cb, bool outside, bool outsideEnd, CaretBoxIterator &iter)
00841 {
00842 int _x = cb->xPos();
00843 int _y = cb->yPos();
00844 int height;
00845 int width = 1;
00846
00847 if (outside) {
00848
00849 RenderStyle *s = cb->element() && cb->element()->parent()
00850 && cb->element()->parent()->renderer()
00851 ? cb->element()->parent()->renderer()->style()
00852 : cb->style();
00853 bool rtl = s->direction() == RTL;
00854
00855 const QFontMetrics &fm = s->fontMetrics();
00856 height = fm.height();
00857
00858 if (!outsideEnd) {
00859 _x--;
00860 } else {
00861 _x += cb->width();
00862 }
00863
00864 int hl = fm.leading() / 2;
00865 int baseline = cb->baselinePosition(false);
00866 if (!cb->isReplaced() || cb->style()->display() == BLOCK) {
00867 if (!outsideEnd ^ rtl)
00868 _y -= fm.leading() / 2;
00869 else
00870 _y += kMax(cb->height() - fm.ascent() - hl, 0);
00871 } else {
00872 _y += baseline - fm.ascent() - hl;
00873 }
00874
00875 } else {
00876
00877 RenderStyle *s = cb->style();
00878 const QFontMetrics &fm = s->fontMetrics();
00879 height = fm.height();
00880
00881 _x += cb->borderLeft() + cb->paddingLeft();
00882 _y += cb->borderTop() + cb->paddingTop();
00883
00884
00885 switch (s->textAlign()) {
00886 case LEFT:
00887 case KHTML_LEFT:
00888 case TAAUTO:
00889 case JUSTIFY:
00890 break;
00891 case CENTER:
00892 case KHTML_CENTER:
00893 _x += cb->contentWidth() / 2;
00894 break;
00895 case KHTML_RIGHT:
00896 case RIGHT:
00897 _x += cb->contentWidth();
00898 break;
00899 }
00900 }
00901
00902 CaretBoxLine *result = new CaretBoxLine;
00903 deleter->append(result);
00904 result->caret_boxes.append(new CaretBox(_x, _y, width, height, cb,
00905 outside, outsideEnd));
00906 iter = result->begin();
00907 return result;
00908 }
00909
00910 #if DEBUG_CARETMODE > 0
00911 void CaretBoxLine::dump(QTextStream &ts, const QString &ind) const
00912 {
00913 ts << ind << "cbl: baseFlowBox@" << basefb << endl;
00914 QString ind2 = ind + " ";
00915 for (size_t i = 0; i < caret_boxes.size(); i++) {
00916 if (i > 0) ts << endl;
00917 caret_boxes[i]->dump(ts, ind2);
00918 }
00919 }
00920 #endif
00921
00922
00923
00931 inline InlineFlowBox *seekBaseFlowBox(InlineBox *b, RenderObject *base = 0)
00932 {
00933
00934 while (b->parent() && b->object() != base) {
00935 b = b->parent();
00936 }
00937 Q_ASSERT(b->isInlineFlowBox());
00938 return static_cast<InlineFlowBox *>(b);
00939 }
00940
00943 inline bool isBlockRenderReplaced(RenderObject *r)
00944 {
00945 return r->isRenderReplaced() && r->style()->display() == BLOCK;
00946 }
00947
00964 static CaretBoxLine* findCaretBoxLine(DOM::NodeImpl *node, long offset,
00965 CaretBoxLineDeleter *cblDeleter, RenderObject *base,
00966 long &r_ofs, CaretBoxIterator &caretBoxIt)
00967 {
00968 bool outside, outsideEnd;
00969 RenderObject *r = findRenderer(node, offset, base, r_ofs, outside, outsideEnd);
00970 if (!r) { return 0; }
00971 #if DEBUG_CARETMODE > 0
00972 kdDebug(6200) << "=================== findCaretBoxLine" << endl;
00973 kdDebug(6200) << "node " << node << " offset: " << offset << " r " << r->renderName() << "[" << r << "].node " << r->element()->nodeName().string() << "[" << r->element() << "]" << " r_ofs " << r_ofs << " outside " << outside << " outsideEnd " << outsideEnd << endl;
00974 #endif
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 if (r->isText()) do {
00987 RenderText *t = static_cast<RenderText *>(r);
00988 int dummy;
00989 InlineBox *b = t->findInlineTextBox(offset, dummy, true);
00990
00991
00992
00993 if (!b) {
00994 if (t->m_lines.count() > 0)
00995 b = t->m_lines[t->m_lines.count() - 1];
00996 else
00997 break;
00998 }
00999 Q_ASSERT(b);
01000 outside = false;
01001 InlineFlowBox *baseFlowBox = seekBaseFlowBox(b, base);
01002 #if DEBUG_CARETMODE > 2
01003 kdDebug(6200) << "text-box b: " << b << " baseFlowBox: " << baseFlowBox << (b && b->object() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(b->object())->str->s+b->minOffset(), kMin(b->maxOffset() - b->minOffset(), 15L)).string()) : QString::null) << endl;
01004 #endif
01005 #if 0
01006 if (t->containingBlock()->isListItem()) dumpLineBoxes(static_cast<RenderFlow *>(t->containingBlock()));
01007 #endif
01008 #if DEBUG_CARETMODE > 0
01009 kdDebug(6200) << "=================== end findCaretBoxLine (renderText)" << endl;
01010 #endif
01011 return CaretBoxLine::constructCaretBoxLine(cblDeleter, baseFlowBox,
01012 b, outside, outsideEnd, caretBoxIt);
01013 } while(false);
01014
01015
01016 bool isrepl = isBlockRenderReplaced(r);
01017 if (r->isRenderBlock() || r->isRenderInline() || isrepl) {
01018 RenderFlow *flow = static_cast<RenderFlow *>(r);
01019 InlineFlowBox *firstLineBox = isrepl ? 0 : flow->firstLineBox();
01020
01021
01022
01023
01024 if (isrepl || r->isRenderBlock() && (outside || !firstLineBox)
01025 || r->isRenderInline() && !firstLineBox) {
01026 #if DEBUG_CARETMODE > 0
01027 kdDebug(6200) << "=================== end findCaretBoxLine (box " << (outside ? (outsideEnd ? "outside end" : "outside begin") : "inside") << ")" << endl;
01028 #endif
01029 Q_ASSERT(r->isBox());
01030 return CaretBoxLine::constructCaretBoxLine(cblDeleter,
01031 static_cast<RenderBox *>(r), outside, outsideEnd, caretBoxIt);
01032 }
01033
01034 kdDebug(6200) << "firstlinebox " << firstLineBox << endl;
01035 InlineFlowBox *baseFlowBox = seekBaseFlowBox(firstLineBox, base);
01036 return CaretBoxLine::constructCaretBoxLine(cblDeleter, baseFlowBox,
01037 firstLineBox, outside, outsideEnd, caretBoxIt);
01038 }
01039
01040 RenderBlock *cb = r->containingBlock();
01041
01042 Q_ASSERT(cb);
01043
01044
01045
01046 if (!cb->isRenderBlock()) {
01047 kdWarning() << "containing block is no render block!!! crash imminent" << endl;
01048 }
01049
01050 InlineFlowBox *flowBox = cb->firstLineBox();
01051
01052
01053
01054 if (!flowBox) {
01055
01056
01057
01058
01059
01060 #if DEBUG_CARETMODE > 0
01061 kdDebug(6200) << "=================== end findCaretBoxLine (2)" << endl;
01062 #endif
01063 return CaretBoxLine::constructCaretBoxLine(cblDeleter, cb,
01064 outside, outsideEnd, caretBoxIt);
01065 }
01066
01067
01068
01069
01070 for (; flowBox; flowBox = static_cast<InlineFlowBox *>(flowBox->nextLineBox())) {
01071 #if DEBUG_CARETMODE > 0
01072 kdDebug(6200) << "[scan line]" << endl;
01073 #endif
01074
01075
01076 InlineFlowBox *baseFlowBox = seekBaseFlowBox(flowBox, base);
01077 CaretBoxLine *cbl = CaretBoxLine::constructCaretBoxLine(cblDeleter,
01078 baseFlowBox, 0, outside, outsideEnd, caretBoxIt, r);
01079 #if DEBUG_CARETMODE > 5
01080 kdDebug(6200) << cbl->information() << endl;
01081 #endif
01082 if (caretBoxIt != cbl->end()) {
01083 #if DEBUG_CARETMODE > 0
01084 kdDebug(6200) << "=================== end findCaretBoxLine (3)" << endl;
01085 #endif
01086 return cbl;
01087 }
01088 }
01089
01090
01091
01092
01093 Q_ASSERT(!flowBox);
01094 CaretBoxLine *cbl = findCaretBoxLine(nextLeafNode(node, base ? base->element() : 0), 0, cblDeleter, base, r_ofs, caretBoxIt);
01095 #if DEBUG_CARETMODE > 0
01096 kdDebug(6200) << "=================== end findCaretBoxLine" << endl;
01097 #endif
01098 return cbl;
01099 }
01100
01107 static inline RenderTable *findTableUpTo(RenderObject *r, RenderFlow *cb)
01108 {
01109 while (r && r != cb && !r->isTable()) r = r->parent();
01110 return r && r->isTable() ? static_cast<RenderTable *>(r) : 0;
01111 }
01112
01115 static inline bool isDescendant(RenderObject *r, RenderObject *cb)
01116 {
01117 while (r && r != cb) r = r->parent();
01118 return r;
01119 }
01120
01131 static bool containsEditableElement(KHTMLPart *part, RenderBlock *cb,
01132 RenderTable *&table, bool fromEnd = false)
01133 {
01134 RenderObject *r = cb;
01135 if (fromEnd)
01136 while (r->lastChild()) r = r->lastChild();
01137 else
01138 while (r->firstChild()) r = r->firstChild();
01139
01140 RenderTable *tempTable = 0;
01141 table = 0;
01142 bool withinCb;
01143
01144 ObjectTraversalState trav = InsideDescending;
01145 do {
01146 bool modWithinCb = withinCb = isDescendant(r, cb);
01147
01148
01149 if (!modWithinCb) {
01150 modWithinCb = true;
01151 r = cb;
01152 } else
01153 tempTable = findTableUpTo(r, cb);
01154
01155 #if DEBUG_CARETMODE > 1
01156 kdDebug(6201) << "cee: r " << (r ? r->renderName() : QString::null) << "@" << r << " cb " << cb << " withinCb " << withinCb << " modWithinCb " << modWithinCb << " tempTable " << tempTable << endl;
01157 #endif
01158 if (r && modWithinCb && r->element() && !isUnsuitable(r, trav)
01159 && (part->isCaretMode() || part->isEditable()
01160 || r->style()->userInput() == UI_ENABLED)) {
01161 table = tempTable;
01162 #if DEBUG_CARETMODE > 1
01163 kdDebug(6201) << "cee: editable" << endl;
01164 #endif
01165 return true;
01166 }
01167
01168
01169
01170
01171 r = fromEnd ? r->objectAbove() : r->objectBelow();
01172 } while (r && withinCb);
01173 return false;
01174 }
01175
01188 static bool containsEditableChildElement(KHTMLPart *part, RenderBlock *cb,
01189 RenderTable *&table, bool fromEnd, RenderObject *start)
01190 {
01191 int state = 0;
01192 ObjectTraversalState trav = OutsideAscending;
01193
01194 RenderObject *r = start;
01195 do {
01196 r = traverseRenderObjects(r, trav, fromEnd, cb->parent(), state);
01197 } while(r && !(state & AdvancedToSibling));
01198
01199
01200
01201
01202 if (!r) return false;
01203
01204 if (fromEnd)
01205 while (r->firstChild()) r = r->firstChild();
01206 else
01207 while (r->lastChild()) r = r->lastChild();
01208
01209 if (!r) return false;
01210
01211 RenderTable *tempTable = 0;
01212 table = 0;
01213 bool withinCb = false;
01214 do {
01215
01216 bool modWithinCb = withinCb = isDescendant(r, cb);
01217
01218
01219 if (!modWithinCb) {
01220 modWithinCb = true;
01221 r = cb;
01222 } else
01223 tempTable = findTableUpTo(r, cb);
01224
01225 #if DEBUG_CARETMODE > 1
01226 kdDebug(6201) << "cece: r " << (r ? r->renderName() : QString::null) << "@" << r << " cb " << cb << " withinCb " << withinCb << " modWithinCb " << modWithinCb << " tempTable " << tempTable << endl;
01227 #endif
01228 if (r && withinCb && r->element() && !isUnsuitable(r, trav)
01229 && (part->isCaretMode() || part->isEditable()
01230 || r->style()->userInput() == UI_ENABLED)) {
01231 table = tempTable;
01232 #if DEBUG_CARETMODE > 1
01233 kdDebug(6201) << "cece: editable" << endl;
01234 #endif
01235 return true;
01236 }
01237
01238 r = fromEnd ? r->objectAbove() : r->objectBelow();
01239 } while (withinCb);
01240 return false;
01241 }
01242
01243
01244
01245 LinearDocument::LinearDocument(KHTMLPart *part, NodeImpl *node, long offset,
01246 CaretAdvancePolicy advancePolicy, ElementImpl *baseElem)
01247 : node(node), offset(offset), m_part(part),
01248 advPol(advancePolicy), base(0)
01249 {
01250 if (node == 0) return;
01251
01252 if (baseElem) {
01253 RenderObject *b = baseElem->renderer();
01254 if (b && (b->isRenderBlock() || b->isRenderInline()))
01255 base = b;
01256 }
01257
01258 initPreBeginIterator();
01259 initEndIterator();
01260 }
01261
01262 LinearDocument::~LinearDocument()
01263 {
01264 }
01265
01266 int LinearDocument::count() const
01267 {
01268
01269 return 1;
01270 }
01271
01272 LinearDocument::Iterator LinearDocument::current()
01273 {
01274 return LineIterator(this, node, offset);
01275 }
01276
01277 LinearDocument::Iterator LinearDocument::begin()
01278 {
01279 NodeImpl *n = base ? base->element() : 0;
01280 if (!base) n = node ? node->getDocument() : 0;
01281 if (!n) return end();
01282
01283 n = n->firstChild();
01284 if (advPol == LeafsOnly)
01285 while (n->firstChild()) n = n->firstChild();
01286
01287 if (!n) return end();
01288 return LineIterator(this, n, n->minOffset());
01289 }
01290
01291 LinearDocument::Iterator LinearDocument::preEnd()
01292 {
01293 NodeImpl *n = base ? base->element() : 0;
01294 if (!base) n = node ? node->getDocument() : 0;
01295 if (!n) return preBegin();
01296
01297 n = n->lastChild();
01298 if (advPol == LeafsOnly)
01299 while (n->lastChild()) n = n->lastChild();
01300
01301 if (!n) return preBegin();
01302 return LineIterator(this, n, n->maxOffset());
01303 }
01304
01305 void LinearDocument::initPreBeginIterator()
01306 {
01307 _preBegin = LineIterator(this, 0, 0);
01308 }
01309
01310 void LinearDocument::initEndIterator()
01311 {
01312 _end = LineIterator(this, 0, 1);
01313 }
01314
01315
01316
01317 CaretBoxIterator LineIterator::currentBox ;
01318 long LineIterator::currentOffset ;
01319
01320 LineIterator::LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset)
01321 : lines(l)
01322 {
01323
01324 if (!node) { cbl = 0; return; }
01325 cbl = findCaretBoxLine(node, offset, &lines->cblDeleter,
01326 l->baseObject(), currentOffset, currentBox);
01327
01328 #if DEBUG_CARETMODE > 0
01329 if (!cbl) kdDebug(6200) << "no render object found!" << endl;
01330 #endif
01331 if (!cbl) return;
01332 #if DEBUG_CARETMODE > 1
01333 kdDebug(6200) << "LineIterator: offset " << offset << " outside " << cbl->isOutside() << endl;
01334 #endif
01335 #if DEBUG_CARETMODE > 3
01336 kdDebug(6200) << cbl->information() << endl;
01337 #endif
01338 if (currentBox == cbl->end()) {
01339 #if DEBUG_CARETMODE > 0
01340 kdDebug(6200) << "LineIterator: findCaretBoxLine failed" << endl;
01341 #endif
01342 cbl = 0;
01343 }
01344 }
01345
01346 void LineIterator::nextBlock()
01347 {
01348 RenderObject *base = lines->baseObject();
01349
01350 bool cb_outside = cbl->isOutside();
01351 bool cb_outside_end = cbl->isOutsideEnd();
01352
01353 {
01354 RenderObject *r = cbl->enclosingObject();
01355
01356 ObjectTraversalState trav;
01357 int state;
01358 mapRenderPosToTraversalState(cb_outside, cb_outside_end, false, trav);
01359 #if DEBUG_CARETMODE > 1
01360 kdDebug(6200) << "nextBlock: before adv r" << r << " " << (r ? r->renderName() : QString::null) << (r && r->isText() ? " contains \"" + QString(((RenderText *)r)->str->s, QMIN(((RenderText *)r)->str->l,15)) + "\"" : QString::null) << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;
01361 #endif
01362 r = advanceSuitableObject(r, trav, false, base, state);
01363 if (!r) {
01364 cbl = 0;
01365 return;
01366 }
01367
01368 mapTraversalStateToRenderPos(trav, false, cb_outside, cb_outside_end);
01369 #if DEBUG_CARETMODE > 1
01370 kdDebug(6200) << "nextBlock: after r" << r << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;
01371 #endif
01372 #if DEBUG_CARETMODE > 0
01373 kdDebug(6200) << "++: r " << r << "[" << (r?r->renderName():QString::null) << "]" << endl;
01374 #endif
01375
01376 RenderBlock *cb;
01377
01378
01379 bool isrepl = isBlockRenderReplaced(r);
01380 if (r->isRenderBlock() || isrepl) {
01381 RenderBox *cb = static_cast<RenderBox *>(r);
01382
01383 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
01384 cb_outside, cb_outside_end, currentBox);
01385
01386 #if DEBUG_CARETMODE > 0
01387 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;
01388 #endif
01389 return;
01390 } else {
01391 cb = r->containingBlock();
01392 Q_ASSERT(cb->isRenderBlock());
01393 }
01394 InlineFlowBox *flowBox = cb->firstLineBox();
01395 #if DEBUG_CARETMODE > 0
01396 kdDebug(6200) << "++: flowBox " << flowBox << " cb " << cb << "[" << (cb?cb->renderName()+QString(".node ")+QString::number((unsigned)cb->element(),16)+(cb->element()?"@"+cb->element()->nodeName().string():QString::null):QString::null) << "]" << endl;
01397 #endif
01398 Q_ASSERT(flowBox);
01399 if (!flowBox) {
01400 cb_outside = cb_outside_end = true;
01401 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
01402 cb_outside, cb_outside_end, currentBox);
01403 return;
01404 }
01405
01406 bool seekOutside = false, seekOutsideEnd = false;
01407 CaretBoxIterator it;
01408 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
01409 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
01410 }
01411 }
01412
01413 void LineIterator::prevBlock()
01414 {
01415 RenderObject *base = lines->baseObject();
01416
01417 bool cb_outside = cbl->isOutside();
01418 bool cb_outside_end = cbl->isOutsideEnd();
01419
01420 {
01421 RenderObject *r = cbl->enclosingObject();
01422 if (r->isAnonymous() && !cb_outside)
01423 cb_outside = true, cb_outside_end = false;
01424
01425 ObjectTraversalState trav;
01426 int state;
01427 mapRenderPosToTraversalState(cb_outside, cb_outside_end, true, trav);
01428 #if DEBUG_CARETMODE > 1
01429 kdDebug(6200) << "prevBlock: before adv r" << r << " " << (r ? r->renderName() : QString::null) << (r && r->isText() ? " contains \"" + QString(((RenderText *)r)->str->s, QMIN(((RenderText *)r)->str->l,15)) + "\"" : QString::null) << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;
01430 #endif
01431 r = advanceSuitableObject(r, trav, true, base, state);
01432 if (!r) {
01433 cbl = 0;
01434 return;
01435 }
01436
01437 mapTraversalStateToRenderPos(trav, true, cb_outside, cb_outside_end);
01438 #if DEBUG_CARETMODE > 1
01439 kdDebug(6200) << "prevBlock: after r" << r << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;
01440 #endif
01441 #if DEBUG_CARETMODE > 0
01442 kdDebug(6200) << "--: r " << r << "[" << (r?r->renderName():QString::null) << "]" << endl;
01443 #endif
01444
01445 RenderBlock *cb;
01446
01447
01448 bool isrepl = isBlockRenderReplaced(r);
01449
01450 if (r->isRenderBlock() || isrepl) {
01451 RenderBox *cb = static_cast<RenderBox *>(r);
01452
01453 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
01454 cb_outside, cb_outside_end, currentBox);
01455
01456 #if DEBUG_CARETMODE > 0
01457 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;
01458 #endif
01459 return;
01460 } else {
01461 cb = r->containingBlock();
01462 Q_ASSERT(cb->isRenderBlock());
01463 }
01464 InlineFlowBox *flowBox = cb->lastLineBox();
01465 #if DEBUG_CARETMODE > 0
01466 kdDebug(6200) << "--: flowBox " << flowBox << " cb " << cb << "[" << (cb?cb->renderName()+QString(".node ")+QString::number((unsigned)cb->element(),16)+(cb->element()?"@"+cb->element()->nodeName().string():QString::null):QString::null) << "]" << endl;
01467 #endif
01468 Q_ASSERT(flowBox);
01469 if (!flowBox) {
01470 cb_outside = true; cb_outside_end = false;
01471 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
01472 cb_outside, cb_outside_end, currentBox);
01473 return;
01474 }
01475
01476 bool seekOutside = false, seekOutsideEnd = false;
01477 CaretBoxIterator it;
01478 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
01479 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
01480 }
01481 }
01482
01483 void LineIterator::advance(bool toBegin)
01484 {
01485 InlineFlowBox *flowBox = cbl->baseFlowBox();
01486 if (flowBox) {
01487 flowBox = static_cast<InlineFlowBox *>(toBegin ? flowBox->prevLineBox() : flowBox->nextLineBox());
01488 if (flowBox) {
01489 bool seekOutside = false, seekOutsideEnd = false;
01490 CaretBoxIterator it;
01491 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
01492 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
01493 }
01494 }
01495
01496
01497 if (!flowBox) { if (toBegin) prevBlock(); else nextBlock(); }
01498
01499 #if DEBUG_CARETMODE > 3
01500 if (cbl) kdDebug(6200) << cbl->information() << endl;
01501 #endif
01502 }
01503
01504
01505
01506 void EditableCaretBoxIterator::advance(bool toBegin)
01507 {
01508 #if DEBUG_CARETMODE > 3
01509 kdDebug(6200) << "---------------" << k_funcinfo << "toBegin " << toBegin << endl;
01510 #endif
01511 const CaretBoxIterator preBegin = cbl->preBegin();
01512 const CaretBoxIterator end = cbl->end();
01513
01514 CaretBoxIterator lastbox = *this, curbox;
01515 bool islastuseable = true;
01516 bool iscuruseable;
01517
01518 adjacent = true;
01519
01520 #if DEBUG_CARETMODE > 4
01521
01522 #endif
01523
01524 if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++();
01525 bool curAtEnd = *this == preBegin || *this == end;
01526 curbox = *this;
01527 bool atEnd = true;
01528 if (!curAtEnd) {
01529 iscuruseable = isEditable(curbox, toBegin);
01530 if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++();
01531 atEnd = *this == preBegin || *this == end;
01532 }
01533 while (!curAtEnd) {
01534 bool haslast = lastbox != end && lastbox != preBegin;
01535 bool hascoming = !atEnd;
01536 bool iscominguseable = true;
01537
01538 if (!atEnd) iscominguseable = isEditable(*this, toBegin);
01539 if (iscuruseable) {
01540 #if DEBUG_CARETMODE > 3
01541 kdDebug(6200) << "ebit::advance: " << (*curbox)->object() << "@" << (*curbox)->object()->renderName() << ".node " << (*curbox)->object()->element() << "[" << ((*curbox)->object()->element() ? (*curbox)->object()->element()->nodeName().string() : QString::null) << "] inline " << (*curbox)->isInline() << " outside " << (*curbox)->isOutside() << " outsideEnd " << (*curbox)->isOutsideEnd() << endl;
01542 #endif
01543
01544 CaretBox *box = *curbox;
01545 if (box->isOutside()) {
01546
01547
01548 if (!box->isInline()) break;
01549
01550 if (advpol == VisibleFlows) break;
01551
01552
01553
01554 InlineBox *ibox = box->inlineBox();
01555
01556 InlineBox *prev = box->isOutsideEnd() ? ibox : ibox->prevOnLine();
01557
01558 InlineBox *next = box->isOutsideEnd() ? ibox->nextOnLine() : ibox;
01559
01560 const bool isprevindicated = !prev || isIndicatedInlineBox(prev);
01561 const bool isnextindicated = !next || isIndicatedInlineBox(next);
01562 const bool last = haslast && !islastuseable;
01563 const bool coming = hascoming && !iscominguseable;
01564 const bool left = !prev || prev->isInlineFlowBox() && isprevindicated
01565 || (toBegin && coming || !toBegin && last);
01566 const bool right = !next || next->isInlineFlowBox() && isnextindicated
01567 || (!toBegin && coming || toBegin && last);
01568 const bool text2indicated = toBegin && next && next->isInlineTextBox()
01569 && isprevindicated
01570 || !toBegin && prev && prev->isInlineTextBox() && isnextindicated;
01571 const bool indicated2text = !toBegin && next && next->isInlineTextBox()
01572 && prev && isprevindicated
01573
01574 ;
01575 #if DEBUG_CARETMODE > 5
01576 kdDebug(6200) << "prev " << prev << " haslast " << haslast << " islastuseable " << islastuseable << " left " << left << " next " << next << " hascoming " << hascoming << " iscominguseable " << iscominguseable << " right " << right << " text2indicated " << text2indicated << " indicated2text " << indicated2text << endl;
01577 #endif
01578
01579 if (left && right && !text2indicated || indicated2text) {
01580 adjacent = false;
01581 #if DEBUG_CARETMODE > 4
01582 kdDebug(6200) << "left && right && !text2indicated || indicated2text" << endl;
01583 #endif
01584 break;
01585 }
01586
01587 } else {
01588
01589 #if DEBUG_CARETMODE > 4
01590 if (box->isInline()) {
01591 InlineBox *ibox = box->inlineBox();
01592 kdDebug(6200) << "inside " << (!ibox->isInlineFlowBox() || static_cast<InlineFlowBox *>(ibox)->firstChild() ? "non-empty" : "empty") << (isIndicatedInlineBox(ibox) ? " indicated" : "") << " adjacent=" << adjacent << endl;
01593 }
01594 #if 0
01595 RenderStyle *s = ibox->object()->style();
01596 kdDebug(6200) << "bordls " << s->borderLeftStyle()
01597 << " bordl " << (s->borderLeftStyle() != BNONE)
01598 << " bordr " << (s->borderRightStyle() != BNONE)
01599 << " bordt " << (s->borderTopStyle() != BNONE)
01600 << " bordb " << (s->borderBottomStyle() != BNONE)
01601 << " padl " << s->paddingLeft().value()
01602 << " padr " << s->paddingRight().value()
01603 << " padt " << s->paddingTop().value()
01604 << " padb " << s->paddingBottom().value()
01605
01606
01607 << " marl " << s->marginLeft().value()
01608 << " marr " << s->marginRight().value()
01609 << endl;
01610 #endif
01611 #endif
01612 break;
01613 }
01614
01615 } else {
01616
01617 if (!(*curbox)->isOutside()) {
01618
01619 adjacent = false;
01620 }
01621
01622 }
01623 lastbox = curbox;
01624 islastuseable = iscuruseable;
01625 curbox = *this;
01626 iscuruseable = iscominguseable;
01627 curAtEnd = atEnd;
01628 if (!atEnd) {
01629 if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++();
01630 atEnd = *this == preBegin || *this == end;
01631 }
01632 }
01633
01634 *static_cast<CaretBoxIterator *>(this) = curbox;
01635 #if DEBUG_CARETMODE > 4
01636
01637 #endif
01638 #if DEBUG_CARETMODE > 3
01639 kdDebug(6200) << "---------------" << k_funcinfo << "end " << endl;
01640 #endif
01641 }
01642
01643 bool EditableCaretBoxIterator::isEditable(const CaretBoxIterator &boxit, bool fromEnd)
01644 {
01645 Q_ASSERT(boxit != cbl->end() && boxit != cbl->preBegin());
01646 CaretBox *b = *boxit;
01647 RenderObject *r = b->object();
01648 #if DEBUG_CARETMODE > 0
01649
01650 kdDebug(6200) << "isEditable r" << r << ": " << (r ? r->renderName() : QString::null) << (r && r->isText() ? " contains \"" + QString(((RenderText *)r)->str->s, QMIN(((RenderText *)r)->str->l,15)) + "\"" : QString::null) << endl;
01651 #endif
01652
01653
01654
01655 NodeImpl *node = r->element();
01656 ObjectTraversalState trav;
01657 mapRenderPosToTraversalState(b->isOutside(), b->isOutsideEnd(), fromEnd, trav);
01658 if (isUnsuitable(r, trav) || !node) {
01659 return false;
01660 }
01661
01662
01663 if (!b->isOutside() && r->isRenderReplaced() && !r->firstChild())
01664 return false;
01665
01666 RenderObject *eff_r = r;
01667 bool globallyNavigable = m_part->isCaretMode() || m_part->isEditable();
01668
01669
01670 if (b->isOutside() && !globallyNavigable) {
01671 NodeImpl *par = node->parent();
01672
01673
01674 Q_ASSERT(par);
01675 if (par) node = par;
01676 eff_r = node->renderer();
01677 Q_ASSERT(eff_r);
01678 }
01679
01680 bool result = globallyNavigable || eff_r->style()->userInput() == UI_ENABLED;
01681 #if DEBUG_CARETMODE > 0
01682 kdDebug(6200) << result << endl;
01683 #endif
01684 return result;
01685 }
01686
01687
01688
01689 void EditableLineIterator::advance(bool toBegin)
01690 {
01691 CaretAdvancePolicy advpol = lines->advancePolicy();
01692 LineIterator lasteditable, lastindicated;
01693 bool haslasteditable = false;
01694 bool haslastindicated = false;
01695 bool uselasteditable = false;
01696
01697 LineIterator::advance(toBegin);
01698 while (cbl) {
01699 if (isEditable(*this)) {
01700 #if DEBUG_CARETMODE > 3
01701 kdDebug(6200) << "advance: " << cbl->enclosingObject() << "@" << cbl->enclosingObject()->renderName() << ".node " << cbl->enclosingObject()->element() << "[" << (cbl->enclosingObject()->element() ? cbl->enclosingObject()->element()->nodeName().string() : QString::null) << "]" << endl;
01702 #endif
01703
01704 bool hasindicated = isIndicatedFlow(cbl->enclosingObject());
01705 if (hasindicated) {
01706 haslastindicated = true;
01707 lastindicated = *this;
01708 }
01709
01710 switch (advpol) {
01711 case IndicatedFlows:
01712 if (hasindicated) goto wend;
01713
01714 case LeafsOnly:
01715 if (cbl->isOutside()) break;
01716
01717 case VisibleFlows: goto wend;
01718 }
01719
01720
01721 lasteditable = *this;
01722 haslasteditable = true;
01723 #if DEBUG_CARETMODE > 4
01724 kdDebug(6200) << "remembered lasteditable " << *lasteditable << endl;
01725 #endif
01726 } else {
01727
01728
01729
01730
01731
01732 if (haslasteditable) { uselasteditable = true; break; }
01733
01734 }
01735 LineIterator::advance(toBegin);
01736 }
01737 wend:
01738
01739 if (uselasteditable) *this = haslastindicated ? lastindicated : lasteditable;
01740 if (!cbl && haslastindicated) *this = lastindicated;
01741 }
01742
01743
01744
01745 void EditableCharacterIterator::initFirstChar()
01746 {
01747 CaretBox *box = *ebit;
01748 InlineBox *b = box->inlineBox();
01749 if (_offset == box->maxOffset())
01750 peekNext();
01751 else if (b && !box->isOutside() && b->isInlineTextBox())
01752 _char = static_cast<RenderText *>(b->object())->str->s[_offset].unicode();
01753 else
01754 _char = -1;
01755 }
01756
01760 static inline bool isCaretBoxEmpty(CaretBox *box) {
01761 if (!box->isInline()) return false;
01762 InlineBox *ibox = box->inlineBox();
01763 return ibox->isInlineFlowBox()
01764 && !static_cast<InlineFlowBox *>(ibox)->firstChild()
01765 && !isIndicatedInlineBox(ibox);
01766 }
01767
01768 EditableCharacterIterator &EditableCharacterIterator::operator ++()
01769 {
01770 _offset++;
01771
01772 CaretBox *box = *ebit;
01773 InlineBox *b = box->inlineBox();
01774 long maxofs = box->maxOffset();
01775 #if DEBUG_CARETMODE > 0
01776 kdDebug(6200) << "box->maxOffset() " << box->maxOffset() << " box->minOffset() " << box->minOffset() << endl;
01777 #endif
01778 if (_offset == maxofs) {
01779 #if DEBUG_CARETMODE > 2
01780 kdDebug(6200) << "_offset == maxofs: " << _offset << " == " << maxofs << endl;
01781 #endif
01782 peekNext();
01783 } else if (_offset > maxofs) {
01784 #if DEBUG_CARETMODE > 2
01785 kdDebug(6200) << "_offset > maxofs: " << _offset << " > " << maxofs << endl;
01786 #endif
01787 if (true) {
01788 ++ebit;
01789 if (ebit == (*_it)->end()) {
01790 ++_it;
01791 #if DEBUG_CARETMODE > 3
01792 kdDebug(6200) << "++_it" << endl;
01793 #endif
01794 if (_it != _it.lines->end()) {
01795 ebit = _it;
01796 box = *ebit;
01797 b = box->inlineBox();
01798 #if DEBUG_CARETMODE > 3
01799 kdDebug(6200) << "box " << box << " b " << b << " isText " << box->isInlineTextBox() << endl;
01800 #endif
01801
01802 #if DEBUG_CARETMODE > 3
01803 RenderObject *_r = box->object();
01804 kdDebug(6200) << "_r " << _r << ":" << _r->element()->nodeName().string() << endl;
01805 #endif
01806 _offset = box->minOffset();
01807 #if DEBUG_CARETMODE > 3
01808 kdDebug(6200) << "_offset " << _offset << endl;
01809 #endif
01810 } else {
01811 b = 0;
01812 _end = true;
01813 }
01814 goto readchar;
01815 }
01816 }
01817
01818 bool adjacent = ebit.isAdjacent();
01819 #if 0
01820
01821 if (adjacent && !(*ebit)->isInlineTextBox()) {
01822 EditableCaretBoxIterator copy = ebit;
01823 ++ebit;
01824 if (ebit != (*_it)->end() && (*ebit)->isInlineTextBox()
01825
01826 )
01827 adjacent = false;
01828 else ebit = copy;
01829 }
01830 #endif
01831
01832 if (adjacent && !(*ebit)->isInlineTextBox()) {
01833 bool noemptybox = true;
01834 while (isCaretBoxEmpty(*ebit)) {
01835 noemptybox = false;
01836 EditableCaretBoxIterator copy = ebit;
01837 ++ebit;
01838 if (ebit == (*_it)->end()) { ebit = copy; break; }
01839 }
01840 if (noemptybox) adjacent = false;
01841 }
01842
01843 _offset = (*ebit)->minOffset() + adjacent;
01844
01845 box = *ebit;
01846 b = box->inlineBox();
01847 goto readchar;
01848 } else {
01849 readchar:
01850
01851 if (b && !box->isOutside() && b->isInlineTextBox() && _offset < b->maxOffset())
01852 _char = static_cast<RenderText *>(b->object())->str->s[_offset].unicode();
01853 else
01854 _char = -1;
01855 }
01856 #if DEBUG_CARETMODE > 2
01857 kdDebug(6200) << "_offset: " << _offset << " char '" << (char)_char << "'" << endl;
01858 #endif
01859
01860 #if DEBUG_CARETMODE > 0
01861 if (!_end && ebit != (*_it)->end()) {
01862 CaretBox *box = *ebit;
01863 RenderObject *_r = box->object();
01864 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) << " _r " << (_r ? _r->element()->nodeName().string() : QString("<nil>")) << endl;
01865 }
01866 #endif
01867 return *this;
01868 }
01869
01870 EditableCharacterIterator &EditableCharacterIterator::operator --()
01871 {
01872 _offset--;
01873
01874
01875 CaretBox *box = *ebit;
01876 CaretBox *_peekPrev = 0;
01877 CaretBox *_peekNext = 0;
01878 InlineBox *b = box->inlineBox();
01879 long minofs = box->minOffset();
01880 #if DEBUG_CARETMODE > 0
01881 kdDebug(6200) << "box->maxOffset() " << box->maxOffset() << " box->minOffset() " << box->minOffset() << endl;
01882 #endif
01883 if (_offset == minofs) {
01884 #if DEBUG_CARETMODE > 2
01885 kdDebug(6200) << "_offset == minofs: " << _offset << " == " << minofs << endl;
01886 #endif
01887
01888
01889 if (b && !box->isOutside() && b->isInlineTextBox())
01890 _char = static_cast<RenderText *>(b->object())->text()[_offset].unicode();
01891 else
01892 _char = -1;
01893
01894
01895 bool do_prev = false;
01896 {
01897 EditableCaretBoxIterator copy;
01898 _peekPrev = 0;
01899 do {
01900 copy = ebit;
01901 --ebit;
01902 if (ebit == (*_it)->preBegin()) { ebit = copy; break; }
01903 } while (isCaretBoxEmpty(*ebit));
01904
01905 if (ebit.isAdjacent() && ebit != (*_it)->preBegin() && (*ebit)->isInlineTextBox()) {
01906 _peekPrev = *ebit;
01907 do_prev = true;
01908 } else
01909 ebit = copy;
01910 }
01911 if (do_prev) goto prev;
01912 } else if (_offset < minofs) {
01913 prev:
01914 #if DEBUG_CARETMODE > 2
01915 kdDebug(6200) << "_offset < minofs: " << _offset << " < " << minofs << endl;
01916 #endif
01917 if (!_peekPrev) {
01918 _peekNext = *ebit;
01919 --ebit;
01920 if (ebit == (*_it)->preBegin()) {
01921 --_it;
01922 #if DEBUG_CARETMODE > 3
01923 kdDebug(6200) << "--_it" << endl;
01924 #endif
01925 if (_it != _it.lines->preBegin()) {
01926
01927 ebit = EditableCaretBoxIterator(_it, true);
01928 box = *ebit;
01929
01930 #if DEBUG_CARETMODE > 3
01931 kdDebug(6200) << "box " << box << " b " << box->inlineBox() << " isText " << box->isInlineTextBox() << endl;
01932 #endif
01933 _offset = box->maxOffset();
01934
01935 _char = -1;
01936 #if DEBUG_CARETMODE > 0
01937 kdDebug(6200) << "echit--(2): box " << box << " b " << box->inlineBox() << (box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << endl;
01938 #endif
01939 } else
01940 _end = true;
01941 return *this;
01942 }
01943 }
01944
01945 #if DEBUG_CARETMODE > 0
01946 bool adjacent = ebit.isAdjacent();
01947 kdDebug(6200) << "adjacent " << adjacent << " _peekNext " << _peekNext << " _peekNext->isInlineTextBox: " << (_peekNext ? _peekNext->isInlineTextBox() : false) << " !((*ebit)->isInlineTextBox): " << (*ebit ? !(*ebit)->isInlineTextBox() : true) << endl;
01948 #endif
01949 #if 0
01950
01951 if (adjacent && _peekNext && _peekNext->isInlineTextBox()
01952 && !(*ebit)->isInlineTextBox()) {
01953 EditableCaretBoxIterator copy = ebit;
01954 --ebit;
01955 if (ebit == (*_it)->preBegin())
01956 ebit = copy;
01957 }
01958 #endif
01959 #if 0
01960
01961 if (adjacent
01962 && !(*ebit)->isInlineTextBox()) {
01963 bool noemptybox = true;
01964 while (isCaretBoxEmpty(*ebit)) {
01965 noemptybox = false;
01966 EditableCaretBoxIterator copy = ebit;
01967 --ebit;
01968 if (ebit == (*_it)->preBegin()) { ebit = copy; break; }
01969 else _peekNext = *copy;
01970 }
01971 if (noemptybox) adjacent = false;
01972 }
01973 #endif
01974 #if DEBUG_CARETMODE > 0
01975 kdDebug(6200) << "(*ebit)->obj " << (*ebit)->object()->renderName() << "[" << (*ebit)->object() << "]" << " minOffset: " << (*ebit)->minOffset() << " maxOffset: " << (*ebit)->maxOffset() << endl;
01976 #endif
01977 #if DEBUG_CARETMODE > 3
01978 RenderObject *_r = (*ebit)->object();
01979 kdDebug(6200) << "_r " << _r << ":" << _r->element()->nodeName().string() << endl;
01980 #endif
01981 _offset = (*ebit)->maxOffset();
01982
01983 #if DEBUG_CARETMODE > 3
01984 kdDebug(6200) << "_offset " << _offset << endl;
01985 #endif
01986 _peekPrev = 0;
01987 } else {
01988 #if DEBUG_CARETMODE > 0
01989 kdDebug(6200) << "_offset: " << _offset << " _peekNext: " << _peekNext << endl;
01990 #endif
01991
01992 if (_peekNext && _offset >= box->maxOffset() && _peekNext->isInlineTextBox())
01993 _char = static_cast<RenderText *>(_peekNext->object())->text()[_peekNext->minOffset()].unicode();
01994 else if (b && _offset < b->maxOffset() && b->isInlineTextBox())
01995 _char = static_cast<RenderText *>(b->object())->text()[_offset].unicode();
01996 else
01997 _char = -1;
01998 }
01999
02000 #if DEBUG_CARETMODE > 0
02001 if (!_end && ebit != (*_it)->preBegin()) {
02002 CaretBox *box = *ebit;
02003 kdDebug(6200) << "echit--(1): box " << box << " b " << box->inlineBox() << (box->isInlineTextBox() ? QString(" contains \"%1\"").arg(QConstString(static_cast<RenderText *>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : QString::null) << endl;
02004 }
02005 #endif
02006 return *this;
02007 }
02008
02009
02010
02011 TableRowIterator::TableRowIterator(RenderTable *table, bool fromEnd,
02012 RenderTableSection::RowStruct *row)
02013 : sec(table, fromEnd)
02014 {
02015
02016 if (*sec) {
02017 if (fromEnd) index = (*sec)->grid.size() - 1;
02018 else index = 0;
02019 }
02020
02021
02022 if (row && *sec) {
02023 while (operator *() != row)
02024 if (fromEnd) operator --(); else operator ++();
02025 }
02026 }
02027
02028 TableRowIterator &TableRowIterator::operator ++()
02029 {
02030 index++;
02031
02032 if (index >= (int)(*sec)->grid.size()) {
02033 ++sec;
02034
02035 if (*sec) index = 0;
02036 }
02037 return *this;
02038 }
02039
02040 TableRowIterator &TableRowIterator::operator --()
02041 {
02042 index--;
02043
02044 if (index < 0) {
02045 --sec;
02046
02047 if (*sec) index = (*sec)->grid.size() - 1;
02048 }
02049 return *this;
02050 }
02051
02052
02053
02054
02055 static RenderTableCell *findNearestTableCellInRow(KHTMLPart *part, int x,
02056 RenderTableSection::RowStruct *row, bool fromEnd);
02057
02071 static inline RenderTableCell *findNearestTableCell(KHTMLPart *part, int x,
02072 TableRowIterator &it, bool fromEnd)
02073 {
02074 RenderTableCell *result = 0;
02075
02076 while (*it) {
02077 result = findNearestTableCellInRow(part, x, *it, fromEnd);
02078 if (result) break;
02079
02080 if (fromEnd) --it; else ++it;
02081 }
02082
02083 return result;
02084 }
02085
02099 static RenderTableCell *findNearestTableCellInRow(KHTMLPart *part, int x,
02100 RenderTableSection::RowStruct *row, bool fromEnd)
02101 {
02102
02103 int n = (int)row->row->size();
02104 int i;
02105 for (i = 0; i < n; i++) {
02106 RenderTableCell *cell = row->row->at(i);
02107 if (!cell || (long)cell == -1) continue;
02108
02109 int absx, absy;
02110 cell->absolutePosition(absx, absy, false);
02111 #if DEBUG_CARETMODE > 1
02112 kdDebug(6201) << "i/n " << i << "/" << n << " absx " << absx << " absy " << absy << endl;
02113 #endif
02114
02115
02116
02117 #if DEBUG_CARETMODE > 1
02118 kdDebug(6201) << "x " << x << " < " << (absx + cell->width()) << "?" << endl;
02119 #endif
02120 if (x < absx + cell->width()) break;
02121 }
02122 if (i >= n) i = n - 1;
02123
02124
02125
02126 for (int cnt = 0; cnt < 2*n; cnt++) {
02127 int index = i - ((cnt >> 1) + 1)*(cnt & 1) + (cnt >> 1)*!(cnt & 1);
02128 if (index < 0 || index >= n) continue;
02129
02130 RenderTableCell *cell = row->row->at(index);
02131 if (!cell || (long)cell == -1) continue;
02132
02133 #if DEBUG_CARETMODE > 1
02134 kdDebug(6201) << "index " << index << " cell " << cell << endl;
02135 #endif
02136 RenderTable *nestedTable;
02137 if (containsEditableElement(part, cell, nestedTable, fromEnd)) {
02138
02139 if (nestedTable) {
02140 TableRowIterator it(nestedTable, fromEnd);
02141 while (*it) {
02142
02143 cell = findNearestTableCell(part, x, it, fromEnd);
02144 if (cell) break;
02145 if (fromEnd) --it; else ++it;
02146 }
02147 }
02148
02149 return cell;
02150 }
02151 }
02152 return 0;
02153 }
02154
02161 static RenderObject *commonAncestorTableSectionOrCell(RenderObject *r1,
02162 RenderObject *r2)
02163 {
02164 if (!r1 || !r2) return 0;
02165 RenderTableSection *sec = 0;
02166 int start_depth=0, end_depth=0;
02167
02168 RenderObject *n = r1;
02169 while (n->parent()) {
02170 n = n->parent();
02171 start_depth++;
02172 }
02173 n = r2;
02174 while( n->parent()) {
02175 n = n->parent();
02176 end_depth++;
02177 }
02178
02179 while (end_depth > start_depth) {
02180 r2 = r2->parent();
02181 end_depth--;
02182 }
02183 while (start_depth > end_depth) {
02184 r1 = r1->parent();
02185
02186 start_depth--;
02187 }
02188
02189 while (r1 != r2){
02190 r1 = r1->parent();
02191 if (r1->isTableSection()) sec = static_cast<RenderTableSection *>(r1);
02192 r2 = r2->parent();
02193 }
02194
02195
02196
02197 while (r1 && !r1->isTableCell() && !r1->isTableSection() && !r1->isTable())
02198 r1 = r1->parent();
02199
02200 return r1 && r1->isTable() ? sec : r1;
02201 }
02202
02210 static int findRowInSection(RenderTableSection *section, RenderTableCell *cell,
02211 RenderTableSection::RowStruct *&row, RenderTableCell *&directCell)
02212 {
02213
02214 RenderObject *r = cell;
02215 while (r != section) {
02216 if (r->isTableCell()) directCell = static_cast<RenderTableCell *>(r);
02217 r = r->parent();
02218 }
02219
02220
02221
02222
02223 int n = section->numRows();
02224 for (int i = 0; i < n; i++) {
02225 row = §ion->grid[i];
02226
02227
02228 int m = row->row->size();
02229 for (int j = 0; j < m; j++) {
02230 RenderTableCell *c = row->row->at(j);
02231 if (c == directCell) return i;
02232 }
02233
02234 }
02235 Q_ASSERT(false);
02236 return -1;
02237 }
02238
02244 static inline RenderTable *findFirstDescendantTable(RenderObject *leaf, RenderBlock *block)
02245 {
02246 RenderTable *result = 0;
02247 while (leaf && leaf != block) {
02248 if (leaf->isTable()) result = static_cast<RenderTable *>(leaf);
02249 leaf = leaf->parent();
02250 }
02251 return result;
02252 }
02253
02257 static inline RenderTableCell *containingTableCell(RenderObject *r)
02258 {
02259 while (r && !r->isTableCell()) r = r->parent();
02260 return static_cast<RenderTableCell *>(r);
02261 }
02262
02263 inline void ErgonomicEditableLineIterator::calcAndStoreNewLine(
02264 RenderBlock *newBlock, bool toBegin)
02265 {
02266
02267
02268 CaretBoxIterator it;
02269 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
02270 newBlock, true, toBegin, it);
02271 #if DEBUG_CARETMODE > 3
02272 kdDebug(6201) << cbl->information() << endl;
02273 #endif
02274
02275
02276 if (!cbl) {
02277 return;
02278 }
02279
02280 EditableLineIterator::advance(toBegin);
02281 }
02282
02283 void ErgonomicEditableLineIterator::determineTopologicalElement(
02284 RenderTableCell *oldCell, RenderObject *newObject, bool toBegin)
02285 {
02286
02287
02288
02289
02290
02291 TableRowIterator it;
02292
02293 RenderObject *commonAncestor = commonAncestorTableSectionOrCell(oldCell, newObject);
02294 #if DEBUG_CARETMODE > 1
02295 kdDebug(6201) << " ancestor " << commonAncestor << endl;
02296 #endif
02297
02298
02299 if (!commonAncestor || commonAncestor->isTableCell()) {
02300
02301 RenderTableCell *cell = static_cast<RenderTableCell *>(commonAncestor);
02302 RenderTable *table = findFirstDescendantTable(newObject, cell);
02303
02304 #if DEBUG_CARETMODE > 0
02305 kdDebug(6201) << "table cell: " << cell << endl;
02306 #endif
02307
02308
02309
02310 if (!table) return;
02311
02312 it = TableRowIterator(table, toBegin);
02313
02314 } else if (commonAncestor->isTableSection()) {
02315
02316 RenderTableSection *section = static_cast<RenderTableSection *>(commonAncestor);
02317 RenderTableSection::RowStruct *row;
02318 int idx = findRowInSection(section, oldCell, row, oldCell);
02319 #if DEBUG_CARETMODE > 1
02320 kdDebug(6201) << "table section: row idx " << idx << endl;
02321 #endif
02322
02323 it = TableRowIterator(section, idx);
02324
02325
02326 int rowspan = oldCell->rowSpan();
02327 while (*it && rowspan--) {
02328 if (toBegin) --it; else ++it;
02329 }
02330
02331 } else {
02332 kdError(6201) << "Neither common cell nor section! " << commonAncestor->renderName() << endl;
02333
02334 }
02335
02336 RenderTableCell *cell = findNearestTableCell(lines->m_part, xCoor, it, toBegin);
02337 #if DEBUG_CARETMODE > 1
02338 kdDebug(6201) << "findNearestTableCell result: " << cell << endl;
02339 #endif
02340
02341 RenderBlock *newBlock = cell;
02342 if (!cell) {
02343 Q_ASSERT(commonAncestor->isTableSection());
02344 RenderTableSection *section = static_cast<RenderTableSection *>(commonAncestor);
02345 cell = containingTableCell(section);
02346 #if DEBUG_CARETMODE > 1
02347 kdDebug(6201) << "containing cell: " << cell << endl;
02348 #endif
02349
02350 RenderTable *nestedTable;
02351 bool editableChild = cell && containsEditableChildElement(lines->m_part,
02352 cell, nestedTable, toBegin, section->table());
02353
02354 if (cell && !editableChild) {
02355 #if DEBUG_CARETMODE > 1
02356 kdDebug(6201) << "========= recursive invocation outer =========" << endl;
02357 #endif
02358 determineTopologicalElement(cell, cell->section(), toBegin);
02359 #if DEBUG_CARETMODE > 1
02360 kdDebug(6201) << "========= end recursive invocation outer =========" << endl;
02361 #endif
02362 return;
02363
02364 } else if (cell && nestedTable) {
02365 #if DEBUG_CARETMODE > 1
02366 kdDebug(6201) << "========= recursive invocation inner =========" << endl;
02367 #endif
02368 determineTopologicalElement(cell, nestedTable, toBegin);
02369 #if DEBUG_CARETMODE > 1
02370 kdDebug(6201) << "========= end recursive invocation inner =========" << endl;
02371 #endif
02372 return;
02373
02374 } else {
02375 #if DEBUG_CARETMODE > 1
02376 kdDebug(6201) << "newBlock is table: " << section->table() << endl;
02377 #endif
02378 RenderObject *r = section->table();
02379 int state;
02380 ObjectTraversalState trav = OutsideAscending;
02381 r = advanceSuitableObject(r, trav, toBegin, lines->baseObject(), state);
02382 if (!r) { cbl = 0; return; }
02383
02384 newBlock = static_cast<RenderBlock *>(!r || r->isRenderBlock() ? r : r->containingBlock());
02385 }
02386 #if 0
02387 } else {
02388
02389 newBlock = cell;
02390
02391
02392 if (!toBegin) {
02393 RenderObject *r = newBlock;
02394 int state;
02395 ObjectTraversalState trav = OutsideAscending;
02396 r = advanceSuitableObject(r, trav, true, lines->advancePolicy(), lines->baseObject(), state);
02397 newBlock = static_cast<RenderBlock *>(!r || r->isRenderBlock() ? r : r->containingBlock());
02398 }
02399 #endif
02400 }
02401
02402 calcAndStoreNewLine(newBlock, toBegin);
02403 }
02404
02405 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator ++()
02406 {
02407 RenderTableCell *oldCell = containingTableCell(cbl->enclosingObject());
02408
02409 EditableLineIterator::operator ++();
02410 if (*this == lines->end() || *this == lines->preBegin()) return *this;
02411
02412 RenderTableCell *newCell = containingTableCell(cbl->enclosingObject());
02413
02414 if (!newCell || newCell == oldCell) return *this;
02415
02416 determineTopologicalElement(oldCell, newCell, false);
02417
02418 return *this;
02419 }
02420
02421 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator --()
02422 {
02423 RenderTableCell *oldCell = containingTableCell(cbl->enclosingObject());
02424
02425 EditableLineIterator::operator --();
02426 if (*this == lines->end() || *this == lines->preBegin()) return *this;
02427
02428 RenderTableCell *newCell = containingTableCell(cbl->enclosingObject());
02429
02430 if (!newCell || newCell == oldCell) return *this;
02431
02432 determineTopologicalElement(oldCell, newCell, true);
02433
02434 return *this;
02435 }
02436
02437
02438
02448 static CaretBox *nearestCaretBox(LineIterator &it, CaretViewContext *cv,
02449 int &x, int &absx, int &absy)
02450 {
02451
02452 RenderObject *cb = (*it)->containingBlock();
02453 #if DEBUG_CARETMODE > 4
02454 kdDebug(6200) << "nearestCB: cb " << cb << "@" << (cb ? cb->renderName() : "") << endl;
02455 #endif
02456
02457 if (cb) cb->absolutePosition(absx, absy);
02458 else absx = absy = 0;
02459
02460
02461
02462
02463 x = cv->origX - absx;
02464 CaretBox *caretBox = 0;
02465
02466 int xPos;
02467 int oldXPos = -1;
02468 EditableCaretBoxIterator fbit = it;
02469 #if DEBUG_CARETMODE > 0
02470
02471
02472
02473 #endif
02474
02475 for (CaretBox *b; fbit != (*it)->end(); ++fbit) {
02476 b = *fbit;
02477
02478 #if DEBUG_CARETMODE > 0
02479
02480
02481
02482 #endif
02483 xPos = b->xPos();
02484
02485
02486 if (x < xPos) {
02487
02488 if (oldXPos < 0 || x - (oldXPos + caretBox->width()) > xPos - x) {
02489 caretBox = b;
02490 }
02491 break;
02492 }
02493
02494 caretBox = b;
02495
02496
02497 if (x >= xPos && x < xPos + caretBox->width())
02498 break;
02499 oldXPos = xPos;
02500
02501
02502
02503 }
02504
02505 return caretBox;
02506 }
02507
02513 static void moveItToNextWord(EditableCharacterIterator &it)
02514 {
02515 #if DEBUG_CARETMODE > 0
02516 kdDebug(6200) << "%%%%%%%%%%%%%%%%%%%%% moveItToNextWord" << endl;
02517 #endif
02518 EditableCharacterIterator copy;
02519 while (!it.isEnd() && !(*it).isSpace() && !(*it).isPunct()) {
02520 #if DEBUG_CARETMODE > 2
02521 kdDebug(6200) << "reading1 '" << (*it).latin1() << "'" << endl;
02522 #endif
02523 copy = it;
02524 ++it;
02525 }
02526
02527 if (it.isEnd()) {
02528 it = copy;
02529 return;
02530 }
02531
02532 while (!it.isEnd() && ((*it).isSpace() || (*it).isPunct())) {
02533 #if DEBUG_CARETMODE > 2
02534 kdDebug(6200) << "reading2 '" << (*it).latin1() << "'" << endl;
02535 #endif
02536 copy = it;
02537 ++it;
02538 }
02539
02540 if (it.isEnd()) it = copy;
02541 }
02542
02548 static void moveItToPrevWord(EditableCharacterIterator &it)
02549 {
02550 if (it.isEnd()) return;
02551
02552 #if DEBUG_CARETMODE > 0
02553 kdDebug(6200) << "%%%%%%%%%%%%%%%%%%%%% moveItToPrevWord" << endl;
02554 #endif
02555 EditableCharacterIterator copy;
02556
02557
02558 do {
02559 copy = it;
02560 --it;
02561 #if DEBUG_CARETMODE > 2
02562 if (!it.isEnd()) kdDebug(6200) << "reading1 '" << (*it).latin1() << "'" << endl;
02563 #endif
02564 } while (!it.isEnd() && ((*it).isSpace() || (*it).isPunct()));
02565
02566 if (it.isEnd()) {
02567 it = copy;
02568 return;
02569 }
02570
02571 do {
02572 copy = it;
02573 --it;
02574 #if DEBUG_CARETMODE > 0
02575 if (!it.isEnd()) kdDebug(6200) << "reading2 '" << (*it).latin1() << "' (" << (int)(*it).latin1() << ") box " << it.caretBox() << endl;
02576 #endif
02577 } while (!it.isEnd() && !(*it).isSpace() && !(*it).isPunct());
02578
02579 it = copy;
02580 #if DEBUG_CARETMODE > 1
02581 if (!it.isEnd()) kdDebug(6200) << "effective '" << (*it).latin1() << "' (" << (int)(*it).latin1() << ") box " << it.caretBox() << endl;
02582 #endif
02583 }
02584
02592 static void moveIteratorByPage(LinearDocument &ld,
02593 ErgonomicEditableLineIterator &it, int mindist, bool next)
02594 {
02595
02596
02597 if (it == ld.end() || it == ld.preBegin()) return;
02598
02599 ErgonomicEditableLineIterator copy = it;
02600 #if DEBUG_CARETMODE > 0
02601 kdDebug(6200) << " mindist: " << mindist << endl;
02602 #endif
02603
02604 CaretBoxLine *cbl = *copy;
02605 int absx = 0, absy = 0;
02606
02607 RenderBlock *lastcb = cbl->containingBlock();
02608 Q_ASSERT(lastcb->isRenderBlock());
02609 lastcb->absolutePosition(absx, absy, false);
02610
02611 int lastfby = cbl->begin().data()->yPos();
02612 int lastheight = 0;
02613 int rescue = 1000;
02614 do {
02615 if (next) ++copy; else --copy;
02616 if (copy == ld.end() || copy == ld.preBegin()) break;
02617
02618 cbl = *copy;
02619 RenderBlock *cb = cbl->containingBlock();
02620
02621 int diff = 0;
02622
02623
02624 int fby = cbl->begin().data()->yPos();
02625 if (cb != lastcb) {
02626 if (next) {
02627 diff = absy + lastfby + lastheight;
02628 cb->absolutePosition(absx, absy, false);
02629 diff = absy - diff + fby;
02630 lastfby = 0;
02631 } else {
02632 diff = absy;
02633 cb->absolutePosition(absx, absy, false);
02634 diff -= absy + fby + lastheight;
02635 lastfby = fby - lastheight;
02636 }
02637 #if DEBUG_CARETMODE > 2
02638 kdDebug(6200) << "absdiff " << diff << endl;
02639 #endif
02640 } else {
02641 diff = kAbs(fby - lastfby);
02642 }
02643 #if DEBUG_CARETMODE > 2
02644 kdDebug(6200) << "cbl->begin().data()->yPos(): " << fby << " diff " << diff << endl;
02645 #endif
02646
02647 mindist -= diff;
02648
02649 lastheight = kAbs(fby - lastfby);
02650 lastfby = fby;
02651 lastcb = cb;
02652 it = copy;
02653 #if DEBUG_CARETMODE > 0
02654 kdDebug(6200) << " mindist: " << mindist << endl;
02655 #endif
02656
02657
02658
02659
02660 } while (mindist - lastheight > 0 && --rescue);
02661 }
02662
02663
02664 }