📄 render_text.cpp
字号:
RootInlineBox* lastRootBox = 0;
bool dirtiedLines = false;
// Dirty all text boxes that include characters in between offset and offset+len.
for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
// Text run is entirely before the affected range.
if (curr->end() < offset)
continue;
// Text run is entirely after the affected range.
if (curr->start() > end) {
curr->offsetRun(delta);
RootInlineBox* root = curr->root();
if (!firstRootBox) {
firstRootBox = root;
if (!dirtiedLines) { // The affected area was in between two runs. Go ahead and mark the root box of the run after the affected area as dirty.
firstRootBox->markDirty();
dirtiedLines = true;
}
}
lastRootBox = root;
}
else if (curr->end() >= offset && curr->end() <= end) {
curr->dirtyLineBoxes(); // Text run overlaps with the left end of the affected range.
dirtiedLines = true;
}
else if (curr->start() <= offset && curr->end() >= end) {
curr->dirtyLineBoxes(); // Text run subsumes the affected range.
dirtiedLines = true;
}
else if (curr->start() <= end && curr->end() >= end) {
curr->dirtyLineBoxes(); // Text run overlaps with right end of the affected range.
dirtiedLines = true;
}
}
// Now we have to walk all of the clean lines and adjust their cached line break information
// to reflect our updated offsets.
if (lastRootBox)
lastRootBox = lastRootBox->nextRootBox();
if (firstRootBox) {
RootInlineBox* prev = firstRootBox->prevRootBox();
if (prev)
firstRootBox = prev;
}
for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
if (!curr->isDirty() && curr->lineBreakObj() == this && curr->lineBreakPos() > end)
curr->setLineBreakPos(curr->lineBreakPos()+delta);
}
m_linesDirty = dirtiedLines;
setText(text, force);
}
void RenderText::setText(DOMStringImpl *text, bool force)
{
if (!text)
return;
if (!force && str == text)
return;
if (str)
str->deref();
#ifdef APPLE_CHANGES
m_allAsciiChecked = false;
#endif
str = text;
if (str) {
str = str->replace('\\', backslashAsCurrencySymbol());
if ( style() ) {
switch(style()->textTransform()) {
case CAPITALIZE: str = str->capitalize(); break;
case UPPERCASE: str = str->upper(); break;
case LOWERCASE: str = str->lower(); break;
case NONE:
default:;
}
}
str->ref();
}
#if APPLE_CHANGES
cacheWidths();
#endif
// ### what should happen if we change the text of a
// RenderBR object ?
KHTMLAssert(!isBR() || (str->l == 1 && (*str->s) == '\n'));
KHTMLAssert(!str->l || str->s);
setNeedsLayoutAndMinMaxRecalc();
#ifdef BIDI_DEBUG
QConstString cstr(str->s, str->l);
kdDebug( 6040 ) << "RenderText::setText( " << cstr.string().length() << " ) '" << cstr.string() << "'" << endl;
#endif
}
int RenderText::height() const
{
// FIXME: Why use line-height? Shouldn't we be adding in the height of the last text box? -dwh
int retval = 0;
if (firstTextBox())
retval = lastTextBox()->m_y + lineHeight(false) - firstTextBox()->m_y;
return retval;
}
short RenderText::lineHeight(bool firstLine, bool) const
{
// Always use the interior line height of the parent (e.g., if our parent is an inline block).
return parent()->lineHeight(firstLine, true);
}
short RenderText::baselinePosition( bool firstLine, bool ) const
{
const QFontMetrics &fm = metrics( firstLine );
return fm.ascent() +
( lineHeight( firstLine ) - fm.height() ) / 2;
}
void RenderText::dirtyLineBoxes(bool fullLayout, bool)
{
if (fullLayout)
deleteTextBoxes();
else if (!m_linesDirty) {
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
box->dirtyLineBoxes();
}
m_linesDirty = false;
}
InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool)
{
KHTMLAssert(!isRootLineBox);
InlineTextBox* textBox = new (renderArena()) InlineTextBox(this);
if (!m_firstTextBox)
m_firstTextBox = m_lastTextBox = textBox;
else {
m_lastTextBox->setNextLineBox(textBox);
textBox->setPreviousLineBox(m_lastTextBox);
m_lastTextBox = textBox;
}
return textBox;
}
void RenderText::position(InlineBox* box, int from, int len, bool reverse)
{
InlineTextBox *s = static_cast<InlineTextBox*>(box);
// ### should not be needed!!!
if (len == 0) {
// We want the box to be destroyed.
s->remove();
s->detach(renderArena());
m_firstTextBox = m_lastTextBox = 0;
return;
}
reverse = reverse && !style()->visuallyOrdered();
#ifdef DEBUG_LAYOUT
QChar *ch = str->s+from;
QConstString cstr(ch, len);
qDebug("setting run text to *%s*, len=%d, w)=%d" , cstr.string().latin1(), len, width );//" << y << ")" << " height=" << lineHeight(false) << " fontHeight=" << metrics(false).height() << " ascent =" << metrics(false).ascent() << endl;
#endif
s->m_reversed = reverse;
s->m_start = from;
s->m_len = len;
}
unsigned int RenderText::width(unsigned int from, unsigned int len, bool firstLine) const
{
if(!str->s || from > str->l ) return 0;
if ( from + len > str->l ) len = str->l - from;
const Font *f = htmlFont( firstLine );
return width( from, len, f );
}
unsigned int RenderText::width(unsigned int from, unsigned int len, const Font *f) const
{
if(!str->s || from > str->l ) return 0;
if ( from + len > str->l ) len = str->l - from;
int w;
if ( f == &style()->htmlFont() && from == 0 && len == str->l )
w = m_maxWidth;
#if APPLE_CHANGES
else if (f == &style()->htmlFont())
w = widthFromCache (f, from, len);
#endif
else
w = f->width(str->s, str->l, from, len );
//kdDebug( 6040 ) << "RenderText::width(" << from << ", " << len << ") = " << w << endl;
return w;
}
int RenderText::width() const
{
int w;
int minx = 100000000;
int maxx = 0;
// slooow
for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) {
if(s->m_x < minx)
minx = s->m_x;
if(s->m_x + s->m_width > maxx)
maxx = s->m_x + s->m_width;
}
w = kMax(0, maxx-minx);
return w;
}
QRect RenderText::getAbsoluteRepaintRect()
{
RenderObject *cb = containingBlock();
return cb->getAbsoluteRepaintRect();
}
QRect RenderText::selectionRect()
{
QRect rect;
if (selectionState() == SelectionNone)
return rect;
RenderBlock* cb = containingBlock();
if (!cb)
return rect;
// Now calculate startPos and endPos for painting selection.
// We include a selection while endPos > 0
int startPos, endPos;
if (selectionState() == SelectionInside) {
// We are fully selected.
startPos = 0;
endPos = str->l;
} else {
selectionStartEnd(startPos, endPos);
if (selectionState() == SelectionStart)
endPos = str->l;
else if (selectionState() == SelectionEnd)
startPos = 0;
}
if (startPos == endPos)
return rect;
int absx, absy;
cb->absolutePosition(absx, absy);
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
QRect r = box->selectionRect(absx, absy, startPos, endPos);
if (!r.isEmpty()) {
if (rect.isEmpty())
rect = r;
else
rect = rect.unite(r);
}
}
return rect;
}
short RenderText::verticalPositionHint( bool firstLine ) const
{
return parent()->verticalPositionHint( firstLine );
}
const QFontMetrics &RenderText::metrics(bool firstLine) const
{
return style(firstLine)->fontMetrics();
}
const Font *RenderText::htmlFont(bool firstLine) const
{
return &style(firstLine)->htmlFont();
}
long RenderText::caretMinOffset() const
{
InlineTextBox *box = firstTextBox();
if (!box)
return 0;
int minOffset = box->m_start;
for (box = box->nextTextBox(); box; box = box->nextTextBox())
minOffset = kMin(minOffset, box->m_start);
return minOffset;
}
long RenderText::caretMaxOffset() const
{
InlineTextBox* box = lastTextBox();
if (!box)
return str->l;
int maxOffset = box->m_start + box->m_len;
for (box = box->prevTextBox(); box; box = box->prevTextBox())
maxOffset = kMax(maxOffset,box->m_start + box->m_len);
return maxOffset;
}
unsigned long RenderText::caretMaxRenderedOffset() const
{
int l = 0;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
l += box->m_len;
return l;
}
InlineBox *RenderText::inlineBox(long offset, EAffinity affinity)
{
for (InlineTextBox *box = firstTextBox(); box; box = box->nextTextBox()) {
if (offset >= box->m_start && offset <= box->m_start + box->m_len) {
if (affinity == DOWNSTREAM && box->nextTextBox() && offset == box->m_start + box->m_len)
return box->nextTextBox();
return box;
}
else if (offset < box->m_start) {
// The offset we're looking for is before this node
// this means the offset must be in content that is
// not rendered.
return box->prevTextBox() ? box->prevTextBox() : firstTextBox();
}
}
return 0;
}
RenderTextFragment::RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str,
int startOffset, int endOffset)
:RenderText(_node, _str->substring(startOffset, endOffset)),
m_start(startOffset), m_end(endOffset), m_generatedContentStr(0)
{}
RenderTextFragment::RenderTextFragment(DOM::NodeImpl* _node, DOM::DOMStringImpl* _str)
:RenderText(_node, _str), m_start(0)
{
m_generatedContentStr = _str;
if (_str) {
_str->ref();
m_end = _str->l;
}
else
m_end = 0;
}
RenderTextFragment::~RenderTextFragment()
{
if (m_generatedContentStr)
m_generatedContentStr->deref();
}
bool RenderTextFragment::isTextFragment() const
{
return true;
}
DOM::DOMStringImpl* RenderTextFragment::originalString() const
{
DOM::DOMStringImpl* result = 0;
if (element())
result = element()->string();
else
result = contentString();
if (result && (start() > 0 || start() < result->l))
result = result->substring(start(), end());
return result;
}
#undef BIDI_DEBUG
#undef DEBUG_LAYOUT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -