22 #include "tdehtml_caret_p.h"
24 #include "html/html_documentimpl.h"
35 enum ObjectAdvanceState {
36 LeftObject = 0x01, AdvancedToSibling = 0x02, EnteredObject = 0x04
47 enum ObjectTraversalState {
48 OutsideDescending, InsideDescending, InsideAscending, OutsideAscending
60 static RenderObject* traverseRenderObjects(RenderObject *obj,
61 ObjectTraversalState &trav,
bool toBegin, RenderObject *base,
66 case OutsideDescending:
67 trav = InsideDescending;
69 case InsideDescending:
70 r = toBegin ? obj->lastChild() : obj->firstChild();
72 trav = OutsideDescending;
74 state |= EnteredObject;
76 trav = InsideAscending;
80 trav = OutsideAscending;
82 case OutsideAscending:
83 r = toBegin ? obj->previousSibling() : obj->nextSibling();
85 trav = OutsideDescending;
86 state |= AdvancedToSibling;
90 trav = InsideAscending;
105 static inline RenderObject *renderObjectBelow(RenderObject *obj, ObjectTraversalState &trav, RenderObject *base)
107 trav = InsideDescending;
109 RenderObject *r = obj;
110 while (r && trav != OutsideDescending) {
111 r = traverseRenderObjects(r, trav,
false, base, state);
112 #if DEBUG_CARETMODE > 3
113 kdDebug(6200) <<
"renderObjectBelow: r " << r <<
" trav " << trav <<
endl;
116 trav = InsideDescending;
125 static inline RenderObject *renderObjectAbove(RenderObject *obj, ObjectTraversalState &trav, RenderObject *base)
127 trav = OutsideAscending;
129 RenderObject *r = obj;
130 while (r && trav != InsideAscending) {
131 r = traverseRenderObjects(r, trav,
true, base, state);
132 #if DEBUG_CARETMODE > 3
133 kdDebug(6200) <<
"renderObjectAbove: r " << r <<
" trav " << trav <<
endl;
136 trav = InsideAscending;
144 static inline bool isIndicatedInlineBox(InlineBox *box)
147 if (box->isInlineTextBox())
return false;
148 RenderStyle *s = box->object()->style();
149 return s->borderLeftWidth() || s->borderRightWidth()
150 || s->borderTopWidth() || s->borderBottomWidth()
151 || s->paddingLeft().value() || s->paddingRight().value()
152 || s->paddingTop().value() || s->paddingBottom().value()
155 || s->marginLeft().value() || s->marginRight().value();
162 static inline bool isIndicatedFlow(RenderObject *r)
164 RenderStyle *s = r->style();
165 return s->borderLeftStyle() != BNONE || s->borderRightStyle() != BNONE
166 || s->borderTopStyle() != BNONE || s->borderBottomStyle() != BNONE
170 || s->hasClip() || s->hidesOverflow()
171 || s->backgroundColor().isValid() || s->backgroundImage();
187 static RenderObject *advanceObject(RenderObject *r,
188 ObjectTraversalState &trav,
bool toBegin,
189 RenderObject *base,
int &state)
192 ObjectTraversalState origtrav = trav;
193 RenderObject *a = traverseRenderObjects(r, trav, toBegin, base, state);
195 bool ignoreOutsideDesc = toBegin && origtrav == OutsideAscending;
198 RenderObject *la = 0;
199 ObjectTraversalState latrav = trav;
200 ObjectTraversalState lasttrav = origtrav;
203 #if DEBUG_CARETMODE > 5
204 kdDebug(6200) <<
"a " << a <<
" trav " << trav <<
endl;
207 #if DEBUG_CARETMODE > 4
208 kdDebug(6200) <<
"a " << a <<
" trav " << trav <<
" origtrav " << origtrav <<
" ignoreOD " << ignoreOutsideDesc <<
endl;
213 case OutsideDescending:
214 if (trav == InsideAscending)
return a;
215 if (trav == OutsideDescending)
return a;
217 case InsideDescending:
218 if (trav == OutsideDescending)
return a;
220 case InsideAscending:
221 if (trav == OutsideAscending)
return a;
223 case OutsideAscending:
224 if (trav == OutsideAscending)
return a;
225 if (trav == InsideAscending && lasttrav == InsideDescending)
return a;
226 if (trav == OutsideDescending && !ignoreOutsideDesc)
return a;
230 la = a; latrav = trav;
231 ignoreOutsideDesc =
false;
238 case OutsideDescending:
239 if (trav == InsideAscending)
return a;
240 if (trav == OutsideDescending)
return a;
242 case InsideDescending:
245 case InsideAscending:
248 case OutsideAscending:
253 if (trav == OutsideDescending)
return a;
254 if (trav == OutsideAscending) {
258 la = a; latrav = trav;
267 a = traverseRenderObjects(a, trav, toBegin, base, state);
270 if (la) trav = latrav, a = la;
283 static inline bool isUnsuitable(RenderObject *r, ObjectTraversalState trav)
285 if (!r)
return false;
286 return r->isTableCol() || r->isTableSection() || r->isTableRow()
287 || (r->isText() &&
static_cast<RenderText *
>(r)->inlineTextBoxCount() == 0);
305 static inline RenderObject *advanceSuitableObject(RenderObject *r,
306 ObjectTraversalState &trav,
bool toBegin,
307 RenderObject *base,
int &state)
310 r = advanceObject(r, trav, toBegin, base, state);
311 #if DEBUG_CARETMODE > 2
312 kdDebug(6200) <<
"after advanceSWP: r " << r <<
" trav " << trav <<
" toBegin " << toBegin <<
endl;
314 }
while (isUnsuitable(r, trav));
327 static NodeImpl *nextLeafNode(NodeImpl *r, NodeImpl *baseElem)
329 NodeImpl *n = r->firstChild();
331 while (n) { r = n; n = n->firstChild(); }
332 return const_cast<NodeImpl *
>(r);
334 n = r->nextSibling();
337 while (n) { r = n; n = n->firstChild(); }
338 return const_cast<NodeImpl *
>(r);
342 if (n == baseElem) n = 0;
345 n = r->nextSibling();
349 while (n) { r = n; n = n->firstChild(); }
350 return const_cast<NodeImpl *
>(r);
353 if (n == baseElem) n = 0;
368 static NodeImpl *prevLeafNode(NodeImpl *r, NodeImpl *baseElem)
370 NodeImpl *n = r->firstChild();
372 while (n) { r = n; n = n->firstChild(); }
373 return const_cast<NodeImpl *
>(r);
375 n = r->previousSibling();
378 while (n) { r = n; n = n->firstChild(); }
379 return const_cast<NodeImpl *
>(r);
383 if (n == baseElem) n = 0;
386 n = r->previousSibling();
390 while (n) { r = n; n = n->lastChild(); }
391 return const_cast<NodeImpl *
>(r);
394 if (n == baseElem) n = 0;
411 void mapDOMPosToRenderPos(NodeImpl *node,
long offset,
412 RenderObject *&r,
long &r_ofs,
bool &outside,
bool &outsideEnd)
414 if (node->nodeType() == Node::TEXT_NODE) {
417 r = node->renderer();
419 }
else if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE) {
423 if (node->firstChild()) {
425 NodeImpl *child = offset <= 0 ? node->firstChild()
427 : node->childNode((
unsigned long)offset);
430 #if DEBUG_CARETMODE > 5
431 kdDebug(6200) <<
"mapDTR: child " << child <<
"@" << (child ? child->nodeName().string() : TQString::null) <<
" atEnd " << atEnd <<
endl;
433 if (atEnd) child = node->lastChild();
435 r = child->renderer();
441 if (r && child->nodeType() == Node::TEXT_NODE) {
443 RenderObject *o = node->renderer();
444 while (o->continuation() && o->continuation() != r)
445 o = o->continuation();
446 if (!r || o->continuation() != r) {
447 r = child->renderer();
453 if (r && r->isBR()) {
454 r = r->objectAbove();
462 r = node->renderer();
468 kdWarning() << k_funcinfo <<
"Mapping from nodes of type " << node->nodeType()
469 <<
" not supported!" <<
endl;
483 void mapRenderPosToDOMPos(RenderObject *r,
long r_ofs,
484 bool outside,
bool outsideEnd, NodeImpl *&node,
long &offset)
488 #if DEBUG_CARETMODE > 5
489 kdDebug(6200) <<
"mapRTD: r " << r <<
"@" << (r ? r->renderName() : TQString::null) << (r && r->element() ? TQString(
".node ") + TQString::number((
unsigned)r->element(),16) +
"@" + r->element()->nodeName().string() : TQString::null) <<
" outside " << outside <<
" outsideEnd " << outsideEnd <<
endl;
491 if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::TEXT_NODE) {
494 NodeImpl *parent = node->parent();
498 if (r != node->renderer()) {
499 RenderObject *o = node->renderer();
500 while (o->continuation() && o->continuation() != r)
501 o = o->continuation();
502 if (o->continuation() == r) {
506 node = r->firstChild() ? r->firstChild()->element() : node;
510 if (!parent)
goto inside;
512 offset = (long)node->nodeIndex() + outsideEnd;
514 #if DEBUG_CARETMODE > 5
515 kdDebug(6200) << node <<
"@" << (node ? node->nodeName().string() : TQString::null) <<
" offset " << offset <<
endl;
524 kdWarning() << k_funcinfo <<
"Mapping to nodes of type " << node->nodeType()
525 <<
" not supported!" <<
endl;
530 static inline void ensureLeafNode(NodeImpl *&node, NodeImpl *base)
532 if (node && node->hasChildNodes()) node = nextLeafNode(node, base);
541 static inline void mapRenderPosToTraversalState(
bool outside,
bool atEnd,
542 bool toBegin, ObjectTraversalState &trav)
544 if (!outside) atEnd = !toBegin;
545 if (!atEnd ^ toBegin)
546 trav = outside ? OutsideDescending : InsideDescending;
548 trav = outside ? OutsideAscending : InsideAscending;
557 static inline void mapTraversalStateToRenderPos(ObjectTraversalState trav,
558 bool toBegin,
bool &outside,
bool &atEnd)
562 case OutsideDescending: outside =
true;
563 case InsideDescending: atEnd = toBegin;
break;
564 case OutsideAscending: outside =
true;
565 case InsideAscending: atEnd = !toBegin;
break;
584 static RenderObject* findRenderer(NodeImpl *&node,
long offset,
585 RenderObject *base,
long &r_ofs,
586 bool &outside,
bool &outsideEnd)
590 mapDOMPosToRenderPos(node, offset, r, r_ofs, outside, outsideEnd);
591 #if DEBUG_CARETMODE > 2
592 kdDebug(6200) <<
"findRenderer: node " << node <<
" " << (node ? node->nodeName().string() : TQString::null) <<
" offset " << offset <<
" r " << r <<
"[" << (r ? r->renderName() : TQString::null) <<
"] r_ofs " << r_ofs <<
" outside " << outside <<
" outsideEnd " << outsideEnd <<
endl;
595 NodeImpl *baseElem = base ? base->element() : 0;
597 node = nextLeafNode(node, baseElem);
599 r = node->renderer();
600 if (r) r_ofs = offset;
602 #if DEBUG_CARETMODE > 3
605 ObjectTraversalState trav;
607 mapRenderPosToTraversalState(outside, outsideEnd,
false, trav);
608 if (r && isUnsuitable(r, trav)) {
609 r = advanceSuitableObject(r, trav,
false, base, state);
610 mapTraversalStateToRenderPos(trav,
false, outside, outsideEnd);
611 if (r) r_ofs = r->minOffset();
613 #if DEBUG_CARETMODE > 3
622 static ElementImpl *determineBaseElement(NodeImpl *caretNode)
627 DocumentImpl *doc = caretNode->getDocument();
630 if (doc->isHTMLDocument())
631 return static_cast<HTMLDocumentImpl *
>(doc)->body();
638 #if DEBUG_CARETMODE > 0
639 void CaretBox::dump(TQTextStream &ts,
const TQString &ind)
const
641 ts << ind <<
"b@" << _box;
644 ts <<
"<" << _box->object() <<
":" << _box->object()->renderName() <<
">";
647 ts <<
" " << _x <<
"+" << _y <<
"+" << _w <<
"*" << _h;
650 if (cb) ts <<
":" << cb->renderName();
652 ts <<
" " << (_outside ? (outside_end ?
"oe" :
"o-") :
"i-");
659 #if DEBUG_CARETMODE > 0
660 # define DEBUG_ACIB 1
662 # define DEBUG_ACIB DEBUG_CARETMODE
664 void CaretBoxLine::addConvertedInlineBox(InlineBox *box, SeekBoxParams &sbp)
668 bool coalesceOutsideBoxes =
false;
669 CaretBoxIterator lastCoalescedBox;
670 for (; box; box = box->nextOnLine()) {
673 kdDebug(6200) <<
"box->object " << box->object() <<
endl;
674 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;
677 if (!box->object())
continue;
679 RenderStyle *s = box->object()->style(box->m_firstLine);
681 RenderStyle *ps = box->parent() && box->parent()->object()
682 ? box->parent()->object()->style(box->parent()->m_firstLine)
685 if (box->isInlineFlowBox()) {
687 kdDebug(6200) <<
"isinlineflowbox " << box <<
endl;
689 InlineFlowBox *flowBox =
static_cast<InlineFlowBox *
>(box);
690 bool rtl = ps->direction() == RTL;
691 const TQFontMetrics &pfm = ps->fontMetrics();
693 if (flowBox->includeLeftEdge()) {
697 if (coalesceOutsideBoxes) {
698 if (sbp.equalsBox(flowBox,
true,
false)) {
699 sbp.it = lastCoalescedBox;
700 Q_ASSERT(!sbp.found);
704 addCreatedFlowBoxEdge(flowBox, pfm,
true, rtl);
709 if (flowBox->firstChild()) {
711 kdDebug(6200) <<
"this " <<
this <<
" flowBox " << flowBox <<
" firstChild " << flowBox->firstChild() <<
endl;
712 kdDebug(6200) <<
"== recursive invocation" <<
endl;
714 addConvertedInlineBox(flowBox->firstChild(), sbp);
716 kdDebug(6200) <<
"== recursive invocation end" <<
endl;
720 addCreatedFlowBoxInside(flowBox, s->fontMetrics());
724 if (flowBox->includeRightEdge()) {
725 addCreatedFlowBoxEdge(flowBox, pfm,
false, rtl);
726 lastCoalescedBox = preEnd();
727 sbp.check(lastCoalescedBox);
728 coalesceOutsideBoxes =
true;
731 }
else if (box->isInlineTextBox()) {
733 kdDebug(6200) <<
"isinlinetextbox " << box << (box->object() ? TQString(
" contains \"%1\"").arg(TQConstString(
static_cast<RenderText *
>(box->object())->str->s+box->minOffset(), kMin(box->maxOffset() - box->minOffset(), 15L)).string()) : TQString::null) <<
endl;
735 caret_boxes.append(
new CaretBox(box,
false,
false));
738 coalesceOutsideBoxes =
false;
742 kdDebug(6200) <<
"some replaced or what " << box <<
endl;
745 bool rtl = ps->direction() == RTL;
746 const TQFontMetrics &pfm = ps->fontMetrics();
748 if (coalesceOutsideBoxes) {
749 if (sbp.equalsBox(box,
true,
false)) {
750 sbp.it = lastCoalescedBox;
751 Q_ASSERT(!sbp.found);
755 addCreatedInlineBoxEdge(box, pfm,
true, rtl);
759 caret_boxes.append(
new CaretBox(box,
false,
false));
762 addCreatedInlineBoxEdge(box, pfm,
false, rtl);
763 lastCoalescedBox = preEnd();
764 sbp.check(lastCoalescedBox);
765 coalesceOutsideBoxes =
true;
771 void CaretBoxLine::addCreatedFlowBoxInside(InlineFlowBox *flowBox,
const TQFontMetrics &fm)
774 CaretBox *caretBox =
new CaretBox(flowBox,
false,
false);
775 caret_boxes.append(caretBox);
781 caretBox->_y += flowBox->baseline() - fm.ascent();
782 caretBox->_h = fm.height();
785 void CaretBoxLine::addCreatedFlowBoxEdge(InlineFlowBox *flowBox,
const TQFontMetrics &fm,
bool left,
bool rtl)
787 CaretBox *caretBox =
new CaretBox(flowBox,
true, !left);
788 caret_boxes.append(caretBox);
790 if (left ^ rtl) caretBox->_x -= flowBox->paddingLeft() + flowBox->borderLeft() + 1;
791 else caretBox->_x += caretBox->_w + flowBox->paddingRight() + flowBox->borderRight();
793 caretBox->_y += flowBox->baseline() - fm.ascent();
794 caretBox->_h = fm.height();
798 void CaretBoxLine::addCreatedInlineBoxEdge(InlineBox *box,
const TQFontMetrics &fm,
bool left,
bool rtl)
800 CaretBox *caretBox =
new CaretBox(box,
true, !left);
801 caret_boxes.append(caretBox);
803 if (left ^ rtl) caretBox->_x--;
804 else caretBox->_x += caretBox->_w;
806 caretBox->_y += box->baseline() - fm.ascent();
807 caretBox->_h = fm.height();
811 CaretBoxLine *CaretBoxLine::constructCaretBoxLine(CaretBoxLineDeleter *deleter,
812 InlineFlowBox *basicFlowBox, InlineBox *seekBox,
bool seekOutside,
813 bool seekOutsideEnd, CaretBoxIterator &iter, RenderObject *seekObject)
826 CaretBoxLine *result =
new CaretBoxLine(basicFlowBox);
827 deleter->append(result);
829 SeekBoxParams sbp(seekBox, seekOutside, seekOutsideEnd, seekObject, iter);
832 result->addConvertedInlineBox(basicFlowBox, sbp);
834 if (!sbp.found) sbp.it = result->end();
839 CaretBoxLine *CaretBoxLine::constructCaretBoxLine(CaretBoxLineDeleter *deleter,
840 RenderBox *cb,
bool outside,
bool outsideEnd, CaretBoxIterator &iter)
849 RenderStyle *s = cb->element() && cb->element()->parent()
850 && cb->element()->parent()->renderer()
851 ? cb->element()->parent()->renderer()->style()
853 bool rtl = s->direction() == RTL;
855 const TQFontMetrics &fm = s->fontMetrics();
856 height = fm.height();
864 int hl = fm.leading() / 2;
865 int baseline = cb->baselinePosition(
false);
866 if (!cb->isReplaced() || cb->style()->display() == BLOCK) {
867 if (!outsideEnd ^ rtl)
868 _y -= fm.leading() / 2;
870 _y += kMax(cb->height() - fm.ascent() - hl, 0);
872 _y += baseline - fm.ascent() - hl;
877 RenderStyle *s = cb->style();
878 const TQFontMetrics &fm = s->fontMetrics();
879 height = fm.height();
881 _x += cb->borderLeft() + cb->paddingLeft();
882 _y += cb->borderTop() + cb->paddingTop();
885 switch (s->textAlign()) {
893 _x += cb->contentWidth() / 2;
897 _x += cb->contentWidth();
902 CaretBoxLine *result =
new CaretBoxLine;
903 deleter->append(result);
904 result->caret_boxes.append(
new CaretBox(_x, _y, width, height, cb,
905 outside, outsideEnd));
906 iter = result->begin();
910 #if DEBUG_CARETMODE > 0
911 void CaretBoxLine::dump(TQTextStream &ts,
const TQString &ind)
const
913 ts << ind <<
"cbl: baseFlowBox@" << basefb <<
endl;
914 TQString ind2 = ind +
" ";
915 for (
size_t i = 0; i < caret_boxes.size(); i++) {
916 if (i > 0) ts <<
endl;
917 caret_boxes[i]->dump(ts, ind2);
931 inline InlineFlowBox *seekBaseFlowBox(InlineBox *b, RenderObject *base = 0)
934 while (b->parent() && b->object() != base) {
937 Q_ASSERT(b->isInlineFlowBox());
938 return static_cast<InlineFlowBox *
>(b);
943 inline bool isBlockRenderReplaced(RenderObject *r)
945 return r->isRenderReplaced() && r->style()->display() == BLOCK;
964 static CaretBoxLine* findCaretBoxLine(DOM::NodeImpl *node,
long offset,
965 CaretBoxLineDeleter *cblDeleter, RenderObject *base,
966 long &r_ofs, CaretBoxIterator &caretBoxIt)
968 bool outside, outsideEnd;
969 RenderObject *r = findRenderer(node, offset, base, r_ofs, outside, outsideEnd);
970 if (!r) {
return 0; }
971 #if DEBUG_CARETMODE > 0
972 kdDebug(6200) <<
"=================== findCaretBoxLine" <<
endl;
973 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;
986 if (r->isText())
do {
987 RenderText *t =
static_cast<RenderText *
>(r);
989 InlineBox *b = t->findInlineTextBox(offset, dummy,
true);
994 if (t->m_lines.count() > 0)
995 b = t->m_lines[t->m_lines.count() - 1];
1001 InlineFlowBox *baseFlowBox = seekBaseFlowBox(b, base);
1002 #if DEBUG_CARETMODE > 2
1003 kdDebug(6200) <<
"text-box b: " << b <<
" baseFlowBox: " << baseFlowBox << (b && b->object() ? TQString(
" contains \"%1\"").arg(TQConstString(
static_cast<RenderText *
>(b->object())->str->s+b->minOffset(), kMin(b->maxOffset() - b->minOffset(), 15L)).string()) : TQString::null) <<
endl;
1006 if (t->containingBlock()->isListItem()) dumpLineBoxes(
static_cast<RenderFlow *
>(t->containingBlock()));
1008 #if DEBUG_CARETMODE > 0
1009 kdDebug(6200) <<
"=================== end findCaretBoxLine (renderText)" <<
endl;
1011 return CaretBoxLine::constructCaretBoxLine(cblDeleter, baseFlowBox,
1012 b, outside, outsideEnd, caretBoxIt);
1016 bool isrepl = isBlockRenderReplaced(r);
1017 if (r->isRenderBlock() || r->isRenderInline() || isrepl) {
1018 RenderFlow *flow =
static_cast<RenderFlow *
>(r);
1019 InlineFlowBox *firstLineBox = isrepl ? 0 : flow->firstLineBox();
1024 if (isrepl || r->isRenderBlock() && (outside || !firstLineBox)
1025 || r->isRenderInline() && !firstLineBox) {
1026 #if DEBUG_CARETMODE > 0
1027 kdDebug(6200) <<
"=================== end findCaretBoxLine (box " << (outside ? (outsideEnd ?
"outside end" :
"outside begin") :
"inside") <<
")" <<
endl;
1029 Q_ASSERT(r->isBox());
1030 return CaretBoxLine::constructCaretBoxLine(cblDeleter,
1031 static_cast<RenderBox *
>(r), outside, outsideEnd, caretBoxIt);
1034 kdDebug(6200) <<
"firstlinebox " << firstLineBox <<
endl;
1035 InlineFlowBox *baseFlowBox = seekBaseFlowBox(firstLineBox, base);
1036 return CaretBoxLine::constructCaretBoxLine(cblDeleter, baseFlowBox,
1037 firstLineBox, outside, outsideEnd, caretBoxIt);
1040 RenderBlock *cb = r->containingBlock();
1046 if (!cb->isRenderBlock()) {
1047 kdWarning() <<
"containing block is no render block!!! crash imminent" <<
endl;
1050 InlineFlowBox *flowBox = cb->firstLineBox();
1060 #if DEBUG_CARETMODE > 0
1061 kdDebug(6200) <<
"=================== end findCaretBoxLine (2)" <<
endl;
1063 return CaretBoxLine::constructCaretBoxLine(cblDeleter, cb,
1064 outside, outsideEnd, caretBoxIt);
1070 for (; flowBox; flowBox =
static_cast<InlineFlowBox *
>(flowBox->nextLineBox())) {
1071 #if DEBUG_CARETMODE > 0
1076 InlineFlowBox *baseFlowBox = seekBaseFlowBox(flowBox, base);
1077 CaretBoxLine *cbl = CaretBoxLine::constructCaretBoxLine(cblDeleter,
1078 baseFlowBox, 0, outside, outsideEnd, caretBoxIt, r);
1079 #if DEBUG_CARETMODE > 5
1082 if (caretBoxIt != cbl->end()) {
1083 #if DEBUG_CARETMODE > 0
1084 kdDebug(6200) <<
"=================== end findCaretBoxLine (3)" <<
endl;
1094 CaretBoxLine *cbl = findCaretBoxLine(nextLeafNode(node, base ? base->element() : 0), 0, cblDeleter, base, r_ofs, caretBoxIt);
1095 #if DEBUG_CARETMODE > 0
1096 kdDebug(6200) <<
"=================== end findCaretBoxLine" <<
endl;
1107 static inline RenderTable *findTableUpTo(RenderObject *r, RenderFlow *cb)
1109 while (r && r != cb && !r->isTable()) r = r->parent();
1110 return r && r->isTable() ?
static_cast<RenderTable *
>(r) : 0;
1115 static inline bool isDescendant(RenderObject *r, RenderObject *cb)
1117 while (r && r != cb) r = r->parent();
1131 static bool containsEditableElement(
TDEHTMLPart *part, RenderBlock *cb,
1132 RenderTable *&table,
bool fromEnd =
false)
1134 RenderObject *r = cb;
1136 while (r->lastChild()) r = r->lastChild();
1138 while (r->firstChild()) r = r->firstChild();
1140 RenderTable *tempTable = 0;
1144 ObjectTraversalState trav = InsideDescending;
1146 bool modWithinCb = withinCb = isDescendant(r, cb);
1153 tempTable = findTableUpTo(r, cb);
1155 #if DEBUG_CARETMODE > 1
1156 kdDebug(6201) <<
"cee: r " << (r ? r->renderName() : TQString::null) <<
"@" << r <<
" cb " << cb <<
" withinCb " << withinCb <<
" modWithinCb " << modWithinCb <<
" tempTable " << tempTable <<
endl;
1158 if (r && modWithinCb && r->element() && !isUnsuitable(r, trav)
1160 || r->style()->userInput() == UI_ENABLED)) {
1162 #if DEBUG_CARETMODE > 1
1171 r = fromEnd ? r->objectAbove() : r->objectBelow();
1172 }
while (r && withinCb);
1188 static bool containsEditableChildElement(
TDEHTMLPart *part, RenderBlock *cb,
1189 RenderTable *&table,
bool fromEnd, RenderObject *start)
1192 ObjectTraversalState trav = OutsideAscending;
1194 RenderObject *r = start;
1196 r = traverseRenderObjects(r, trav, fromEnd, cb->parent(), state);
1197 }
while(r && !(state & AdvancedToSibling));
1202 if (!r)
return false;
1205 while (r->firstChild()) r = r->firstChild();
1207 while (r->lastChild()) r = r->lastChild();
1209 if (!r)
return false;
1211 RenderTable *tempTable = 0;
1213 bool withinCb =
false;
1216 bool modWithinCb = withinCb = isDescendant(r, cb);
1223 tempTable = findTableUpTo(r, cb);
1225 #if DEBUG_CARETMODE > 1
1226 kdDebug(6201) <<
"cece: r " << (r ? r->renderName() : TQString::null) <<
"@" << r <<
" cb " << cb <<
" withinCb " << withinCb <<
" modWithinCb " << modWithinCb <<
" tempTable " << tempTable <<
endl;
1228 if (r && withinCb && r->element() && !isUnsuitable(r, trav)
1230 || r->style()->userInput() == UI_ENABLED)) {
1232 #if DEBUG_CARETMODE > 1
1238 r = fromEnd ? r->objectAbove() : r->objectBelow();
1245 LinearDocument::LinearDocument(
TDEHTMLPart *part, NodeImpl *node,
long offset,
1246 CaretAdvancePolicy advancePolicy, ElementImpl *baseElem)
1247 : node(node), offset(offset), m_part(part),
1248 advPol(advancePolicy), base(0)
1250 if (node == 0)
return;
1253 RenderObject *b = baseElem->renderer();
1254 if (b && (b->isRenderBlock() || b->isRenderInline()))
1258 initPreBeginIterator();
1262 LinearDocument::~LinearDocument()
1266 int LinearDocument::count()
const
1272 LinearDocument::Iterator LinearDocument::current()
1274 return LineIterator(
this, node, offset);
1277 LinearDocument::Iterator LinearDocument::begin()
1279 NodeImpl *n = base ? base->element() : 0;
1280 if (!base) n = node ? node->getDocument() : 0;
1281 if (!n)
return end();
1283 n = n->firstChild();
1284 if (advPol == LeafsOnly)
1285 while (n->firstChild()) n = n->firstChild();
1287 if (!n)
return end();
1288 return LineIterator(
this, n, n->minOffset());
1291 LinearDocument::Iterator LinearDocument::preEnd()
1293 NodeImpl *n = base ? base->element() : 0;
1294 if (!base) n = node ? node->getDocument() : 0;
1295 if (!n)
return preBegin();
1298 if (advPol == LeafsOnly)
1299 while (n->lastChild()) n = n->lastChild();
1301 if (!n)
return preBegin();
1302 return LineIterator(
this, n, n->maxOffset());
1305 void LinearDocument::initPreBeginIterator()
1307 _preBegin = LineIterator(
this, 0, 0);
1310 void LinearDocument::initEndIterator()
1312 _end = LineIterator(
this, 0, 1);
1317 CaretBoxIterator LineIterator::currentBox ;
1318 long LineIterator::currentOffset ;
1320 LineIterator::LineIterator(LinearDocument *l, DOM::NodeImpl *node,
long offset)
1324 if (!node) { cbl = 0;
return; }
1325 cbl = findCaretBoxLine(node, offset, &lines->cblDeleter,
1326 l->baseObject(), currentOffset, currentBox);
1328 #if DEBUG_CARETMODE > 0
1329 if (!cbl)
kdDebug(6200) <<
"no render object found!" <<
endl;
1332 #if DEBUG_CARETMODE > 1
1333 kdDebug(6200) <<
"LineIterator: offset " << offset <<
" outside " << cbl->isOutside() <<
endl;
1335 #if DEBUG_CARETMODE > 3
1338 if (currentBox == cbl->end()) {
1339 #if DEBUG_CARETMODE > 0
1340 kdDebug(6200) <<
"LineIterator: findCaretBoxLine failed" <<
endl;
1346 void LineIterator::nextBlock()
1348 RenderObject *base = lines->baseObject();
1350 bool cb_outside = cbl->isOutside();
1351 bool cb_outside_end = cbl->isOutsideEnd();
1354 RenderObject *r = cbl->enclosingObject();
1356 ObjectTraversalState trav;
1358 mapRenderPosToTraversalState(cb_outside, cb_outside_end,
false, trav);
1359 #if DEBUG_CARETMODE > 1
1360 kdDebug(6200) <<
"nextBlock: before adv r" << r <<
" " << (r ? r->renderName() : TQString::null) << (r && r->isText() ?
" contains \"" + TQString(((RenderText *)r)->str->s, TQMIN(((RenderText *)r)->str->l,15)) +
"\"" : TQString::null) <<
" trav " << trav <<
" cb_outside " << cb_outside <<
" cb_outside_end " << cb_outside_end <<
endl;
1362 r = advanceSuitableObject(r, trav,
false, base, state);
1368 mapTraversalStateToRenderPos(trav,
false, cb_outside, cb_outside_end);
1369 #if DEBUG_CARETMODE > 1
1370 kdDebug(6200) <<
"nextBlock: after r" << r <<
" trav " << trav <<
" cb_outside " << cb_outside <<
" cb_outside_end " << cb_outside_end <<
endl;
1372 #if DEBUG_CARETMODE > 0
1373 kdDebug(6200) <<
"++: r " << r <<
"[" << (r?r->renderName():TQString::null) <<
"]" <<
endl;
1379 bool isrepl = isBlockRenderReplaced(r);
1380 if (r->isRenderBlock() || isrepl) {
1381 RenderBox *cb =
static_cast<RenderBox *
>(r);
1383 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
1384 cb_outside, cb_outside_end, currentBox);
1386 #if DEBUG_CARETMODE > 0
1387 kdDebug(6200) <<
"r->isFlow is cb. continuation @" << cb->continuation() <<
endl;
1391 cb = r->containingBlock();
1392 Q_ASSERT(cb->isRenderBlock());
1394 InlineFlowBox *flowBox = cb->firstLineBox();
1395 #if DEBUG_CARETMODE > 0
1396 kdDebug(6200) <<
"++: flowBox " << flowBox <<
" cb " << cb <<
"[" << (cb?cb->renderName()+TQString(
".node ")+TQString::number((
unsigned)cb->element(),16)+(cb->element()?
"@"+cb->element()->nodeName().string():TQString::null):TQString::null) <<
"]" <<
endl;
1400 cb_outside = cb_outside_end =
true;
1401 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
1402 cb_outside, cb_outside_end, currentBox);
1406 bool seekOutside =
false, seekOutsideEnd =
false;
1407 CaretBoxIterator it;
1408 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
1409 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
1413 void LineIterator::prevBlock()
1415 RenderObject *base = lines->baseObject();
1417 bool cb_outside = cbl->isOutside();
1418 bool cb_outside_end = cbl->isOutsideEnd();
1421 RenderObject *r = cbl->enclosingObject();
1422 if (r->isAnonymous() && !cb_outside)
1423 cb_outside =
true, cb_outside_end =
false;
1425 ObjectTraversalState trav;
1427 mapRenderPosToTraversalState(cb_outside, cb_outside_end,
true, trav);
1428 #if DEBUG_CARETMODE > 1
1429 kdDebug(6200) <<
"prevBlock: before adv r" << r <<
" " << (r ? r->renderName() : TQString::null) << (r && r->isText() ?
" contains \"" + TQString(((RenderText *)r)->str->s, TQMIN(((RenderText *)r)->str->l,15)) +
"\"" : TQString::null) <<
" trav " << trav <<
" cb_outside " << cb_outside <<
" cb_outside_end " << cb_outside_end <<
endl;
1431 r = advanceSuitableObject(r, trav,
true, base, state);
1437 mapTraversalStateToRenderPos(trav,
true, cb_outside, cb_outside_end);
1438 #if DEBUG_CARETMODE > 1
1439 kdDebug(6200) <<
"prevBlock: after r" << r <<
" trav " << trav <<
" cb_outside " << cb_outside <<
" cb_outside_end " << cb_outside_end <<
endl;
1441 #if DEBUG_CARETMODE > 0
1442 kdDebug(6200) <<
"--: r " << r <<
"[" << (r?r->renderName():TQString::null) <<
"]" <<
endl;
1448 bool isrepl = isBlockRenderReplaced(r);
1450 if (r->isRenderBlock() || isrepl) {
1451 RenderBox *cb =
static_cast<RenderBox *
>(r);
1453 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
1454 cb_outside, cb_outside_end, currentBox);
1456 #if DEBUG_CARETMODE > 0
1457 kdDebug(6200) <<
"r->isFlow is cb. continuation @" << cb->continuation() <<
endl;
1461 cb = r->containingBlock();
1462 Q_ASSERT(cb->isRenderBlock());
1464 InlineFlowBox *flowBox = cb->lastLineBox();
1465 #if DEBUG_CARETMODE > 0
1466 kdDebug(6200) <<
"--: flowBox " << flowBox <<
" cb " << cb <<
"[" << (cb?cb->renderName()+TQString(
".node ")+TQString::number((
unsigned)cb->element(),16)+(cb->element()?
"@"+cb->element()->nodeName().string():TQString::null):TQString::null) <<
"]" <<
endl;
1470 cb_outside =
true; cb_outside_end =
false;
1471 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb,
1472 cb_outside, cb_outside_end, currentBox);
1476 bool seekOutside =
false, seekOutsideEnd =
false;
1477 CaretBoxIterator it;
1478 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
1479 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
1483 void LineIterator::advance(
bool toBegin)
1485 InlineFlowBox *flowBox = cbl->baseFlowBox();
1487 flowBox =
static_cast<InlineFlowBox *
>(toBegin ? flowBox->prevLineBox() : flowBox->nextLineBox());
1489 bool seekOutside =
false, seekOutsideEnd =
false;
1490 CaretBoxIterator it;
1491 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
1492 flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it);
1497 if (!flowBox) {
if (toBegin) prevBlock();
else nextBlock(); }
1499 #if DEBUG_CARETMODE > 3
1500 if (cbl)
kdDebug(6200) << cbl->information() <<
endl;
1506 void EditableCaretBoxIterator::advance(
bool toBegin)
1508 #if DEBUG_CARETMODE > 3
1509 kdDebug(6200) <<
"---------------" << k_funcinfo <<
"toBegin " << toBegin <<
endl;
1511 const CaretBoxIterator preBegin = cbl->preBegin();
1512 const CaretBoxIterator
end = cbl->end();
1514 CaretBoxIterator lastbox = *
this, curbox;
1515 bool islastuseable =
true;
1520 #if DEBUG_CARETMODE > 4
1524 if (toBegin) CaretBoxIterator::operator --();
else CaretBoxIterator::operator ++();
1525 bool curAtEnd = *
this == preBegin || *
this ==
end;
1529 iscuruseable = isEditable(curbox, toBegin);
1530 if (toBegin) CaretBoxIterator::operator --();
else CaretBoxIterator::operator ++();
1531 atEnd = *
this == preBegin || *
this ==
end;
1534 bool haslast = lastbox !=
end && lastbox != preBegin;
1535 bool hascoming = !atEnd;
1536 bool iscominguseable =
true;
1538 if (!atEnd) iscominguseable = isEditable(*
this, toBegin);
1540 #if DEBUG_CARETMODE > 3
1541 kdDebug(6200) <<
"ebit::advance: " << (*curbox)->object() <<
"@" << (*curbox)->object()->renderName() <<
".node " << (*curbox)->object()->element() <<
"[" << ((*curbox)->object()->element() ? (*curbox)->object()->element()->nodeName().string() : TQString::null) <<
"] inline " << (*curbox)->isInline() <<
" outside " << (*curbox)->isOutside() <<
" outsideEnd " << (*curbox)->isOutsideEnd() <<
endl;
1544 CaretBox *box = *curbox;
1545 if (box->isOutside()) {
1548 if (!box->isInline())
break;
1550 if (advpol == VisibleFlows)
break;
1554 InlineBox *ibox = box->inlineBox();
1556 InlineBox *prev = box->isOutsideEnd() ? ibox : ibox->prevOnLine();
1558 InlineBox *
next = box->isOutsideEnd() ? ibox->nextOnLine() : ibox;
1560 const bool isprevindicated = !prev || isIndicatedInlineBox(prev);
1561 const bool isnextindicated = !
next || isIndicatedInlineBox(next);
1562 const bool last = haslast && !islastuseable;
1563 const bool coming = hascoming && !iscominguseable;
1564 const bool left = !prev || prev->isInlineFlowBox() && isprevindicated
1565 || (toBegin && coming || !toBegin && last);
1566 const bool right = !
next ||
next->isInlineFlowBox() && isnextindicated
1567 || (!toBegin && coming || toBegin && last);
1568 const bool text2indicated = toBegin &&
next &&
next->isInlineTextBox()
1570 || !toBegin && prev && prev->isInlineTextBox() && isnextindicated;
1571 const bool indicated2text = !toBegin &&
next &&
next->isInlineTextBox()
1572 && prev && isprevindicated
1575 #if DEBUG_CARETMODE > 5
1576 kdDebug(6200) <<
"prev " << prev <<
" haslast " << haslast <<
" islastuseable " << islastuseable <<
" left " << left <<
" next " <<
next <<
" hascoming " << hascoming <<
" iscominguseable " << iscominguseable <<
" right " << right <<
" text2indicated " << text2indicated <<
" indicated2text " << indicated2text <<
endl;
1579 if (left && right && !text2indicated || indicated2text) {
1581 #if DEBUG_CARETMODE > 4
1582 kdDebug(6200) <<
"left && right && !text2indicated || indicated2text" <<
endl;
1589 #if DEBUG_CARETMODE > 4
1590 if (box->isInline()) {
1591 InlineBox *ibox = box->inlineBox();
1592 kdDebug(6200) <<
"inside " << (!ibox->isInlineFlowBox() ||
static_cast<InlineFlowBox *
>(ibox)->firstChild() ?
"non-empty" :
"empty") << (isIndicatedInlineBox(ibox) ?
" indicated" :
"") <<
" adjacent=" << adjacent <<
endl;
1595 RenderStyle *s = ibox->object()->style();
1596 kdDebug(6200) <<
"bordls " << s->borderLeftStyle()
1597 <<
" bordl " << (s->borderLeftStyle() != BNONE)
1598 <<
" bordr " << (s->borderRightStyle() != BNONE)
1599 <<
" bordt " << (s->borderTopStyle() != BNONE)
1600 <<
" bordb " << (s->borderBottomStyle() != BNONE)
1601 <<
" padl " << s->paddingLeft().value()
1602 <<
" padr " << s->paddingRight().value()
1603 <<
" padt " << s->paddingTop().value()
1604 <<
" padb " << s->paddingBottom().value()
1607 <<
" marl " << s->marginLeft().value()
1608 <<
" marr " << s->marginRight().value()
1617 if (!(*curbox)->isOutside()) {
1624 islastuseable = iscuruseable;
1626 iscuruseable = iscominguseable;
1629 if (toBegin) CaretBoxIterator::operator --();
else CaretBoxIterator::operator ++();
1630 atEnd = *
this == preBegin || *
this ==
end;
1634 *
static_cast<CaretBoxIterator *
>(
this) = curbox;
1635 #if DEBUG_CARETMODE > 4
1638 #if DEBUG_CARETMODE > 3
1639 kdDebug(6200) <<
"---------------" << k_funcinfo <<
"end " <<
endl;
1643 bool EditableCaretBoxIterator::isEditable(
const CaretBoxIterator &boxit,
bool fromEnd)
1645 Q_ASSERT(boxit != cbl->end() && boxit != cbl->preBegin());
1646 CaretBox *b = *boxit;
1647 RenderObject *r = b->object();
1648 #if DEBUG_CARETMODE > 0
1650 kdDebug(6200) <<
"isEditable r" << r <<
": " << (r ? r->renderName() : TQString::null) << (r && r->isText() ?
" contains \"" + TQString(((RenderText *)r)->str->s, TQMIN(((RenderText *)r)->str->l,15)) +
"\"" : TQString::null) <<
endl;
1655 NodeImpl *node = r->element();
1656 ObjectTraversalState trav;
1657 mapRenderPosToTraversalState(b->isOutside(), b->isOutsideEnd(), fromEnd, trav);
1658 if (isUnsuitable(r, trav) || !node) {
1663 if (!b->isOutside() && r->isRenderReplaced() && !r->firstChild())
1666 RenderObject *eff_r = r;
1667 bool globallyNavigable = m_part->isCaretMode() || m_part->isEditable();
1670 if (b->isOutside() && !globallyNavigable) {
1671 NodeImpl *par = node->parent();
1675 if (par) node = par;
1676 eff_r = node->renderer();
1680 bool result = globallyNavigable || eff_r->style()->userInput() == UI_ENABLED;
1681 #if DEBUG_CARETMODE > 0
1689 void EditableLineIterator::advance(
bool toBegin)
1691 CaretAdvancePolicy advpol = lines->advancePolicy();
1692 LineIterator lasteditable, lastindicated;
1693 bool haslasteditable =
false;
1694 bool haslastindicated =
false;
1695 bool uselasteditable =
false;
1697 LineIterator::advance(toBegin);
1699 if (isEditable(*
this)) {
1700 #if DEBUG_CARETMODE > 3
1701 kdDebug(6200) <<
"advance: " << cbl->enclosingObject() <<
"@" << cbl->enclosingObject()->renderName() <<
".node " << cbl->enclosingObject()->element() <<
"[" << (cbl->enclosingObject()->element() ? cbl->enclosingObject()->element()->nodeName().string() : TQString::null) <<
"]" <<
endl;
1704 bool hasindicated = isIndicatedFlow(cbl->enclosingObject());
1706 haslastindicated =
true;
1707 lastindicated = *
this;
1711 case IndicatedFlows:
1712 if (hasindicated)
goto wend;
1715 if (cbl->isOutside())
break;
1717 case VisibleFlows:
goto wend;
1721 lasteditable = *
this;
1722 haslasteditable =
true;
1723 #if DEBUG_CARETMODE > 4
1724 kdDebug(6200) <<
"remembered lasteditable " << *lasteditable <<
endl;
1732 if (haslasteditable) { uselasteditable =
true;
break; }
1735 LineIterator::advance(toBegin);
1739 if (uselasteditable) *
this = haslastindicated ? lastindicated : lasteditable;
1740 if (!cbl && haslastindicated) *
this = lastindicated;
1745 void EditableCharacterIterator::initFirstChar()
1747 CaretBox *box = *ebit;
1748 InlineBox *b = box->inlineBox();
1749 if (_offset == box->maxOffset())
1751 else if (b && !box->isOutside() && b->isInlineTextBox())
1752 _char =
static_cast<RenderText *
>(b->object())->str->s[_offset].unicode();
1760 static inline bool isCaretBoxEmpty(CaretBox *box) {
1761 if (!box->isInline())
return false;
1762 InlineBox *ibox = box->inlineBox();
1763 return ibox->isInlineFlowBox()
1764 && !
static_cast<InlineFlowBox *
>(ibox)->firstChild()
1765 && !isIndicatedInlineBox(ibox);
1768 EditableCharacterIterator &EditableCharacterIterator::operator ++()
1772 CaretBox *box = *ebit;
1773 InlineBox *b = box->inlineBox();
1774 long maxofs = box->maxOffset();
1775 #if DEBUG_CARETMODE > 0
1776 kdDebug(6200) <<
"box->maxOffset() " << box->maxOffset() <<
" box->minOffset() " << box->minOffset() <<
endl;
1778 if (_offset == maxofs) {
1779 #if DEBUG_CARETMODE > 2
1780 kdDebug(6200) <<
"_offset == maxofs: " << _offset <<
" == " << maxofs <<
endl;
1783 }
else if (_offset > maxofs) {
1784 #if DEBUG_CARETMODE > 2
1785 kdDebug(6200) <<
"_offset > maxofs: " << _offset <<
" > " << maxofs <<
endl;
1789 if (ebit == (*_it)->end()) {
1791 #if DEBUG_CARETMODE > 3
1794 if (_it != _it.lines->end()) {
1797 b = box->inlineBox();
1798 #if DEBUG_CARETMODE > 3
1799 kdDebug(6200) <<
"box " << box <<
" b " << b <<
" isText " << box->isInlineTextBox() <<
endl;
1802 #if DEBUG_CARETMODE > 3
1803 RenderObject *_r = box->object();
1804 kdDebug(6200) <<
"_r " << _r <<
":" << _r->element()->nodeName().string() <<
endl;
1806 _offset = box->minOffset();
1807 #if DEBUG_CARETMODE > 3
1818 bool adjacent = ebit.isAdjacent();
1821 if (adjacent && !(*ebit)->isInlineTextBox()) {
1822 EditableCaretBoxIterator
copy = ebit;
1824 if (ebit != (*_it)->end() && (*ebit)->isInlineTextBox()
1832 if (adjacent && !(*ebit)->isInlineTextBox()) {
1833 bool noemptybox =
true;
1834 while (isCaretBoxEmpty(*ebit)) {
1836 EditableCaretBoxIterator
copy = ebit;
1838 if (ebit == (*_it)->end()) { ebit =
copy;
break; }
1840 if (noemptybox) adjacent =
false;
1843 _offset = (*ebit)->minOffset() + adjacent;
1846 b = box->inlineBox();
1851 if (b && !box->isOutside() && b->isInlineTextBox() && _offset < b->maxOffset())
1852 _char =
static_cast<RenderText *
>(b->object())->str->s[_offset].unicode();
1856 #if DEBUG_CARETMODE > 2
1857 kdDebug(6200) <<
"_offset: " << _offset <<
" char '" << (char)_char <<
"'" <<
endl;
1860 #if DEBUG_CARETMODE > 0
1861 if (!_end && ebit != (*_it)->end()) {
1862 CaretBox *box = *ebit;
1863 RenderObject *_r = box->object();
1864 kdDebug(6200) <<
"echit++(1): box " << box << (box && box->isInlineTextBox() ? TQString(
" contains \"%1\"").arg(TQConstString(
static_cast<RenderText *
>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : TQString::null) <<
" _r " << (_r ? _r->element()->nodeName().string() : TQString(
"<nil>")) <<
endl;
1870 EditableCharacterIterator &EditableCharacterIterator::operator --()
1875 CaretBox *box = *ebit;
1876 CaretBox *_peekPrev = 0;
1877 CaretBox *_peekNext = 0;
1878 InlineBox *b = box->inlineBox();
1879 long minofs = box->minOffset();
1880 #if DEBUG_CARETMODE > 0
1881 kdDebug(6200) <<
"box->maxOffset() " << box->maxOffset() <<
" box->minOffset() " << box->minOffset() <<
endl;
1883 if (_offset == minofs) {
1884 #if DEBUG_CARETMODE > 2
1885 kdDebug(6200) <<
"_offset == minofs: " << _offset <<
" == " << minofs <<
endl;
1889 if (b && !box->isOutside() && b->isInlineTextBox())
1890 _char =
static_cast<RenderText *
>(b->object())->text()[_offset].unicode();
1895 bool do_prev =
false;
1897 EditableCaretBoxIterator
copy;
1902 if (ebit == (*_it)->preBegin()) { ebit =
copy;
break; }
1903 }
while (isCaretBoxEmpty(*ebit));
1905 if (ebit.isAdjacent() && ebit != (*_it)->preBegin() && (*ebit)->isInlineTextBox()) {
1911 if (do_prev)
goto prev;
1912 }
else if (_offset < minofs) {
1914 #if DEBUG_CARETMODE > 2
1915 kdDebug(6200) <<
"_offset < minofs: " << _offset <<
" < " << minofs <<
endl;
1920 if (ebit == (*_it)->preBegin()) {
1922 #if DEBUG_CARETMODE > 3
1925 if (_it != _it.lines->preBegin()) {
1927 ebit = EditableCaretBoxIterator(_it,
true);
1930 #if DEBUG_CARETMODE > 3
1931 kdDebug(6200) <<
"box " << box <<
" b " << box->inlineBox() <<
" isText " << box->isInlineTextBox() <<
endl;
1933 _offset = box->maxOffset();
1936 #if DEBUG_CARETMODE > 0
1937 kdDebug(6200) <<
"echit--(2): box " << box <<
" b " << box->inlineBox() << (box->isInlineTextBox() ? TQString(
" contains \"%1\"").arg(TQConstString(
static_cast<RenderText *
>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : TQString::null) <<
endl;
1945 #if DEBUG_CARETMODE > 0
1946 bool adjacent = ebit.isAdjacent();
1947 kdDebug(6200) <<
"adjacent " << adjacent <<
" _peekNext " << _peekNext <<
" _peekNext->isInlineTextBox: " << (_peekNext ? _peekNext->isInlineTextBox() :
false) <<
" !((*ebit)->isInlineTextBox): " << (*ebit ? !(*ebit)->isInlineTextBox() :
true) <<
endl;
1951 if (adjacent && _peekNext && _peekNext->isInlineTextBox()
1952 && !(*ebit)->isInlineTextBox()) {
1953 EditableCaretBoxIterator
copy = ebit;
1955 if (ebit == (*_it)->preBegin())
1964 && !(*ebit)->isInlineTextBox()) {
1965 bool noemptybox =
true;
1966 while (isCaretBoxEmpty(*ebit)) {
1968 EditableCaretBoxIterator
copy = ebit;
1970 if (ebit == (*_it)->preBegin()) { ebit =
copy;
break; }
1971 else _peekNext = *
copy;
1973 if (noemptybox) adjacent =
false;
1976 #if DEBUG_CARETMODE > 0
1977 kdDebug(6200) <<
"(*ebit)->obj " << (*ebit)->object()->renderName() <<
"[" << (*ebit)->object() <<
"]" <<
" minOffset: " << (*ebit)->minOffset() <<
" maxOffset: " << (*ebit)->maxOffset() <<
endl;
1979 #if DEBUG_CARETMODE > 3
1980 RenderObject *_r = (*ebit)->object();
1981 kdDebug(6200) <<
"_r " << _r <<
":" << _r->element()->nodeName().string() <<
endl;
1983 _offset = (*ebit)->maxOffset();
1985 #if DEBUG_CARETMODE > 3
1990 #if DEBUG_CARETMODE > 0
1991 kdDebug(6200) <<
"_offset: " << _offset <<
" _peekNext: " << _peekNext <<
endl;
1994 if (_peekNext && _offset >= box->maxOffset() && _peekNext->isInlineTextBox())
1995 _char =
static_cast<RenderText *
>(_peekNext->object())->text()[_peekNext->minOffset()].unicode();
1996 else if (b && _offset < b->maxOffset() && b->isInlineTextBox())
1997 _char =
static_cast<RenderText *
>(b->object())->text()[_offset].unicode();
2002 #if DEBUG_CARETMODE > 0
2003 if (!_end && ebit != (*_it)->preBegin()) {
2004 CaretBox *box = *ebit;
2005 kdDebug(6200) <<
"echit--(1): box " << box <<
" b " << box->inlineBox() << (box->isInlineTextBox() ? TQString(
" contains \"%1\"").arg(TQConstString(
static_cast<RenderText *
>(box->object())->str->s+box->minOffset(), box->maxOffset() - box->minOffset()).string()) : TQString::null) <<
endl;
2013 TableRowIterator::TableRowIterator(RenderTable *table,
bool fromEnd,
2014 RenderTableSection::RowStruct *row)
2015 : sec(table, fromEnd)
2019 if (fromEnd) index = (*sec)->grid.size() - 1;
2025 while (
operator *() != row)
2026 if (fromEnd) operator --();
else operator ++();
2030 TableRowIterator &TableRowIterator::operator ++()
2034 if (index >= (
int)(*sec)->grid.size()) {
2037 if (*sec) index = 0;
2042 TableRowIterator &TableRowIterator::operator --()
2049 if (*sec) index = (*sec)->grid.size() - 1;
2057 static RenderTableCell *findNearestTableCellInRow(
TDEHTMLPart *part,
int x,
2058 RenderTableSection::RowStruct *row,
bool fromEnd);
2073 static inline RenderTableCell *findNearestTableCell(
TDEHTMLPart *part,
int x,
2074 TableRowIterator &it,
bool fromEnd)
2076 RenderTableCell *result = 0;
2079 result = findNearestTableCellInRow(part, x, *it, fromEnd);
2082 if (fromEnd) --it;
else ++it;
2101 static RenderTableCell *findNearestTableCellInRow(
TDEHTMLPart *part,
int x,
2102 RenderTableSection::RowStruct *row,
bool fromEnd)
2105 int n = (int)row->row->size();
2107 for (i = 0; i < n; i++) {
2108 RenderTableCell *cell = row->row->at(i);
2109 if (!cell || (
long)cell == -1)
continue;
2112 cell->absolutePosition(absx, absy,
false);
2113 #if DEBUG_CARETMODE > 1
2114 kdDebug(6201) <<
"i/n " << i <<
"/" << n <<
" absx " << absx <<
" absy " << absy <<
endl;
2119 #if DEBUG_CARETMODE > 1
2120 kdDebug(6201) <<
"x " << x <<
" < " << (absx + cell->width()) <<
"?" <<
endl;
2122 if (x < absx + cell->width())
break;
2124 if (i >= n) i = n - 1;
2128 for (
int cnt = 0; cnt < 2*n; cnt++) {
2129 int index = i - ((cnt >> 1) + 1)*(cnt & 1) + (cnt >> 1)*!(cnt & 1);
2130 if (index < 0 || index >= n)
continue;
2132 RenderTableCell *cell = row->row->at(index);
2133 if (!cell || (
long)cell == -1)
continue;
2135 #if DEBUG_CARETMODE > 1
2136 kdDebug(6201) <<
"index " << index <<
" cell " << cell <<
endl;
2138 RenderTable *nestedTable;
2139 if (containsEditableElement(part, cell, nestedTable, fromEnd)) {
2142 TableRowIterator it(nestedTable, fromEnd);
2145 cell = findNearestTableCell(part, x, it, fromEnd);
2147 if (fromEnd) --it;
else ++it;
2163 static RenderObject *commonAncestorTableSectionOrCell(RenderObject *r1,
2166 if (!r1 || !r2)
return 0;
2167 RenderTableSection *sec = 0;
2168 int start_depth=0, end_depth=0;
2170 RenderObject *n = r1;
2171 while (n->parent()) {
2176 while( n->parent()) {
2181 while (end_depth > start_depth) {
2185 while (start_depth > end_depth) {
2193 if (r1->isTableSection()) sec =
static_cast<RenderTableSection *
>(r1);
2199 while (r1 && !r1->isTableCell() && !r1->isTableSection() && !r1->isTable())
2202 return r1 && r1->isTable() ? sec : r1;
2212 static int findRowInSection(RenderTableSection *section, RenderTableCell *cell,
2213 RenderTableSection::RowStruct *&row, RenderTableCell *&directCell)
2216 RenderObject *r = cell;
2217 while (r != section) {
2218 if (r->isTableCell()) directCell =
static_cast<RenderTableCell *
>(r);
2225 int n = section->numRows();
2226 for (
int i = 0; i < n; i++) {
2227 row = §ion->grid[i];
2230 int m = row->row->size();
2231 for (
int j = 0; j < m; j++) {
2232 RenderTableCell *c = row->row->at(j);
2233 if (c == directCell)
return i;
2246 static inline RenderTable *findFirstDescendantTable(RenderObject *leaf, RenderBlock *block)
2248 RenderTable *result = 0;
2249 while (leaf && leaf != block) {
2250 if (leaf->isTable()) result =
static_cast<RenderTable *
>(leaf);
2251 leaf = leaf->parent();
2259 static inline RenderTableCell *containingTableCell(RenderObject *r)
2261 while (r && !r->isTableCell()) r = r->parent();
2262 return static_cast<RenderTableCell *
>(r);
2265 inline void ErgonomicEditableLineIterator::calcAndStoreNewLine(
2266 RenderBlock *newBlock,
bool toBegin)
2270 CaretBoxIterator it;
2271 cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter,
2272 newBlock,
true, toBegin, it);
2273 #if DEBUG_CARETMODE > 3
2282 EditableLineIterator::advance(toBegin);
2285 void ErgonomicEditableLineIterator::determineTopologicalElement(
2286 RenderTableCell *oldCell, RenderObject *newObject,
bool toBegin)
2293 TableRowIterator it;
2295 RenderObject *commonAncestor = commonAncestorTableSectionOrCell(oldCell, newObject);
2296 #if DEBUG_CARETMODE > 1
2297 kdDebug(6201) <<
" ancestor " << commonAncestor <<
endl;
2301 if (!commonAncestor || commonAncestor->isTableCell()) {
2303 RenderTableCell *cell =
static_cast<RenderTableCell *
>(commonAncestor);
2304 RenderTable *table = findFirstDescendantTable(newObject, cell);
2306 #if DEBUG_CARETMODE > 0
2314 it = TableRowIterator(table, toBegin);
2316 }
else if (commonAncestor->isTableSection()) {
2318 RenderTableSection *section =
static_cast<RenderTableSection *
>(commonAncestor);
2319 RenderTableSection::RowStruct *row;
2320 int idx = findRowInSection(section, oldCell, row, oldCell);
2321 #if DEBUG_CARETMODE > 1
2322 kdDebug(6201) <<
"table section: row idx " << idx <<
endl;
2325 it = TableRowIterator(section, idx);
2328 int rowspan = oldCell->rowSpan();
2329 while (*it && rowspan--) {
2330 if (toBegin) --it;
else ++it;
2334 kdError(6201) <<
"Neither common cell nor section! " << commonAncestor->renderName() <<
endl;
2338 RenderTableCell *cell = findNearestTableCell(lines->m_part, xCoor, it, toBegin);
2339 #if DEBUG_CARETMODE > 1
2340 kdDebug(6201) <<
"findNearestTableCell result: " << cell <<
endl;
2343 RenderBlock *newBlock = cell;
2345 Q_ASSERT(commonAncestor->isTableSection());
2346 RenderTableSection *section =
static_cast<RenderTableSection *
>(commonAncestor);
2347 cell = containingTableCell(section);
2348 #if DEBUG_CARETMODE > 1
2349 kdDebug(6201) <<
"containing cell: " << cell <<
endl;
2352 RenderTable *nestedTable;
2353 bool editableChild = cell && containsEditableChildElement(lines->m_part,
2354 cell, nestedTable, toBegin, section->table());
2356 if (cell && !editableChild) {
2357 #if DEBUG_CARETMODE > 1
2358 kdDebug(6201) <<
"========= recursive invocation outer =========" <<
endl;
2360 determineTopologicalElement(cell, cell->section(), toBegin);
2361 #if DEBUG_CARETMODE > 1
2362 kdDebug(6201) <<
"========= end recursive invocation outer =========" <<
endl;
2366 }
else if (cell && nestedTable) {
2367 #if DEBUG_CARETMODE > 1
2368 kdDebug(6201) <<
"========= recursive invocation inner =========" <<
endl;
2370 determineTopologicalElement(cell, nestedTable, toBegin);
2371 #if DEBUG_CARETMODE > 1
2372 kdDebug(6201) <<
"========= end recursive invocation inner =========" <<
endl;
2377 #if DEBUG_CARETMODE > 1
2378 kdDebug(6201) <<
"newBlock is table: " << section->table() <<
endl;
2380 RenderObject *r = section->table();
2382 ObjectTraversalState trav = OutsideAscending;
2383 r = advanceSuitableObject(r, trav, toBegin, lines->baseObject(), state);
2384 if (!r) { cbl = 0;
return; }
2386 newBlock =
static_cast<RenderBlock *
>(!r || r->isRenderBlock() ? r : r->containingBlock());
2395 RenderObject *r = newBlock;
2397 ObjectTraversalState trav = OutsideAscending;
2398 r = advanceSuitableObject(r, trav,
true, lines->advancePolicy(), lines->baseObject(), state);
2399 newBlock =
static_cast<RenderBlock *
>(!r || r->isRenderBlock() ? r : r->containingBlock());
2404 calcAndStoreNewLine(newBlock, toBegin);
2407 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator ++()
2409 RenderTableCell *oldCell = containingTableCell(cbl->enclosingObject());
2411 EditableLineIterator::operator ++();
2412 if (*
this == lines->end() || *
this == lines->preBegin())
return *
this;
2414 RenderTableCell *newCell = containingTableCell(cbl->enclosingObject());
2416 if (!newCell || newCell == oldCell)
return *
this;
2418 determineTopologicalElement(oldCell, newCell,
false);
2423 ErgonomicEditableLineIterator &ErgonomicEditableLineIterator::operator --()
2425 RenderTableCell *oldCell = containingTableCell(cbl->enclosingObject());
2427 EditableLineIterator::operator --();
2428 if (*
this == lines->end() || *
this == lines->preBegin())
return *
this;
2430 RenderTableCell *newCell = containingTableCell(cbl->enclosingObject());
2432 if (!newCell || newCell == oldCell)
return *
this;
2434 determineTopologicalElement(oldCell, newCell,
true);
2450 static CaretBox *nearestCaretBox(LineIterator &it, CaretViewContext *cv,
2451 int &x,
int &absx,
int &absy)
2454 RenderObject *cb = (*it)->containingBlock();
2455 #if DEBUG_CARETMODE > 4
2456 kdDebug(6200) <<
"nearestCB: cb " << cb <<
"@" << (cb ? cb->renderName() :
"") <<
endl;
2459 if (cb) cb->absolutePosition(absx, absy);
2460 else absx = absy = 0;
2465 x = cv->origX - absx;
2466 CaretBox *caretBox = 0;
2470 EditableCaretBoxIterator fbit = it;
2471 #if DEBUG_CARETMODE > 0
2477 for (CaretBox *b; fbit != (*it)->end(); ++fbit) {
2480 #if DEBUG_CARETMODE > 0
2490 if (oldXPos < 0 || x - (oldXPos + caretBox->width()) > xPos - x) {
2499 if (x >= xPos && x < xPos + caretBox->width())
2515 static void moveItToNextWord(EditableCharacterIterator &it)
2517 #if DEBUG_CARETMODE > 0
2518 kdDebug(6200) <<
"%%%%%%%%%%%%%%%%%%%%% moveItToNextWord" <<
endl;
2520 EditableCharacterIterator
copy;
2521 while (!it.isEnd() && !(*it).isSpace() && !(*it).isPunct()) {
2522 #if DEBUG_CARETMODE > 2
2523 kdDebug(6200) <<
"reading1 '" << (*it).latin1() <<
"'" <<
endl;
2534 while (!it.isEnd() && ((*it).isSpace() || (*it).isPunct())) {
2535 #if DEBUG_CARETMODE > 2
2536 kdDebug(6200) <<
"reading2 '" << (*it).latin1() <<
"'" <<
endl;
2542 if (it.isEnd()) it =
copy;
2550 static void moveItToPrevWord(EditableCharacterIterator &it)
2552 if (it.isEnd())
return;
2554 #if DEBUG_CARETMODE > 0
2555 kdDebug(6200) <<
"%%%%%%%%%%%%%%%%%%%%% moveItToPrevWord" <<
endl;
2557 EditableCharacterIterator
copy;
2563 #if DEBUG_CARETMODE > 2
2564 if (!it.isEnd())
kdDebug(6200) <<
"reading1 '" << (*it).latin1() <<
"'" <<
endl;
2566 }
while (!it.isEnd() && ((*it).isSpace() || (*it).isPunct()));
2576 #if DEBUG_CARETMODE > 0
2577 if (!it.isEnd())
kdDebug(6200) <<
"reading2 '" << (*it).latin1() <<
"' (" << (int)(*it).latin1() <<
") box " << it.caretBox() <<
endl;
2579 }
while (!it.isEnd() && !(*it).isSpace() && !(*it).isPunct());
2582 #if DEBUG_CARETMODE > 1
2583 if (!it.isEnd())
kdDebug(6200) <<
"effective '" << (*it).latin1() <<
"' (" << (int)(*it).latin1() <<
") box " << it.caretBox() <<
endl;
2594 static void moveIteratorByPage(LinearDocument &ld,
2595 ErgonomicEditableLineIterator &it,
int mindist,
bool next)
2599 if (it == ld.end() || it == ld.preBegin())
return;
2601 ErgonomicEditableLineIterator
copy = it;
2602 #if DEBUG_CARETMODE > 0
2606 CaretBoxLine *cbl = *
copy;
2607 int absx = 0, absy = 0;
2609 RenderBlock *lastcb = cbl->containingBlock();
2610 Q_ASSERT(lastcb->isRenderBlock());
2611 lastcb->absolutePosition(absx, absy,
false);
2613 int lastfby = cbl->begin().data()->yPos();
2618 if (copy == ld.end() || copy == ld.preBegin())
break;
2621 RenderBlock *cb = cbl->containingBlock();
2626 int fby = cbl->begin().data()->yPos();
2629 diff = absy + lastfby + lastheight;
2630 cb->absolutePosition(absx, absy,
false);
2631 diff = absy - diff + fby;
2635 cb->absolutePosition(absx, absy,
false);
2636 diff -= absy + fby + lastheight;
2637 lastfby = fby - lastheight;
2639 #if DEBUG_CARETMODE > 2
2643 diff = kAbs(fby - lastfby);
2645 #if DEBUG_CARETMODE > 2
2646 kdDebug(6200) <<
"cbl->begin().data()->yPos(): " << fby <<
" diff " << diff <<
endl;
2651 lastheight = kAbs(fby - lastfby);
2655 #if DEBUG_CARETMODE > 0
2662 }
while (mindist - lastheight > 0 && --rescue);
This class is tdehtml's main class.
bool isCaretMode() const
Returns whether caret mode is on/off.
bool isEditable() const
Returns true if the document is editable, false otherwise.
kndbgstream & endl(kndbgstream &s)
kdbgstream kdWarning(int area=0)
kdbgstream kdError(int area=0)
kdbgstream kdDebug(int area=0)
const TDEShortcut & copy()
const TDEShortcut & next()
const TDEShortcut & end()