⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rendertext.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
void RenderText::trimmedPrefWidths(int leadWidth,                                   int& beginMinW, bool& beginWS,                                   int& endMinW, bool& endWS,                                   bool& hasBreakableChar, bool& hasBreak,                                   int& beginMaxW, int& endMaxW,                                   int& minW, int& maxW, bool& stripFrontSpaces){    bool collapseWhiteSpace = style()->collapseWhiteSpace();    if (!collapseWhiteSpace)        stripFrontSpaces = false;    if (m_hasTab || prefWidthsDirty())        calcPrefWidths(leadWidth);    beginWS = !stripFrontSpaces && m_hasBeginWS;    endWS = m_hasEndWS;    int len = textLength();    if (!len || (stripFrontSpaces && m_text->containsOnlyWhitespace())) {        beginMinW = 0;        endMinW = 0;        beginMaxW = 0;        endMaxW = 0;        minW = 0;        maxW = 0;        hasBreak = false;        return;    }    minW = m_minWidth;    maxW = m_maxWidth;    beginMinW = m_beginMinWidth;    endMinW = m_endMinWidth;    hasBreakableChar = m_hasBreakableChar;    hasBreak = m_hasBreak;    if ((*m_text)[0] == ' ' || ((*m_text)[0] == '\n' && !style()->preserveNewline()) || (*m_text)[0] == '\t') {        const Font& f = style()->font(); // FIXME: This ignores first-line.        if (stripFrontSpaces) {            const UChar space = ' ';            int spaceWidth = f.width(TextRun(&space, 1));            maxW -= spaceWidth;        } else            maxW += f.wordSpacing();    }    stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;    if (!style()->autoWrap() || minW > maxW)        minW = maxW;    // Compute our max widths by scanning the string for newlines.    if (hasBreak) {        const Font& f = style()->font(); // FIXME: This ignores first-line.        bool firstLine = true;        beginMaxW = maxW;        endMaxW = maxW;        for (int i = 0; i < len; i++) {            int linelen = 0;            while (i + linelen < len && (*m_text)[i + linelen] != '\n')                linelen++;            if (linelen) {                endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW);                if (firstLine) {                    firstLine = false;                    leadWidth = 0;                    beginMaxW = endMaxW;                }                i += linelen;            } else if (firstLine) {                beginMaxW = 0;                firstLine = false;                leadWidth = 0;            }            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;        }    }}static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style){    return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);}int RenderText::minPrefWidth() const{    if (prefWidthsDirty())        const_cast<RenderText*>(this)->calcPrefWidths(0);            return m_minWidth;}int RenderText::maxPrefWidth() const{    if (prefWidthsDirty())        const_cast<RenderText*>(this)->calcPrefWidths(0);            return m_maxWidth;}void RenderText::calcPrefWidths(int leadWidth){    ASSERT(m_hasTab || prefWidthsDirty());    m_minWidth = 0;    m_beginMinWidth = 0;    m_endMinWidth = 0;    m_maxWidth = 0;    if (isBR())        return;    int currMinWidth = 0;    int currMaxWidth = 0;    m_hasBreakableChar = false;    m_hasBreak = false;    m_hasTab = false;    m_hasBeginWS = false;    m_hasEndWS = false;    const Font& f = style()->font(); // FIXME: This ignores first-line.    int wordSpacing = style()->wordSpacing();    int len = textLength();    const UChar* txt = characters();    bool needsWordSpacing = false;    bool ignoringSpaces = false;    bool isSpace = false;    bool firstWord = true;    bool firstLine = true;    int nextBreakable = -1;    int lastWordBoundary = 0;    bool breakNBSP = style()->autoWrap() && style()->nbspMode() == SPACE;    bool breakAll = (style()->wordBreak() == BreakAllWordBreak || style()->wordBreak() == BreakWordBreak) && style()->autoWrap();    for (int i = 0; i < len; i++) {        UChar c = txt[i];        bool previousCharacterIsSpace = isSpace;        bool isNewline = false;        if (c == '\n') {            if (style()->preserveNewline()) {                m_hasBreak = true;                isNewline = true;                isSpace = false;            } else                isSpace = true;        } else if (c == '\t') {            if (!style()->collapseWhiteSpace()) {                m_hasTab = true;                isSpace = false;            } else                isSpace = true;        } else            isSpace = c == ' ';        if ((isSpace || isNewline) && !i)            m_hasBeginWS = true;        if ((isSpace || isNewline) && i == len - 1)            m_hasEndWS = true;        if (!ignoringSpaces && style()->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)            ignoringSpaces = true;        if (ignoringSpaces && !isSpace)            ignoringSpaces = false;        // Ignore spaces and soft hyphens        if (ignoringSpaces) {            ASSERT(lastWordBoundary == i);            lastWordBoundary++;            continue;        } else if (c == softHyphen) {            currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth);            lastWordBoundary = i + 1;            continue;        }        bool hasBreak = breakAll || isBreakable(txt, i, len, nextBreakable, breakNBSP);        bool betweenWords = true;        int j = i;        while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) {            j++;            if (j == len)                break;            c = txt[j];            if (isBreakable(txt, j, len, nextBreakable, breakNBSP))                break;            if (breakAll) {                betweenWords = false;                break;            }        }        int wordLen = j - i;        if (wordLen) {            int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth);            currMinWidth += w;            if (betweenWords) {                if (lastWordBoundary == i)                    currMaxWidth += w;                else                    currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth);                lastWordBoundary = j;            }            bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style());            bool isCollapsibleWhiteSpace = (j < len) && style()->isCollapsibleWhiteSpace(c);            if (j < len && style()->autoWrap())                m_hasBreakableChar = true;            // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the            // last word in the run.            if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))                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.                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()->autoWrap() || isNewline)                m_hasBreakableChar = true;            if (currMinWidth > m_minWidth)                m_minWidth = currMinWidth;            currMinWidth = 0;            if (isNewline) { // Only set if preserveNewline was true and we saw a newline.                if (firstLine) {                    firstLine = false;                    leadWidth = 0;                    if (!style()->autoWrap())                        m_beginMinWidth = currMaxWidth;                }                if (currMaxWidth > m_maxWidth)                    m_maxWidth = currMaxWidth;                currMaxWidth = 0;            } else {                currMaxWidth += f.width(TextRun(txt + i, 1, allowTabs(), leadWidth + currMaxWidth));                needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;            }            ASSERT(lastWordBoundary == i);            lastWordBoundary++;        }    }    if (needsWordSpacing && len > 1 || ignoringSpaces && !firstWord)        currMaxWidth += wordSpacing;    m_minWidth = max(currMinWidth, m_minWidth);    m_maxWidth = max(currMaxWidth, m_maxWidth);    if (!style()->autoWrap())        m_minWidth = m_maxWidth;    if (style()->whiteSpace() == PRE) {        if (firstLine)            m_beginMinWidth = m_maxWidth;        m_endMinWidth = currMaxWidth;    }    setPrefWidthsDirty(false);}bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const{    unsigned currPos;    for (currPos = from;         currPos < from + len && ((*m_text)[currPos] == '\n' || (*m_text)[currPos] == ' ' || (*m_text)[currPos] == '\t');         currPos++) { }    return currPos >= (from + len);}int RenderText::firstRunX() const{    return m_firstTextBox ? m_firstTextBox->m_x : 0;}int RenderText::firstRunY() const{    return m_firstTextBox ? m_firstTextBox->m_y : 0;}    void RenderText::setSelectionState(SelectionState state){    InlineTextBox* box;    RenderObject::setSelectionState(state);    if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {        int startPos, endPos;        selectionStartEnd(startPos, endPos);        if (selectionState() == SelectionStart) {            endPos = textLength();            // 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(state == SelectionInside);        }    }    containingBlock()->setSelectionState(state);}void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force){    unsigned oldLen = textLength();    unsigned newLen = text->length();    int delta = newLen - oldLen;    unsigned end = len ? offset + len - 1 : offset;    RootInlineBox* firstRootBox = 0;    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) {            // Text run overlaps with the left end of the affected range.            curr->dirtyLineBoxes();            dirtiedLines = true;        } else if (curr->start() <= offset && curr->end() >= end) {            // Text run subsumes the affected range.            curr->dirtyLineBoxes();            dirtiedLines = true;        } else if (curr->start() <= end && curr->end() >= end) {            // Text run overlaps with right end of the affected range.            curr->dirtyLineBoxes();            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->lineBreakObj() == this && curr->lineBreakPos() > end)            curr->setLineBreakPos(curr->lineBreakPos() + delta);    }    // If the text node is empty, dirty the line where new text will be inserted.    if (!firstTextBox() && parent()) {        parent()->dirtyLinesFromChangedChild(this);        dirtiedLines = true;    }    m_linesDirty = dirtiedLines;    setText(text, force);}static inline bool isInlineFlowOrEmptyText(RenderObject* o){    if (o->isRenderInline())        return true;    if (!o->isText())        return false;    StringImpl* text = toRenderText(o)->text();    if (!text)        return true;    return !text->length();}UChar RenderText::previousCharacter(){    // find previous text renderer if one exists    RenderObject* previousText = this;    while ((previousText = previousText->previousInPreOrder()))        if (!isInlineFlowOrEmptyText(previousText))            break;    UChar prev = ' ';    if (previousText && previousText->isText())        if (StringImpl* previousString = toRenderText(previousText)->text())            prev = (*previousString)[previousString->length() - 1];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -