📄 khtml_caret.cpp
字号:
while (n) { r = n; n = n->firstChild(); } return const_cast<NodeImpl *>(r); }/*end if*/ n = r->previousSibling(); if (n) { r = n; while (n) { r = n; n = n->firstChild(); } return const_cast<NodeImpl *>(r); }/*end if*/ n = r->parentNode(); if (n == baseElem) n = 0; while (n) { r = n; n = r->previousSibling(); if (n) { r = n; n = r->lastChild(); while (n) { r = n; n = n->lastChild(); } return const_cast<NodeImpl *>(r); }/*end if*/ n = r->parentNode(); if (n == baseElem) n = 0; }/*wend*/ return 0;}#endif/** Maps a DOM Range position to the corresponding caret position. * * The offset boundary is not checked for validity. * @param node DOM node * @param offset zero-based offset within node * @param r returns render object (may be 0 if DOM node has no render object) * @param r_ofs returns the appropriate offset for the found render object r * @param outside returns true when offset is applied to the outside of * \c r, or false for the inside. * @param outsideEnd return true when the caret position is at the outside end. */void /*KDE_NO_EXPORT*/ mapDOMPosToRenderPos(NodeImpl *node, long offset, RenderObject *&r, long &r_ofs, bool &outside, bool &outsideEnd){ if (node->nodeType() == Node::TEXT_NODE) { outside = false; outsideEnd = false; r = node->renderer(); r_ofs = offset; } else if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE) { // Though offset points between two children, attach it to the visually // most suitable one (and only there, because the mapping must stay bijective) if (node->firstChild()) { outside = true; NodeImpl *child = offset <= 0 ? node->firstChild() // childNode is expensive : node->childNode((unsigned long)offset); // index was child count or out of bounds bool atEnd = !child;#if DEBUG_CARETMODE > 5 kdDebug(6200) << "mapDTR: child " << child << "@" << (child ? child->nodeName().string() : QString::null) << " atEnd " << atEnd << endl;#endif if (atEnd) child = node->lastChild(); r = child->renderer(); r_ofs = 0; outsideEnd = atEnd; // Outside text nodes most likely stem from a continuation. Seek // the enclosing continued render object and use this one instead. if (r && child->nodeType() == Node::TEXT_NODE) { r = r->parent(); RenderObject *o = node->renderer(); while (o->continuation() && o->continuation() != r) o = o->continuation(); if (!r || o->continuation() != r) { r = child->renderer(); } }/*end if*/ // BRs cause troubles. Returns the previous render object instead, // giving it the attributes outside, outside end. if (r && r->isBR()) { r = r->objectAbove(); outsideEnd = true; }/*end if*/ } else { // Element has no children, treat offset to be inside the node. outside = false; outsideEnd = false; r = node->renderer(); r_ofs = 0; // only offset 0 possible } } else { r = 0; kdWarning() << k_funcinfo << "Mapping from nodes of type " << node->nodeType() << " not supported!" << endl; }}/** Maps a caret position to the corresponding DOM Range position. * * @param r render object * @param r_ofs offset within render object * @param outside true when offset is interpreted to be on the outside of * \c r, or false if on the inside. * @param outsideEnd true when the caret position is at the outside end. * @param node returns DOM node * @param offset returns zero-based offset within node */void /*KDE_NO_EXPORT*/ mapRenderPosToDOMPos(RenderObject *r, long r_ofs, bool outside, bool outsideEnd, NodeImpl *&node, long &offset){ node = r->element(); Q_ASSERT(node);#if DEBUG_CARETMODE > 5 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;#endif if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::TEXT_NODE) { if (outside) { NodeImpl *parent = node->parent(); // If this is part of a continuation, use the actual node as the parent, // and the first render child as the node. if (r != node->renderer()) { RenderObject *o = node->renderer(); while (o->continuation() && o->continuation() != r) o = o->continuation(); if (o->continuation() == r) { parent = node; // ### What if the first render child does not map to a child of // the continued node? node = r->firstChild() ? r->firstChild()->element() : node; } }/*end if*/ if (!parent) goto inside; offset = (long)node->nodeIndex() + outsideEnd; node = parent;#if DEBUG_CARETMODE > 5 kdDebug(6200) << node << "@" << (node ? node->nodeName().string() : QString::null) << " offset " << offset << endl;#endif } else { // !outsideinside: offset = r_ofs; } } else { offset = 0; kdWarning() << k_funcinfo << "Mapping to nodes of type " << node->nodeType() << " not supported!" << endl; }}/** Make sure the given node is a leaf node. */static inline void ensureLeafNode(NodeImpl *&node, NodeImpl *base){ if (node && node->hasChildNodes()) node = nextLeafNode(node, base);}/** Converts a caret position to its respective object traversal state. * @param outside whether the caret is outside the object * @param atEnd whether the caret position is at the end * @param toBegin \c true when advancing towards the beginning * @param trav returns the corresponding traversal state */static inline void mapRenderPosToTraversalState(bool outside, bool atEnd, bool toBegin, ObjectTraversalState &trav){ if (!outside) atEnd = !toBegin; if (!atEnd ^ toBegin) trav = outside ? OutsideDescending : InsideDescending; else trav = outside ? OutsideAscending : InsideAscending;}/** Converts a traversal state to its respective caret position * @param trav object traversal state * @param toBegin \c true when advancing towards the beginning * @param outside whether the caret is outside the object * @param atEnd whether the caret position is at the end */static inline void mapTraversalStateToRenderPos(ObjectTraversalState trav, bool toBegin, bool &outside, bool &atEnd){ outside = false; switch (trav) { case OutsideDescending: outside = true; // fall through case InsideDescending: atEnd = toBegin; break; case OutsideAscending: outside = true; // fall through case InsideAscending: atEnd = !toBegin; break; }}/** Finds the next node that has a renderer. * * Note that if the initial @p node has a renderer, this will be returned, * regardless of the caret advance policy. * Otherwise, for the next nodes, only leaf nodes are considered. * @param node node to start with, will be updated accordingly * @param offset offset of caret within \c node * @param base base render object which this method must not advance beyond * (0 means document) * @param r_ofs return the caret offset within the returned renderer * @param outside returns whether offset is to be interpreted to the outside * (true) or the inside (false) of the render object. * @param outsideEnd returns whether the end of the outside position is meant * @return renderer or 0 if no following node has a renderer. */static RenderObject* findRenderer(NodeImpl *&node, long offset, RenderObject *base, long &r_ofs, bool &outside, bool &outsideEnd){ if (!node) return 0; RenderObject *r; mapDOMPosToRenderPos(node, offset, r, r_ofs, outside, outsideEnd);#if DEBUG_CARETMODE > 2 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;#endif if (r) return r; NodeImpl *baseElem = base ? base->element() : 0; while (!r) { node = nextLeafNode(node, baseElem); if (!node) break; r = node->renderer(); if (r) r_ofs = offset; }#if DEBUG_CARETMODE > 3 kdDebug(6200) << "1r " << r << endl;#endif ObjectTraversalState trav; int state; // not used mapRenderPosToTraversalState(outside, outsideEnd, false, trav); if (r && isUnsuitable(r, trav)) { r = advanceSuitableObject(r, trav, false, base, state); mapTraversalStateToRenderPos(trav, false, outside, outsideEnd); if (r) r_ofs = r->minOffset(); }#if DEBUG_CARETMODE > 3 kdDebug(6200) << "2r " << r << endl;#endif return r;}/** returns a suitable base element * @param caretNode current node containing caret. */static ElementImpl *determineBaseElement(NodeImpl *caretNode){ // ### for now, only body is delivered for html documents, // and 0 for xml documents. DocumentImpl *doc = caretNode->getDocument(); if (!doc) return 0; // should not happen, but who knows. if (doc->isHTMLDocument()) return static_cast<HTMLDocumentImpl *>(doc)->body(); return 0;}// == class CaretBox implementation#if DEBUG_CARETMODE > 0void CaretBox::dump(QTextStream &ts, const QString &ind) const{ ts << ind << "b@" << _box; if (_box) { ts << "<" << _box->object() << ":" << _box->object()->renderName() << ">"; }/*end if*/ ts << " " << _x << "+" << _y << "+" << _w << "*" << _h; ts << " cb@" << cb; if (cb) ts << ":" << cb->renderName(); ts << " " << (_outside ? (outside_end ? "oe" : "o-") : "i-");// ts << endl;}#endif// == class CaretBoxLine implementation#if DEBUG_CARETMODE > 0# define DEBUG_ACIB 1#else# define DEBUG_ACIB DEBUG_CARETMODE#endifvoid CaretBoxLine::addConvertedInlineBox(InlineBox *box, SeekBoxParams &sbp) /*KDE_NO_EXPORT*/{ // Generate only one outside caret box between two elements. If // coalesceOutsideBoxes is true, generating left outside boxes is inhibited. bool coalesceOutsideBoxes = false; CaretBoxIterator lastCoalescedBox; for (; box; box = box->nextOnLine()) {#if DEBUG_ACIBkdDebug(6200) << "box " << box << endl;kdDebug(6200) << "box->object " << box->object() << endl;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;#endif // ### Why the hell can object() ever be 0?! if (!box->object()) continue; RenderStyle *s = box->object()->style(box->m_firstLine); // parent style for outside caret boxes RenderStyle *ps = box->parent() && box->parent()->object() ? box->parent()->object()->style(box->parent()->m_firstLine) : s; if (box->isInlineFlowBox()) {#if DEBUG_ACIBkdDebug(6200) << "isinlineflowbox " << box << endl;#endif InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(box); bool rtl = ps->direction() == RTL; const QFontMetrics &pfm = ps->fontMetrics(); if (flowBox->includeLeftEdge()) { // If this box is to be coalesced with the outside end box of its // predecessor, then check if it is the searched box. If it is, we // substitute the outside end box. if (coalesceOutsideBoxes) { if (sbp.equalsBox(flowBox, true, false)) { sbp.it = lastCoalescedBox; Q_ASSERT(!sbp.found); sbp.found = true; } } else { addCreatedFlowBoxEdge(flowBox, pfm, true, rtl); sbp.check(preEnd()); } }/*end if*/ if (flowBox->firstChild()) {#if DEBUG_ACIBkdDebug(6200) << "this " << this << " flowBox " << flowBox << " firstChild " << flowBox->firstChild() << endl;kdDebug(6200) << "== recursive invocation" << endl;#endif addConvertedInlineBox(flowBox->firstChild(), sbp);#if DEBUG_ACIBkdDebug(6200) << "== recursive invocation end" << endl;#endif} else { addCreatedFlowBoxInside(flowBox, s->fontMetrics()); sbp.check(preEnd()); } if (flowBox->includeRightEdge()) { addCreatedFlowBoxEdge(flowBox, pfm, false, rtl); lastCoalescedBox = preEnd(); sbp.check(lastCoalescedBox); coalesceOutsideBoxes = true; } } else if (box->isInlineTextBox()) {#if DEBUG_ACIBkdDebug(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;#endif caret_boxes.append(new CaretBox(box, false, false)); sbp.check(preEnd()); // coalescing has been interrupted coalesceOutsideBoxes = false; } else {#if DEBUG_ACIBkdDebug(6200) << "some replaced or what " << box << endl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -