📄 render_text.cpp
字号:
sel->height = height();
sel->area = 0;
boxInfoList.append(sel);
}
#endif
#ifdef APPLE_CHANGES
bool RenderText::allAscii() const
{
if (m_allAsciiChecked)
return m_allAscii;
m_allAsciiChecked = true;
unsigned int i;
for (i = 0; i < str->l; i++){
if (str->s[i].unicode() >= 0x7f){
m_allAscii = false;
return m_allAscii;
}
}
m_allAscii = true;
return m_allAscii;
}
bool RenderText::shouldUseMonospaceCache(const Font *f) const
{
return (f && f->isFixedPitch() && allAscii() && !style()->htmlFont().isSmallCaps());
}
// We cache the width of the ' ' character for <pre> text. We could go futher
// and cache a widths array for all styles, at the expense of increasing the size of the
// RenderText.
void RenderText::cacheWidths()
{
const Font *f = htmlFont( false );
if (shouldUseMonospaceCache(f)){
float fw;
QChar c(' ');
f->floatCharacterWidths( &c, 1, 0, 1, 0, &fw);
m_monospaceCharacterWidth = (int)fw;
}
else
m_monospaceCharacterWidth = 0;
}
inline int RenderText::widthFromCache(const Font *f, int start, int len) const
{
if (m_monospaceCharacterWidth != 0){
int i, w = 0;
for (i = start; i < start+len; i++){
int dir = str->s[i].direction();
if (dir != QChar::DirNSM && dir != QChar::DirBN)
w += m_monospaceCharacterWidth;
}
return w;
}
return f->width(str->s, str->l, start, len);
}
#ifdef XXX
inline int RenderText::widthFromCache(const Font *f, int start, int len) const
{
if (m_monospaceCharacterWidth != 0){
return len * m_monospaceCharacterWidth;
}
return f->width(str->s, str->l, start, len);
}
#endif
#endif
void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
int& endMinW, bool& endWS,
bool& hasBreakableChar, bool& hasBreak,
int& beginMaxW, int& endMaxW,
int& minW, int& maxW, bool& stripFrontSpaces)
{
bool isPre = style()->whiteSpace() == PRE;
if (isPre)
stripFrontSpaces = false;
int len = str->l;
if (len == 0 || (stripFrontSpaces && str->containsOnlyWhitespace())) {
maxW = 0;
hasBreak = false;
return;
}
minW = m_minWidth;
maxW = m_maxWidth;
beginWS = stripFrontSpaces ? false : m_hasBeginWS;
endWS = m_hasEndWS;
beginMinW = m_beginMinWidth;
endMinW = m_endMinWidth;
hasBreakableChar = m_hasBreakableChar;
hasBreak = m_hasBreak;
if (stripFrontSpaces && (str->s[0] == ' ' || (!isPre && str->s[0] == '\n'))) {
const Font *f = htmlFont( false );
QChar space[1]; space[0] = ' ';
int spaceWidth = f->width(space, 1, 0);
maxW -= spaceWidth;
}
stripFrontSpaces = !isPre && m_hasEndWS;
if (style()->whiteSpace() == NOWRAP)
minW = maxW;
else if (minW > maxW)
minW = maxW;
// Compute our max widths by scanning the string for newlines.
if (hasBreak) {
const Font *f = htmlFont( false );
bool firstLine = true;
beginMaxW = endMaxW = maxW;
for (int i = 0; i < len; i++)
{
int linelen = 0;
while (i+linelen < len && str->s[i+linelen] != '\n')
linelen++;
if (linelen)
{
#if !APPLE_CHANGES
endMaxW = f->width(str->s, str->l, i, linelen);
#else
endMaxW = widthFromCache(f, i, linelen);
#endif
if (firstLine) {
firstLine = false;
beginMaxW = endMaxW;
}
i += linelen;
}
else if (firstLine) {
beginMaxW = 0;
firstLine = false;
}
if (i == len-1)
// A <pre> run that ends with a newline, as in, e.g.,
// <pre>Some text\n\n<span>More text</pre>
endMaxW = 0;
}
}
}
void RenderText::calcMinMaxWidth()
{
KHTMLAssert( !minMaxKnown() );
// ### calc Min and Max width...
m_minWidth = m_beginMinWidth = m_endMinWidth = 0;
m_maxWidth = 0;
if (isBR())
return;
int currMinWidth = 0;
int currMaxWidth = 0;
m_hasBreakableChar = m_hasBreak = m_hasBeginWS = m_hasEndWS = false;
// ### not 100% correct for first-line
const Font *f = htmlFont( false );
int wordSpacing = style()->wordSpacing();
int len = str->l;
bool ignoringSpaces = false;
bool isSpace = false;
bool isPre = style()->whiteSpace() == PRE;
bool firstWord = true;
bool firstLine = true;
for(int i = 0; i < len; i++)
{
const QChar c = str->s[i];
bool previousCharacterIsSpace = isSpace;
bool isNewline = false;
if (c == '\n') {
if (isPre) {
m_hasBreak = true;
isNewline = true;
isSpace = false;
}
else
isSpace = true;
} else {
isSpace = c == ' ';
}
if ((isSpace || isNewline) && i == 0)
m_hasBeginWS = true;
if ((isSpace || isNewline) && i == len-1)
m_hasEndWS = true;
if (!ignoringSpaces && !isPre && previousCharacterIsSpace && isSpace)
ignoringSpaces = true;
if (ignoringSpaces && !isSpace)
ignoringSpaces = false;
if (ignoringSpaces || (i > 0 && c.unicode() == SOFT_HYPHEN)) // Ignore spaces and soft hyphens
continue;
int wordlen = 0;
while (i+wordlen < len && str->s[i+wordlen] != '\n' && str->s[i+wordlen] != ' ' &&
(i+wordlen == 0 || str->s[i+wordlen].unicode() != SOFT_HYPHEN) && // Skip soft hyphens
(wordlen == 0 || !isBreakable( str->s, i+wordlen, str->l)))
wordlen++;
if (wordlen)
{
#if !APPLE_CHANGES
int w = f->width(str->s, str->l, i, wordlen);
#else
int w = widthFromCache(f, i, wordlen);
#endif
currMinWidth += w;
currMaxWidth += w;
bool isBreakableCharSpace = (i+wordlen < len) ? ((!isPre && str->s[i+wordlen] == '\n') ||
str->s[i+wordlen] == ' ') : false;
if (i+wordlen < len && style()->whiteSpace() == NORMAL)
m_hasBreakableChar = true;
// Add in wordspacing to our maxwidth, but not if this is the last word on a line or the
// last word in the run.
if (wordSpacing && isBreakableCharSpace && !containsOnlyWhitespace(i+wordlen, len-(i+wordlen)))
currMaxWidth += wordSpacing;
if (firstWord) {
firstWord = false;
// If the first character in the run is breakable, then we consider ourselves to have a beginning
// minimum width of 0, since a break could occur right before our run starts, preventing us from ever
// being appended to a previous text run when considering the total minimum width of the containing block.
bool hasBreak = isBreakable(str->s, i, str->l);
if (hasBreak)
m_hasBreakableChar = true;
m_beginMinWidth = hasBreak ? 0 : w;
}
m_endMinWidth = w;
if (currMinWidth > m_minWidth) m_minWidth = currMinWidth;
currMinWidth = 0;
i += wordlen-1;
}
else {
// Nowrap can never be broken, so don't bother setting the
// breakable character boolean. Pre can only be broken if we encounter a newline.
if (style()->whiteSpace() == NORMAL || isNewline)
m_hasBreakableChar = true;
if (currMinWidth > m_minWidth) m_minWidth = currMinWidth;
currMinWidth = 0;
if (isNewline) // Only set if isPre was true and we saw a newline.
{
if (firstLine) {
firstLine = false;
m_beginMinWidth = currMaxWidth;
}
if (currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth;
currMaxWidth = 0;
}
else
{
currMaxWidth += f->width( str->s, str->l, i + wordlen );
}
}
}
if(currMinWidth > m_minWidth) m_minWidth = currMinWidth;
if(currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth;
if (style()->whiteSpace() != NORMAL)
m_minWidth = m_maxWidth;
if (isPre) {
if (firstLine)
m_beginMinWidth = m_maxWidth;
m_endMinWidth = currMaxWidth;
}
setMinMaxKnown();
//kdDebug( 6040 ) << "Text::calcMinMaxWidth(): min = " << m_minWidth << " max = " << m_maxWidth << endl;
}
bool RenderText::containsOnlyWhitespace(unsigned int from, unsigned int len) const
{
unsigned int currPos;
for (currPos = from;
currPos < from+len && (str->s[currPos] == '\n' || str->s[currPos].unicode() == ' ');
currPos++);
return currPos >= (from+len);
}
int RenderText::minXPos() const
{
if (!m_firstTextBox) return 0;
int retval=6666666;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
retval = kMin(retval, (int)box->m_x);
return retval;
}
int RenderText::xPos() const
{
return m_firstTextBox ? m_firstTextBox->m_x : 0;
}
int RenderText::yPos() const
{
return m_firstTextBox ? m_firstTextBox->m_y : 0;
}
const QFont &RenderText::font()
{
return style()->font();
}
void RenderText::setSelectionState(SelectionState s)
{
InlineTextBox* box;
m_selectionState = s;
if (s == SelectionStart || s == SelectionEnd || s == SelectionBoth) {
int startPos, endPos;
selectionStartEnd(startPos, endPos);
if(selectionState() == SelectionStart) {
endPos = str->l;
// to handle selection from end of text to end of line
if (startPos != 0 && startPos == endPos) {
startPos = endPos - 1;
}
} else if(selectionState() == SelectionEnd)
startPos = 0;
for (box = firstTextBox(); box; box = box->nextTextBox()) {
if (box->isSelected(startPos, endPos)) {
RootInlineBox* line = box->root();
if (line)
line->setHasSelectedChildren(true);
}
}
}
else {
for (box = firstTextBox(); box; box = box->nextTextBox()) {
RootInlineBox* line = box->root();
if (line)
line->setHasSelectedChildren(s == SelectionInside);
}
}
containingBlock()->setSelectionState(s);
}
void RenderText::setTextWithOffset(DOMStringImpl *text, uint offset, uint len, bool force)
{
uint oldLen = str ? str->l : 0;
uint newLen = text ? text->l : 0;
int delta = newLen - oldLen;
uint end = len ? offset+len-1 : offset;
RootInlineBox* firstRootBox = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -