📄 khtml_caret.cpp
字号:
InlineFlowBox *flowBox = cbl->baseFlowBox(); if (flowBox) { flowBox = static_cast<InlineFlowBox *>(toBegin ? flowBox->prevLineBox() : flowBox->nextLineBox()); if (flowBox) { bool seekOutside = false, seekOutsideEnd = false; // silence gcc uninit warning CaretBoxIterator it; cbl = CaretBoxLine::constructCaretBoxLine(&lines->cblDeleter, flowBox, flowBox->firstChild(), seekOutside, seekOutsideEnd, it); }/*end if*/ }/*end if*/ // if there are no more lines in this block, move towards block to come if (!flowBox) { if (toBegin) prevBlock(); else nextBlock(); }#if DEBUG_CARETMODE > 3 if (cbl) kdDebug(6200) << cbl->information() << endl;#endif}// == class EditableCaretBoxIterator implementationvoid EditableCaretBoxIterator::advance(bool toBegin){#if DEBUG_CARETMODE > 3 kdDebug(6200) << "---------------" << k_funcinfo << "toBegin " << toBegin << endl;#endif const CaretBoxIterator preBegin = cbl->preBegin(); const CaretBoxIterator end = cbl->end(); CaretBoxIterator lastbox = *this, curbox; bool islastuseable = true; // silence gcc bool iscuruseable; // Assume adjacency of caret boxes. Will be falsified later if applicable. adjacent = true;#if DEBUG_CARETMODE > 4// kdDebug(6200) << "ebit::advance: before: " << (**this)->object() << "@" << (**this)->object()->renderName() << ".node " << (**this)->object()->element() << "[" << ((**this)->object()->element() ? (**this)->object()->element()->nodeName().string() : QString::null) << "] inline " << (**this)->isInline() << " outside " << (**this)->isOutside() << " outsideEnd " << (**this)->isOutsideEnd() << endl;#endif if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++(); bool curAtEnd = *this == preBegin || *this == end; curbox = *this; bool atEnd = true; if (!curAtEnd) { iscuruseable = isEditable(curbox, toBegin); if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++(); atEnd = *this == preBegin || *this == end; } while (!curAtEnd) { bool haslast = lastbox != end && lastbox != preBegin; bool hascoming = !atEnd; bool iscominguseable = true; // silence gcc if (!atEnd) iscominguseable = isEditable(*this, toBegin); if (iscuruseable) {#if DEBUG_CARETMODE > 3 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;#endif CaretBox *box = *curbox; if (box->isOutside()) { // if this caret box represents no inline box, it is an outside box // which has to be considered unconditionally if (!box->isInline()) break; if (advpol == VisibleFlows) break; // IndicatedFlows and LeafsOnly are treated equally in caret box lines InlineBox *ibox = box->inlineBox(); // get previous inline box InlineBox *prev = box->isOutsideEnd() ? ibox : ibox->prevOnLine(); // get next inline box InlineBox *next = box->isOutsideEnd() ? ibox->nextOnLine() : ibox; const bool isprevindicated = !prev || isIndicatedInlineBox(prev); const bool isnextindicated = !next || isIndicatedInlineBox(next); const bool last = haslast && !islastuseable; const bool coming = hascoming && !iscominguseable; const bool left = !prev || prev->isInlineFlowBox() && isprevindicated || (toBegin && coming || !toBegin && last); const bool right = !next || next->isInlineFlowBox() && isnextindicated || (!toBegin && coming || toBegin && last); const bool text2indicated = toBegin && next && next->isInlineTextBox() && isprevindicated || !toBegin && prev && prev->isInlineTextBox() && isnextindicated; const bool indicated2text = !toBegin && next && next->isInlineTextBox() && prev && isprevindicated // ### this code is so broken. /*|| toBegin && prev && prev->isInlineTextBox() && isnextindicated*/;#if DEBUG_CARETMODE > 5 kdDebug(6200) << "prev " << prev << " haslast " << haslast << " islastuseable " << islastuseable << " left " << left << " next " << next << " hascoming " << hascoming << " iscominguseable " << iscominguseable << " right " << right << " text2indicated " << text2indicated << " indicated2text " << indicated2text << endl;#endif if (left && right && !text2indicated || indicated2text) { adjacent = false;#if DEBUG_CARETMODE > 4 kdDebug(6200) << "left && right && !text2indicated || indicated2text" << endl;#endif break; } } else { // inside boxes are *always* valid#if DEBUG_CARETMODE > 4if (box->isInline()) { InlineBox *ibox = box->inlineBox(); kdDebug(6200) << "inside " << (!ibox->isInlineFlowBox() || static_cast<InlineFlowBox *>(ibox)->firstChild() ? "non-empty" : "empty") << (isIndicatedInlineBox(ibox) ? " indicated" : "") << " adjacent=" << adjacent << endl; }#if 0 RenderStyle *s = ibox->object()->style(); kdDebug(6200) << "bordls " << s->borderLeftStyle() << " bordl " << (s->borderLeftStyle() != BNONE) << " bordr " << (s->borderRightStyle() != BNONE) << " bordt " << (s->borderTopStyle() != BNONE) << " bordb " << (s->borderBottomStyle() != BNONE) << " padl " << s->paddingLeft().value() << " padr " << s->paddingRight().value() << " padt " << s->paddingTop().value() << " padb " << s->paddingBottom().value() // ### Can inline elements have top/bottom margins? Couldn't find // it in the CSS 2 spec, but Mozilla ignores them, so we do, too. << " marl " << s->marginLeft().value() << " marr " << s->marginRight().value() << endl;#endif#endif break; }/*end if*/ } else { if (!(*curbox)->isOutside()) { // cannot be adjacent anymore adjacent = false; } }/*end if*/ lastbox = curbox; islastuseable = iscuruseable; curbox = *this; iscuruseable = iscominguseable; curAtEnd = atEnd; if (!atEnd) { if (toBegin) CaretBoxIterator::operator --(); else CaretBoxIterator::operator ++(); atEnd = *this == preBegin || *this == end; }/*end if*/ }/*wend*/ *static_cast<CaretBoxIterator *>(this) = curbox;#if DEBUG_CARETMODE > 4// kdDebug(6200) << "still valid? " << (*this != preBegin && *this != end) << endl;#endif#if DEBUG_CARETMODE > 3 kdDebug(6200) << "---------------" << k_funcinfo << "end " << endl;#endif}bool EditableCaretBoxIterator::isEditable(const CaretBoxIterator &boxit, bool fromEnd){ Q_ASSERT(boxit != cbl->end() && boxit != cbl->preBegin()); CaretBox *b = *boxit; RenderObject *r = b->object();#if DEBUG_CARETMODE > 0// if (b->isInlineFlowBox()) kdDebug(6200) << "b is inline flow box" << (outside ? " (outside)" : "") << endl; 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;#endif // Must check caret mode or design mode *after* r->element(), otherwise // lines without a backing DOM node get regarded, leading to a crash. // ### check should actually be in InlineBoxIterator NodeImpl *node = r->element(); ObjectTraversalState trav; mapRenderPosToTraversalState(b->isOutside(), b->isOutsideEnd(), fromEnd, trav); if (isUnsuitable(r, trav) || !node) { return false; } // generally exclude replaced elements with no children from navigation if (!b->isOutside() && r->isRenderReplaced() && !r->firstChild()) return false; RenderObject *eff_r = r; bool globallyNavigable = m_part->isCaretMode() || m_part->isEditable(); // calculate the parent element's editability if this inline box is outside. if (b->isOutside() && !globallyNavigable) { NodeImpl *par = node->parent(); // I wonder whether par can be 0. It shouldn't be possible if the // algorithm contained no bugs. Q_ASSERT(par); if (par) node = par; eff_r = node->renderer(); Q_ASSERT(eff_r); // this is a hard requirement } bool result = globallyNavigable || eff_r->style()->userInput() == UI_ENABLED;#if DEBUG_CARETMODE > 0 kdDebug(6200) << result << endl;#endif return result;}// == class EditableLineIterator implementationvoid EditableLineIterator::advance(bool toBegin){ CaretAdvancePolicy advpol = lines->advancePolicy(); LineIterator lasteditable, lastindicated; bool haslasteditable = false; bool haslastindicated = false; bool uselasteditable = false; LineIterator::advance(toBegin); while (cbl) { if (isEditable(*this)) {#if DEBUG_CARETMODE > 3 kdDebug(6200) << "advance: " << cbl->enclosingObject() << "@" << cbl->enclosingObject()->renderName() << ".node " << cbl->enclosingObject()->element() << "[" << (cbl->enclosingObject()->element() ? cbl->enclosingObject()->element()->nodeName().string() : QString::null) << "]" << endl;#endif bool hasindicated = isIndicatedFlow(cbl->enclosingObject()); if (hasindicated) { haslastindicated = true; lastindicated = *this; } switch (advpol) { case IndicatedFlows: if (hasindicated) goto wend; // fall through case LeafsOnly: if (cbl->isOutside()) break; // fall through case VisibleFlows: goto wend; }/*end switch*/ // remember rejected editable element lasteditable = *this; haslasteditable = true;#if DEBUG_CARETMODE > 4 kdDebug(6200) << "remembered lasteditable " << *lasteditable << endl;#endif } else { // If this element isn't editable, but the last one was, and it was only // rejected because it didn't match the caret advance policy, force it. // Otherwise certain combinations of editable and uneditable elements // could never be reached with some policies. if (haslasteditable) { uselasteditable = true; break; } } LineIterator::advance(toBegin); }/*wend*/wend: if (uselasteditable) *this = haslastindicated ? lastindicated : lasteditable; if (!cbl && haslastindicated) *this = lastindicated;}// == class EditableCharacterIterator implementationvoid EditableCharacterIterator::initFirstChar(){ CaretBox *box = *ebit; InlineBox *b = box->inlineBox(); if (_offset == box->maxOffset()) peekNext(); else if (b && !box->isOutside() && b->isInlineTextBox()) _char = static_cast<RenderText *>(b->object())->str->s[_offset].unicode(); else _char = -1;}/** returns true when the given caret box is empty, i. e. should not * take place in caret movement. */static inline bool isCaretBoxEmpty(CaretBox *box) { if (!box->isInline()) return false; InlineBox *ibox = box->inlineBox(); return ibox->isInlineFlowBox() && !static_cast<InlineFlowBox *>(ibox)->firstChild() && !isIndicatedInlineBox(ibox);}EditableCharacterIterator &EditableCharacterIterator::operator ++(){ _offset++; CaretBox *box = *ebit; InlineBox *b = box->inlineBox(); long maxofs = box->maxOffset();#if DEBUG_CARETMODE > 0 kdDebug(6200) << "box->maxOffset() " << box->maxOffset() << " box->minOffset() " << box->minOffset() << endl;#endif if (_offset == maxofs) {#if DEBUG_CARETMODE > 2kdDebug(6200) << "_offset == maxofs: " << _offset << " == " << maxofs << endl;#endif peekNext(); } else if (_offset > maxofs) {#if DEBUG_CARETMODE > 2kdDebug(6200) << "_offset > maxofs: " << _offset << " > " << maxofs /*<< " _peekNext: " << _peekNext*/ << endl;#endif if (/*!_peekNext*/true) { ++ebit; if (ebit == (*_it)->end()) { // end of line reached, go to next line ++_it;#if DEBUG_CARETMODE > 3kdDebug(6200) << "++_it" << endl;#endif if (_it != _it.lines->end()) { ebit = _it; box = *ebit; b = box->inlineBox();#if DEBUG_CARETMODE > 3kdDebug(6200) << "box " << box << " b " << b << " isText " << box->isInlineTextBox() << endl;#endif#if DEBUG_CARETMODE > 3 RenderObject *_r = box->object();kdDebug(6200) << "_r " << _r << ":" << _r->element()->nodeName().string() << endl;#endif _offset = box->minOffset();#if DEBUG_CARETMODE > 3kdDebug(6200) << "_offset " << _offset << endl;#endif } else { b = 0; _end = true; }/*end if*/ goto readchar; }/*end if*/ }/*end if*/ bool adjacent = ebit.isAdjacent();#if 0 // Jump over element if this one is not a text node. if (adjacent && !(*ebit)->isInlineTextBox()) { EditableCaretBoxIterator copy = ebit; ++ebit; if (ebit != (*_it)->end() && (*ebit)->isInlineTextBox() /*&& (!(*ebit)->isInlineFlowBox() || static_cast<InlineFlowBox *>(*ebit)->)*/) adjacent = false; else ebit = copy; }/*end if*/#endif // Jump over empty elements. if (adjacent && !(*ebit)->isInlineTextBox()) { bool noemptybox = true; while (isCaretBoxEmpty(*ebit)) { noemptybox = false; EditableCaretBoxIterator copy = ebit; ++ebit; if (ebit == (*_it)->end()) { ebit = copy; break; } } if (noemptybox) adjacent = false; }/*end if*/// _r = (*ebit)->object(); /*if (!_it.outside) */_offset = (*ebit)->minOffset() + adjacent; //_peekNext = 0; box = *ebit; b = box->inlineBox(); goto readchar; } else {readchar: // get character if (b && !box->isOutside() && b->isInlineTextBox() && _offset < b->maxOffset()) _char =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -