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