📄 khtml_caret.cpp
字号:
*/static inline bool isDescendant(RenderObject *r, RenderObject *cb){ while (r && r != cb) r = r->parent(); return r;}/** checks whether the given block contains at least one editable element. * * Warning: This function has linear complexity, and therefore is expensive. * Use it sparingly, and cache the result. * @param part part * @param cb block to be searched * @param table returns the nested table if there is one directly at the beginning * or at the end. * @param fromEnd begin search from end (default: begin from beginning) */static bool containsEditableElement(KHTMLPart *part, RenderBlock *cb, RenderTable *&table, bool fromEnd = false){ RenderObject *r = cb; if (fromEnd) while (r->lastChild()) r = r->lastChild(); else while (r->firstChild()) r = r->firstChild(); RenderTable *tempTable = 0; table = 0; bool withinCb;// int state; // not used ObjectTraversalState trav = InsideDescending; do { bool modWithinCb = withinCb = isDescendant(r, cb); // treat cb extra, it would not be considered otherwise if (!modWithinCb) { modWithinCb = true; r = cb; } else tempTable = findTableUpTo(r, cb);#if DEBUG_CARETMODE > 1 kdDebug(6201) << "cee: r " << (r ? r->renderName() : QString::null) << "@" << r << " cb " << cb << " withinCb " << withinCb << " modWithinCb " << modWithinCb << " tempTable " << tempTable << endl;#endif if (r && modWithinCb && r->element() && !isUnsuitable(r, trav) && (part->isCaretMode() || part->isEditable() || r->style()->userInput() == UI_ENABLED)) { table = tempTable;#if DEBUG_CARETMODE > 1 kdDebug(6201) << "cee: editable" << endl;#endif return true; }/*end if*/// RenderObject *oldr = r;// while (r && r == oldr)// r = advanceSuitableObject(r, trav, fromEnd, cb->parent(), state); r = fromEnd ? r->objectAbove() : r->objectBelow(); } while (r && withinCb); return false;}/** checks whether the given block contains at least one editable child * element, beginning with but excluding @p start. * * Warning: This function has linear complexity, and therefore is expensive. * Use it sparingly, and cache the result. * @param part part * @param cb block to be searched * @param table returns the nested table if there is one directly before/after * the start object. * @param fromEnd begin search from end (default: begin from beginning) * @param start object after which to begin search. */static bool containsEditableChildElement(KHTMLPart *part, RenderBlock *cb, RenderTable *&table, bool fromEnd, RenderObject *start){ int state = 0; ObjectTraversalState trav = OutsideAscending;// kdDebug(6201) << "start: " << start << endl; RenderObject *r = start; do { r = traverseRenderObjects(r, trav, fromEnd, cb->parent(), state); } while(r && !(state & AdvancedToSibling));// kdDebug(6201) << "r: " << r << endl; //advanceObject(start, trav, fromEnd, cb->parent(), state);// RenderObject *oldr = r;// while (r && r == oldr) if (!r) return false; if (fromEnd) while (r->firstChild()) r = r->firstChild(); else while (r->lastChild()) r = r->lastChild();// kdDebug(6201) << "child r: " << r << endl; if (!r) return false; RenderTable *tempTable = 0; table = 0; bool withinCb = false; do { bool modWithinCb = withinCb = isDescendant(r, cb); // treat cb extra, it would not be considered otherwise if (!modWithinCb) { modWithinCb = true; r = cb; } else tempTable = findTableUpTo(r, cb);#if DEBUG_CARETMODE > 1 kdDebug(6201) << "cece: r " << (r ? r->renderName() : QString::null) << "@" << r << " cb " << cb << " withinCb " << withinCb << " modWithinCb " << modWithinCb << " tempTable " << tempTable << endl;#endif if (r && withinCb && r->element() && !isUnsuitable(r, trav) && (part->isCaretMode() || part->isEditable() || r->style()->userInput() == UI_ENABLED)) { table = tempTable;#if DEBUG_CARETMODE > 1 kdDebug(6201) << "cece: editable" << endl;#endif return true; }/*end if*/ r = fromEnd ? r->objectAbove() : r->objectBelow(); } while (withinCb); return false;}// == class LinearDocument implementationLinearDocument::LinearDocument(KHTMLPart *part, NodeImpl *node, long offset, CaretAdvancePolicy advancePolicy, ElementImpl *baseElem) : node(node), offset(offset), m_part(part), advPol(advancePolicy), base(0){ if (node == 0) return; if (baseElem) { RenderObject *b = baseElem->renderer(); if (b && (b->isRenderBlock() || b->isRenderInline())) base = b; } initPreBeginIterator(); initEndIterator();}LinearDocument::~LinearDocument(){}int LinearDocument::count() const{ // FIXME: not implemented return 1;}LinearDocument::Iterator LinearDocument::current(){ return LineIterator(this, node, offset);}LinearDocument::Iterator LinearDocument::begin(){ NodeImpl *n = base ? base->element() : 0; if (!base) n = node ? node->getDocument() : 0; if (!n) return end(); n = n->firstChild(); if (advPol == LeafsOnly) while (n->firstChild()) n = n->firstChild(); if (!n) return end(); // must be empty document or empty base element return LineIterator(this, n, n->minOffset());}LinearDocument::Iterator LinearDocument::preEnd(){ NodeImpl *n = base ? base->element() : 0; if (!base) n = node ? node->getDocument() : 0; if (!n) return preBegin(); n = n->lastChild(); if (advPol == LeafsOnly) while (n->lastChild()) n = n->lastChild(); if (!n) return preBegin(); // must be empty document or empty base element return LineIterator(this, n, n->maxOffset());}void LinearDocument::initPreBeginIterator(){ _preBegin = LineIterator(this, 0, 0);}void LinearDocument::initEndIterator(){ _end = LineIterator(this, 0, 1);}// == class LineIterator implementationCaretBoxIterator LineIterator::currentBox /*KDE_NO_EXPORT*/;long LineIterator::currentOffset /*KDE_NO_EXPORT*/;LineIterator::LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset) : lines(l){// kdDebug(6200) << "LineIterator: node " << node << " offset " << offset << endl; if (!node) { cbl = 0; return; } cbl = findCaretBoxLine(node, offset, &lines->cblDeleter, l->baseObject(), currentOffset, currentBox); // can happen on partially loaded documents#if DEBUG_CARETMODE > 0 if (!cbl) kdDebug(6200) << "no render object found!" << endl;#endif if (!cbl) return;#if DEBUG_CARETMODE > 1 kdDebug(6200) << "LineIterator: offset " << offset << " outside " << cbl->isOutside() << endl;#endif#if DEBUG_CARETMODE > 3 kdDebug(6200) << cbl->information() << endl;#endif if (currentBox == cbl->end()) {#if DEBUG_CARETMODE > 0 kdDebug(6200) << "LineIterator: findCaretBoxLine failed" << endl;#endif cbl = 0; }/*end if*/}void LineIterator::nextBlock(){ RenderObject *base = lines->baseObject(); bool cb_outside = cbl->isOutside(); bool cb_outside_end = cbl->isOutsideEnd(); { RenderObject *r = cbl->enclosingObject(); ObjectTraversalState trav; int state; // not used mapRenderPosToTraversalState(cb_outside, cb_outside_end, false, trav);#if DEBUG_CARETMODE > 1 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;#endif r = advanceSuitableObject(r, trav, false, base, state); if (!r) { cbl = 0; return; }/*end if*/ mapTraversalStateToRenderPos(trav, false, cb_outside, cb_outside_end);#if DEBUG_CARETMODE > 1 kdDebug(6200) << "nextBlock: after r" << r << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;#endif#if DEBUG_CARETMODE > 0 kdDebug(6200) << "++: r " << r << "[" << (r?r->renderName():QString::null) << "]" << endl;#endif RenderBlock *cb; // If we hit a block or replaced object, use this as its enclosing object bool isrepl = isBlockRenderReplaced(r); if (r->isRenderBlock() || isrepl) { RenderBox *cb = static_cast<RenderBox *>(r); cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb, cb_outside, cb_outside_end, currentBox);#if DEBUG_CARETMODE > 0 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;#endif return; } else { cb = r->containingBlock(); Q_ASSERT(cb->isRenderBlock()); }/*end if*/ InlineFlowBox *flowBox = cb->firstLineBox();#if DEBUG_CARETMODE > 0 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;#endif Q_ASSERT(flowBox); if (!flowBox) { // ### utter emergency (why is this possible at all?) cb_outside = cb_outside_end = true; cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb, cb_outside, cb_outside_end, currentBox); return; } bool seekOutside = false, seekOutsideEnd = false; // silence gcc uninit warning CaretBoxIterator it; cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it); }}void LineIterator::prevBlock(){ RenderObject *base = lines->baseObject(); bool cb_outside = cbl->isOutside(); bool cb_outside_end = cbl->isOutsideEnd(); { RenderObject *r = cbl->enclosingObject(); if (r->isAnonymous() && !cb_outside) cb_outside = true, cb_outside_end = false; ObjectTraversalState trav; int state; // not used mapRenderPosToTraversalState(cb_outside, cb_outside_end, true, trav);#if DEBUG_CARETMODE > 1 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;#endif r = advanceSuitableObject(r, trav, true, base, state); if (!r) { cbl = 0; return; }/*end if*/ mapTraversalStateToRenderPos(trav, true, cb_outside, cb_outside_end);#if DEBUG_CARETMODE > 1 kdDebug(6200) << "prevBlock: after r" << r << " trav " << trav << " cb_outside " << cb_outside << " cb_outside_end " << cb_outside_end << endl;#endif#if DEBUG_CARETMODE > 0 kdDebug(6200) << "--: r " << r << "[" << (r?r->renderName():QString::null) << "]" << endl;#endif RenderBlock *cb; // If we hit a block, use this as its enclosing object bool isrepl = isBlockRenderReplaced(r);// kdDebug(6200) << "isrepl " << isrepl << " isblock " << r->isRenderBlock() << endl; if (r->isRenderBlock() || isrepl) { RenderBox *cb = static_cast<RenderBox *>(r); cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb, cb_outside, cb_outside_end, currentBox);#if DEBUG_CARETMODE > 0 kdDebug(6200) << "r->isFlow is cb. continuation @" << cb->continuation() << endl;#endif return; } else { cb = r->containingBlock(); Q_ASSERT(cb->isRenderBlock()); }/*end if*/ InlineFlowBox *flowBox = cb->lastLineBox();#if DEBUG_CARETMODE > 0 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;#endif Q_ASSERT(flowBox); if (!flowBox) { // ### utter emergency (why is this possible at all?) cb_outside = true; cb_outside_end = false; cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, cb, cb_outside, cb_outside_end, currentBox); return; } bool seekOutside = false, seekOutsideEnd = false; // silence gcc uninit warning CaretBoxIterator it; cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it); }}void LineIterator::advance(bool toBegin){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -