📄 render_text.cpp
字号:
if (ax > _x) end = offset; else if (ax < _x) start = offset; else break; } return m_start + offset;}int InlineTextBox::widthFromStart(int pos) const{ // gasp! sometimes pos is i < 0 which crashes Font::width pos = kMax(pos, 0); const RenderText *t = renderText(); Q_ASSERT(t->isText()); const Font *f = t->htmlFont(m_firstLine); const QFontMetrics &fm = t->fontMetrics(m_firstLine); int numSpaces = 0; // consider spacing for justified text bool justified = t->style()->textAlign() == JUSTIFY; //kdDebug(6000) << "InlineTextBox::width(int)" << endl; if (justified && m_toAdd > 0) do { //kdDebug(6000) << "justify" << endl;// QConstString cstr = QConstString(t->str->s + m_start, m_len); for( int i = 0; i < m_len; i++ ) if ( t->str->s[m_start+i].category() == QChar::Separator_Space ) numSpaces++; if (numSpaces == 0) break; int toAdd = m_toAdd; int w = 0; // accumulated width int start = 0; // start of non-space sequence int current = 0; // current position while (current < pos) { // add spacing while (current < pos && t->str->s[m_start + current].category() == QChar::Separator_Space) { w += f->getWordSpacing(); w += f->getLetterSpacing(); w += justifyWidth(numSpaces, toAdd); w += fm.width(' '); // ### valid assumption? (LS) current++; start++; }/*wend*/ if (current >= pos) break; // seek next space while (current < pos && t->str->s[m_start + current].category() != QChar::Separator_Space) current++; // check run without spaces if ( current > start ) { w += f->width(t->str->s + m_start, m_len, start, current - start); start = current; } } return w; } while(false);/*end if*/ //kdDebug(6000) << "default" << endl; // else use existing width function return f->width(t->str->s + m_start, m_len, 0, pos);}long InlineTextBox::minOffset() const{ return m_start;}long InlineTextBox::maxOffset() const{ return m_start + m_len;}// -----------------------------------------------------------------------------InlineTextBoxArray::InlineTextBoxArray(){ setAutoDelete(false);}int InlineTextBoxArray::compareItems( Item d1, Item d2 ){ assert(d1); assert(d2); return static_cast<InlineTextBox*>(d1)->m_y - static_cast<InlineTextBox*>(d2)->m_y;}// remove this once QVector::bsearch is fixedint InlineTextBoxArray::findFirstMatching(Item d) const{ int len = count(); if ( !len ) return -1; if ( !d ) return -1; int n1 = 0; int n2 = len - 1; int mid = 0; bool found = false; while ( n1 <= n2 ) { int res; mid = (n1 + n2)/2; if ( (*this)[mid] == 0 ) // null item greater res = -1; else res = ((QGVector*)this)->compareItems( d, (*this)[mid] ); if ( res < 0 ) n2 = mid - 1; else if ( res > 0 ) n1 = mid + 1; else { // found it found = true; break; } } /* if ( !found ) return -1; */ // search to first one equal or bigger while ( found && (mid > 0) && !((QGVector*)this)->compareItems(d, (*this)[mid-1]) ) mid--; return mid;}// -------------------------------------------------------------------------------------RenderText::RenderText(DOM::NodeImpl* node, DOMStringImpl *_str) : RenderObject(node){ // init RenderObject attributes setRenderText(); // our object inherits from RenderText m_minWidth = -1; m_maxWidth = -1; str = _str; if(str) str->ref(); KHTMLAssert(!str || !str->l || str->s); m_selectionState = SelectionNone; m_hasReturn = true;#ifdef DEBUG_LAYOUT QConstString cstr(str->s, str->l); kdDebug( 6040 ) << "RenderText ctr( "<< cstr.string().length() << " ) '" << cstr.string() << "'" << endl;#endif}void RenderText::setStyle(RenderStyle *_style){ if ( style() != _style ) { bool changedText = ((!style() && ( _style->textTransform() != TTNONE || !_style->preserveLF() || !_style->preserveWS() )) || (style() && (style()->textTransform() != _style->textTransform() || style()->whiteSpace() != _style->whiteSpace()))); RenderObject::setStyle( _style ); m_lineHeight = RenderObject::lineHeight(false); if (changedText) { DOM::DOMStringImpl* textToTransform = originalString(); if (textToTransform) setText(textToTransform, true); } }}RenderText::~RenderText(){ KHTMLAssert(m_lines.count() == 0); if(str) str->deref();}void RenderText::deleteInlineBoxes(RenderArena* arena){ // this is a slight variant of QArray::clear(). // We don't delete the array itself here because its // likely to be used in the same size later again, saves // us resize() calls unsigned int len = m_lines.size(); if (len) { if (!arena) arena = renderArena(); for(unsigned int i=0; i < len; i++) { InlineTextBox* s = m_lines.at(i); if (s) s->detach(arena); m_lines.remove(i); } } KHTMLAssert(m_lines.count() == 0);}bool RenderText::isTextFragment() const{ return false;}DOM::DOMStringImpl* RenderText::originalString() const{ return element() ? element()->string() : 0;}InlineTextBox * RenderText::findInlineTextBox( int offset, int &pos, bool checkFirstLetter ){ // The text boxes point to parts of the rendertext's str string // (they don't include '\n') // Find the text box that includes the character at @p offset // and return pos, which is the position of the char in the run. // FIXME: make this use binary search? Dirk says it won't work :-( (LS)#if 0 if (checkFirstLetter && forcedMinOffset()) {// kdDebug(6040) << "checkFirstLetter: forcedMinOffset: " << forcedMinOffset() << endl; RenderFlow *firstLetter = static_cast<RenderFlow *>(previousSibling()); if (firstLetter && firstLetter->isFlow() && firstLetter->isFirstLetter()) { RenderText *letterText = static_cast<RenderText *>(firstLetter->firstChild()); //kdDebug(6040) << "lettertext: " << letterText << " minOfs: " << letterText->minOffset() << " maxOfs: " << letterText->maxOffset() << endl; if (offset >= letterText->minOffset() && offset <= letterText->maxOffset()) { InlineTextBox *result = letterText->findInlineTextBox(offset, pos, false); //kdDebug(6040) << "result: " << result << endl; if (result) return result; } } }#endif if ( m_lines.isEmpty() ) return 0L; // The text boxes don't resemble a contiguous coverage of the text, there // may be holes. Therefore, we snap to the nearest previous text box if // the given offset happens to point to such a hole. InlineTextBox* s = m_lines[0]; uint count = m_lines.count(); uint si = 0; uint nearest_idx = 0; // index of nearest text box int nearest = INT_MAX; // nearest distance//kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; while(!(offset >= s->m_start && offset <= s->m_start + s->m_len) && ++si < count) { int dist = offset - (s->m_start + s->m_len);//kdDebug(6040) << "dist " << dist << " nearest " << nearest << endl; if (dist >= 0 && dist <= nearest) { nearest = dist; nearest_idx = si - 1; }/*end if*/ s = m_lines[si];//kdDebug(6040) << "s[" << si << "] m_start " << s->m_start << " m_end " << (s->m_start + s->m_len) << endl; }//kdDebug(6040) << "nearest_idx " << nearest_idx << " count " << count << endl; if (si >= count) s = m_lines[nearest_idx]; // we are now in the correct text box pos = kMin(offset - s->m_start, int( s->m_len )); //kdDebug(6040) << "offset=" << offset << " s->m_start=" << s->m_start << endl; return s;}bool RenderText::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, HitTestAction /*hitTestAction*/, bool inBox){ assert(parent()); bool inside = false; if (style()->visibility() != HIDDEN) { InlineTextBox *s = m_lines.count() ? m_lines[0] : 0; int si = 0; while(s) { if((_y >=_ty + s->m_y) && (_y < _ty + s->m_y + s->m_height) && (_x >= _tx + s->m_x) && (_x <_tx + s->m_x + s->m_width) ) { inside = true; break; } s = si < (int) m_lines.count()-1 ? m_lines[++si] : 0; } } // #### ported over from Safari. Can this happen at all? (lars) if (inside && element()) { if (info.innerNode() && info.innerNode()->renderer() && !info.innerNode()->renderer()->isInline()) { // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node. info.setInnerNode(element()); // Clear everything else. info.setInnerNonSharedNode(0); info.setURLElement(0); } if (!info.innerNode()) info.setInnerNode(element()); if(!info.innerNonSharedNode()) info.setInnerNonSharedNode(element()); } return inside;}FindSelectionResult RenderText::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int &offset, SelPointState &){// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y// << " _tx=" << _tx << " _ty=" << _ty << endl;//kdDebug(6040) << renderName() << "::checkSelectionPoint x=" << xPos() << " y=" << yPos() << " w=" << width() << " h=" << height() << " m_lines.count=" << m_lines.count() << endl; NodeImpl *lastNode = 0; int lastOffset = 0; FindSelectionResult lastResult = SelectionPointAfter; for(unsigned int si = 0; si < m_lines.count(); si++) { InlineTextBox* s = m_lines[si]; FindSelectionResult result; const Font *f = htmlFont( si==0 ); result = s->checkSelectionPoint(_x, _y, _tx, _ty, f, this, offset, m_lineHeight);// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " line " << si << " result=" << result << " offset=" << offset << endl; if ( result == SelectionPointInside ) // x,y is inside the textrun { offset += s->m_start; // add the offset from the previous lines// kdDebug(6040) << "RenderText::checkSelectionPoint inside -> " << offset << endl; node = element(); return SelectionPointInside; } else if ( result == SelectionPointBefore ) { if (!lastNode) { // x,y is before the textrun -> stop here offset = 0;// kdDebug(6040) << "RenderText::checkSelectionPoint " << this << "before us -> returning Before" << endl; node = element(); return SelectionPointBefore; } } else if ( result == SelectionPointBeforeInLine ) { offset = s->m_start; node = element(); return SelectionPointInside; } else if ( result == SelectionPointAfterInLine ) { lastOffset = s->m_start + s->m_len; lastNode = element(); lastResult = result; // no return here } } if (lastNode) { offset = lastOffset; node = lastNode;// kdDebug(6040) << "RenderText::checkSelectionPoint: lastNode " << lastNode << " lastOffset " << lastOffset << endl; return lastResult; } // set offset to max offset = str->l; //qDebug("setting node to %p", element()); node = element();// kdDebug(6040) << "RenderText::checkSelectionPoint: node " << node << " offset " << offset << endl; return SelectionPointAfter;}void RenderText::caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height){ if (!m_lines.count()) { _x = _y = height = -1; width = 1; return; } int pos; InlineTextBox * s = findInlineTextBox( offset, pos, true ); RenderText *t = s->renderText();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -