📄 render_text.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: render_text.cpp,v 1.136.2.2 2001/11/02 14:18:41 mueller Exp $ *///#define DEBUG_LAYOUT//#define BIDI_DEBUG#include "render_text.h"#include "break_lines.h"#include "render_style.h"#include "misc/loader.h"#include "misc/helper.h"#include <qfontmetrics.h>#include <qfontinfo.h>#include <qfont.h>#include <qpainter.h>#include <qstring.h>#include <qcolor.h>#include <qrect.h>#include <kdebug.h>#define QT_ALLOC_QCHAR_VEC( N ) (QChar*) new char[ sizeof(QChar)*( N ) ]#define QT_DELETE_QCHAR_VEC( P ) delete[] ((char*)( P ))using namespace khtml;using namespace DOM;TextSlave::~TextSlave(){ if(m_reversed) QT_DELETE_QCHAR_VEC(m_text);}void TextSlave::print( QPainter *pt, int _tx, int _ty){ if (!m_text || m_len <= 0) return; QConstString s(m_text, m_len); //kdDebug( 6040 ) << "textSlave::printing(" << s.string() << ") at(" << x+_tx << "/" << y+_ty << ")" << endl; pt->drawText(m_x + _tx, m_y + _ty + m_baseline, s.string());}void TextSlave::printSelection(QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos){ if(startPos > m_len) return; if(startPos < 0) startPos = 0; int _len = m_len; int _width = m_width; if(endPos > 0 && endPos < m_len) { _len = endPos; } _len -= startPos; //kdDebug(6040) << "TextSlave::printSelection startPos (relative)=" << startPos << " len (of selection)=" << _len << " (m_len=" << m_len << ")" << endl; QConstString s(m_text+startPos , _len); if (_len != m_len) _width = p->fontMetrics().width(s.string()); int _offset = 0; if ( startPos > 0 ) { QConstString aStr(m_text, startPos); _offset = p->fontMetrics().width(aStr.string()); } p->save(); QColor c = style->color(); p->setPen(QColor(0xff-c.red(),0xff-c.green(),0xff-c.blue())); QFontMetrics fm = p->fontMetrics(); p->fillRect(m_x + tx + _offset, m_y + ty + m_baseline - fm.ascent(), _width, fm.height(), c); ty += m_baseline; //kdDebug( 6040 ) << "textSlave::printing(" << s.string() << ") at(" << x+_tx << "/" << y+_ty << ")" << endl; p->drawText(m_x + tx + _offset, m_y + ty, s.string()); p->restore();}void TextSlave::printDecoration( QPainter *pt, RenderText* p, int _tx, int _ty, int deco, bool begin, bool end){ _tx += m_x; _ty += m_y; int width = m_width; if( begin ) width -= p->paddingLeft() + p->borderLeft(); if ( end ) width -= p->paddingRight() + p->borderRight(); int underlineOffset = ( pt->fontMetrics().height() + m_baseline ) / 2; if(underlineOffset <= m_baseline) underlineOffset = m_baseline+1; if(deco & UNDERLINE) pt->drawLine(_tx, _ty + underlineOffset, _tx + width, _ty + underlineOffset ); if(deco & OVERLINE) pt->drawLine(_tx, _ty, _tx + width, _ty ); if(deco & LINE_THROUGH) pt->drawLine(_tx, _ty + 2*m_baseline/3, _tx + width, _ty + 2*m_baseline/3 ); // NO! Do NOT add BLINK! It is the most annouing feature of Netscape, and IE has a reason not to // support it. Lars}void TextSlave::printBoxDecorations(QPainter *pt, RenderStyle* style, RenderText *p, int _tx, int _ty, bool begin, bool end){ int topExtra = p->borderTop() + p->paddingTop(); int bottomExtra = p->borderBottom() + p->paddingBottom(); // ### firstline int halfleading = (p->m_lineHeight - style->font().pixelSize() ) / 2; _tx += m_x; _ty += m_y + halfleading - topExtra; int width = m_width; // the height of the decorations is: topBorder + topPadding + CSS fontsize + bottomPadding + bottomBorder int height = style->font().pixelSize() + topExtra + bottomExtra; if( begin ) _tx -= p->paddingLeft() + p->borderLeft(); QColor c = style->backgroundColor(); CachedImage *i = style->backgroundImage(); if(c.isValid() && (!i || i->tiled_pixmap(c).mask())) pt->fillRect(_tx, _ty, width, height, c); if(i) { // ### might need to add some correct offsets // ### use paddingX/Y pt->drawTiledPixmap(_tx, _ty, width, height, i->tiled_pixmap(c)); } if(style->hasBorder()) p->printBorder(pt, _tx, _ty, width, height, style, begin, end);#ifdef BIDI_DEBUG int h = p->lineHeight( false ) + p->paddingTop() + p->paddingBottom() + p->borderTop() + p->borderBottom(); QColor c2 = QColor("#0000ff"); p->drawBorder(pt, _tx, _ty, _tx, _ty + h, 1, RenderObject::BSLeft, c2, c2, SOLID, false, false, 0, 0); p->drawBorder(pt, _tx + m_width, _ty, _tx + m_width, _ty + h, 1, RenderObject::BSRight, c2, c2, SOLID, false, false, 0, 0);#endif}FindSelectionResult TextSlave::checkSelectionPoint(int _x, int _y, int _tx, int _ty, QFontMetrics * fm, int & offset, int lineHeight){ //kdDebug(6040) << "TextSlave::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y // << " _tx+m_x=" << _tx+m_x << " _ty+m_y=" << _ty+m_y << endl; offset = 0; if ( _y < _ty + m_y ) return SelectionPointBefore; // above -> before if ( _y > _ty + m_y + lineHeight || _x > _tx + m_x + m_width ) { // below or on the right -> after // Set the offset to the max offset = m_len; return SelectionPointAfter; } // The Y matches, check if we're on the left if ( _x < _tx + m_x ) return SelectionPointBefore; // on the left (and not below) -> before if ( m_reversed ) return SelectionPointBefore; // Abort if RTL (TODO) int delta = _x - (_tx + m_x); //kdDebug(6040) << "TextSlave::checkSelectionPoint delta=" << delta << endl; int pos = 0; while(pos < m_len) { // ### this will produce wrong results for RTL text!!! int w = fm->width(*(m_text+pos)); int w2 = w/2; w -= w2; delta -= w2; if(delta <= 0) break; pos++; delta -= w; } //kdDebug( 6040 ) << " Text --> inside at position " << pos << endl; offset = pos; return SelectionPointInside;}// -----------------------------------------------------------------------------TextSlaveArray::TextSlaveArray(){ setAutoDelete(true);}int TextSlaveArray::compareItems( Item d1, Item d2 ){ ASSERT(d1); ASSERT(d2); return static_cast<TextSlave*>(d1)->m_y - static_cast<TextSlave*>(d2)->m_y;}// remove this once QVector::bsearch is fixedint TextSlaveArray::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(DOMStringImpl *_str) : RenderObject(){ // init RenderObject attributes setRenderText(); // our object inherits from RenderText setInline(true); // our object is Inline m_minWidth = -1; m_maxWidth = -1; str = _str; if(str) str->ref(); assert(!str || !str->l || str->s); m_selectionState = SelectionNone; m_hasReturn = true; fm = 0;#ifdef DEBUG_LAYOUT QConstString cstr(str->s, str->l); kdDebug( 6040 ) << "RenderText::setText '" << (const char *)cstr.string().utf8() << "'" << endl;#endif}void RenderText::setStyle(RenderStyle *_style){ bool fontchanged = ( !style() || style()->font() != _style->font() ); RenderObject::setStyle(_style); if ( !fm || fontchanged ) { delete fm; fm = new QFontMetrics( style()->font() ); } // ### FIXME firstline support m_lineHeight = RenderObject::lineHeight(false); if ( style()->fontVariant() == SMALL_CAPS ) { setText( str->upper() ); } else { // ### does not work if texttransform is set to None again! switch(style()->textTransform()) { case CAPITALIZE: setText(str->capitalize()); break; case UPPERCASE: setText(str->upper()); break; case LOWERCASE: setText(str->lower()); break; case NONE: default:; } }}RenderText::~RenderText(){ deleteSlaves(); if(str) str->deref(); delete fm;}void RenderText::deleteSlaves(){ // 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(); for(unsigned int i=0; i < len; i++) m_lines.remove(i); ASSERT(m_lines.count() == 0);}TextSlave * RenderText::findTextSlave( int offset, int &pos ){ // The text slaves point to parts of the rendertext's str string // (they don't include '\n') // Find the text slave that includes the character at @p offset // and return pos, which is the position of the char in the slave. if ( m_lines.isEmpty() ) return 0L; TextSlave* s = m_lines[0]; uint si = 0; int off = s->m_len; while(offset > off && si < m_lines.count()) { s = m_lines[++si]; if ( s->m_reversed ) return 0L; // Abort if RTL (TODO) // ### only for visuallyOrdered ! off = s->m_text - str->s + s->m_len; } // we are now in the correct text slave pos = (offset > off ? s->m_len : s->m_len - (off - offset) ); return s;}bool RenderText::containsPoint(int _x, int _y, int _tx, int _ty){ int height = m_lineHeight + borderTop() + paddingTop() + borderBottom() + paddingBottom(); TextSlave *s = m_lines.count() ? m_lines[0] : 0; int si = 0; while(s) { if((_y >=_ty + s->m_y) && (_y < _ty + s->m_y + height) && (_x >= _tx + s->m_x) && (_x <_tx + s->m_x + s->m_width) ) return true; s = si < (int)m_lines.count()-1 ? m_lines[++si] : 0; } return false;}FindSelectionResult RenderText::checkSelectionPoint(int _x, int _y, int _tx, int _ty, int &offset){ //kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y // << " _tx=" << _tx << " _ty=" << _ty << endl; for(unsigned int si = 0; si < m_lines.count(); si++) { TextSlave* s = m_lines[si]; if ( s->m_reversed ) return SelectionPointBefore; // abort if RTL (TODO) int result; if ( khtml::printpainter || hasFirstLine() ) { QFontMetrics _fm = metrics( ( si == 0) ); result = s->checkSelectionPoint(_x, _y, _tx, _ty, &_fm, offset, m_lineHeight); } else { result = s->checkSelectionPoint(_x, _y, _tx, _ty, fm, offset, m_lineHeight); } //kdDebug(6040) << "RenderText::checkSelectionPoint " << this << " line " << si << " result=" << result << " offset=" << offset << endl; if ( result == SelectionPointInside ) // x,y is inside the textslave { // ### only for visuallyOrdered ! offset += s->m_text - str->s; // add the offset from the previous lines //kdDebug(6040) << "RenderText::checkSelectionPoint inside -> " << offset << endl; return SelectionPointInside; } else if ( result == SelectionPointBefore ) { // x,y is before the textslave -> stop here if ( si > 0 ) { // ### only for visuallyOrdered ! offset = s->m_text - str->s - 1; //kdDebug(6040) << "RenderText::checkSelectionPoint before -> " << offset << endl; return SelectionPointInside; } else { offset = 0; //kdDebug(6040) << "RenderText::checkSelectionPoint before us -> returning Before" << endl; return SelectionPointBefore; } } } // set offset to max offset = str->l; return SelectionPointAfter;}void RenderText::cursorPos(int offset, int &_x, int &_y, int &height){ if (!m_lines.count()) { _x = _y = height = -1; return; } int pos; TextSlave * s = findTextSlave( offset, pos ); _y = s->m_y; height = m_lineHeight; // ### firstLine!!! s->m_height; QFontMetrics fm = metrics( false ); // #### wrong for first-line! QString tekst(s->m_text, s->m_len); _x = s->m_x + (fm.boundingRect(tekst, pos)).right(); if(pos) _x += fm.rightBearing( *(s->m_text + pos - 1 ) ); int absx, absy; RenderObject *cb = containingBlock(); if (cb && cb != this && cb->absolutePosition(absx,absy)) { _x += absx; _y += absy; } else { // we don't know our absolute position, and there is not point returning // just a relative one _x = _y = -1; }}bool RenderText::absolutePosition(int &xPos, int &yPos, bool){ if(parent() && parent()->absolutePosition(xPos, yPos, false)) { xPos -= paddingLeft() + borderLeft(); yPos -= borderTop() + paddingTop(); return true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -