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