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

📄 rendertext.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "RenderText.h"#include "CharacterNames.h"#include "FloatQuad.h"#include "FrameView.h"#include "InlineTextBox.h"#include "Range.h"#include "RenderArena.h"#include "RenderBlock.h"#include "RenderLayer.h"#include "RenderView.h"#include "Text.h"#include "TextBreakIterator.h"#include "VisiblePosition.h"#include "break_lines.h"#include <wtf/AlwaysInline.h>using namespace std;using namespace WTF;using namespace Unicode;namespace WebCore {// FIXME: Move to StringImpl.h eventually.static inline bool charactersAreAllASCII(StringImpl* text){    return charactersAreAllASCII(text->characters(), text->length());}RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)     : RenderObject(node)     , m_text(str)     , m_firstTextBox(0)     , m_lastTextBox(0)     , m_minWidth(-1)     , m_maxWidth(-1)     , m_beginMinWidth(0)     , m_endMinWidth(0)     , m_hasTab(false)     , m_linesDirty(false)     , m_containsReversedText(false)     , m_isAllASCII(charactersAreAllASCII(m_text.get())){    ASSERT(m_text);    setIsText();    m_text = document()->displayStringModifiedByEncoding(PassRefPtr<StringImpl>(m_text));    view()->frameView()->setIsVisuallyNonEmpty();}#ifndef NDEBUGRenderText::~RenderText(){    ASSERT(!m_firstTextBox);    ASSERT(!m_lastTextBox);}#endifconst char* RenderText::renderName() const{    return "RenderText";}bool RenderText::isTextFragment() const{    return false;}bool RenderText::isWordBreak() const{    return false;}void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){    // There is no need to ever schedule repaints from a style change of a text run, since    // we already did this for the parent of the text run.    // We do have to schedule layouts, though, since a style change can force us to    // need to relayout.    if (diff == StyleDifferenceLayout)        setNeedsLayoutAndPrefWidthsRecalc();    ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;    ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;    if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) {        if (RefPtr<StringImpl> textToTransform = originalText())            setText(textToTransform.release(), true);    }}void RenderText::destroy(){    if (!documentBeingDestroyed()) {        if (firstTextBox()) {            if (isBR()) {                RootInlineBox* next = firstTextBox()->root()->nextRootBox();                if (next)                    next->markDirty();            }            for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())                box->remove();        } else if (parent())            parent()->dirtyLinesFromChangedChild(this);    }    deleteTextBoxes();    RenderObject::destroy();}void RenderText::extractTextBox(InlineTextBox* box){    checkConsistency();    m_lastTextBox = box->prevTextBox();    if (box == m_firstTextBox)        m_firstTextBox = 0;    if (box->prevTextBox())        box->prevTextBox()->setNextLineBox(0);    box->setPreviousLineBox(0);    for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())        curr->setExtracted();    checkConsistency();}void RenderText::attachTextBox(InlineTextBox* box){    checkConsistency();    if (m_lastTextBox) {        m_lastTextBox->setNextLineBox(box);        box->setPreviousLineBox(m_lastTextBox);    } else        m_firstTextBox = box;    InlineTextBox* last = box;    for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {        curr->setExtracted(false);        last = curr;    }    m_lastTextBox = last;    checkConsistency();}void RenderText::removeTextBox(InlineTextBox* box){    checkConsistency();    if (box == m_firstTextBox)        m_firstTextBox = box->nextTextBox();    if (box == m_lastTextBox)        m_lastTextBox = box->prevTextBox();    if (box->nextTextBox())        box->nextTextBox()->setPreviousLineBox(box->prevTextBox());    if (box->prevTextBox())        box->prevTextBox()->setNextLineBox(box->nextTextBox());    checkConsistency();}void RenderText::deleteTextBoxes(){    if (firstTextBox()) {        RenderArena* arena = renderArena();        InlineTextBox* next;        for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {            next = curr->nextTextBox();            curr->destroy(arena);        }        m_firstTextBox = m_lastTextBox = 0;    }}PassRefPtr<StringImpl> RenderText::originalText() const{    Node* e = node();    return e ? static_cast<Text*>(e)->string() : 0;}void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool){    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())        rects.append(IntRect(tx + box->x(), ty + box->y(), box->width(), box->height()));}void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight){    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this     // function to take ints causes various internal mismatches. But selectionRect takes ints, and     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.    ASSERT(end == UINT_MAX || end <= INT_MAX);    ASSERT(start <= INT_MAX);    start = min(start, static_cast<unsigned>(INT_MAX));    end = min(end, static_cast<unsigned>(INT_MAX));        FloatPoint absPos = localToAbsolute(FloatPoint());    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {        // Note: box->end() returns the index of the last character, not the index past it        if (start <= box->start() && box->end() < end) {            IntRect r = IntRect(absPos.x() + box->x(), absPos.y() + box->y(), box->width(), box->height());            if (useSelectionHeight) {                IntRect selectionRect = box->selectionRect(absPos.x(), absPos.y(), start, end);                r.setHeight(selectionRect.height());                r.setY(selectionRect.y());            }            rects.append(r);        } else {            unsigned realEnd = min(box->end() + 1, end);            IntRect r = box->selectionRect(absPos.x(), absPos.y(), start, realEnd);            if (!r.isEmpty()) {                if (!useSelectionHeight) {                    // change the height and y position because selectionRect uses selection-specific values                    r.setHeight(box->height());                    r.setY(absPos.y() + box->y());                }                rects.append(r);            }        }    }}void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool){    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())        quads.append(localToAbsoluteQuad(FloatRect(box->x(), box->y(), box->width(), box->height())));}void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight){    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this     // function to take ints causes various internal mismatches. But selectionRect takes ints, and     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.    ASSERT(end == UINT_MAX || end <= INT_MAX);    ASSERT(start <= INT_MAX);    start = min(start, static_cast<unsigned>(INT_MAX));    end = min(end, static_cast<unsigned>(INT_MAX));        for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {        // Note: box->end() returns the index of the last character, not the index past it        if (start <= box->start() && box->end() < end) {            IntRect r = IntRect(box->x(), box->y(), box->width(), box->height());            if (useSelectionHeight) {                IntRect selectionRect = box->selectionRect(0, 0, start, end);                r.setHeight(selectionRect.height());                r.setY(selectionRect.y());            }            quads.append(localToAbsoluteQuad(FloatRect(r)));        } else {            unsigned realEnd = min(box->end() + 1, end);            IntRect r = box->selectionRect(0, 0, start, realEnd);            if (!r.isEmpty()) {                if (!useSelectionHeight) {                    // change the height and y position because selectionRect uses selection-specific values                    r.setHeight(box->height());                    r.setY(box->y());                }                quads.append(localToAbsoluteQuad(FloatRect(r)));            }        }    }}InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const{    // The text runs point to parts of the RenderText's m_text    // (they don't include '\n')    // Find the text run that includes the character at offset    // and return pos, which is the position of the char in the run.    if (!m_firstTextBox)        return 0;    InlineTextBox* s = m_firstTextBox;    int off = s->len();    while (offset > off && s->nextTextBox()) {        s = s->nextTextBox();        off = s->start() + s->len();    }    // we are now in the correct text run    pos = (offset > off ? s->len() : s->len() - (off - offset) );    return s;}VisiblePosition RenderText::positionForPoint(const IntPoint& point){    if (!firstTextBox() || textLength() == 0)        return VisiblePosition(node(), 0, DOWNSTREAM);    // Get the offset for the position, since this will take rtl text into account.    int offset;    // FIXME: We should be able to roll these special cases into the general cases in the loop below.    if (firstTextBox() && point.y() <  firstTextBox()->root()->bottomOverflow() && point.x() < firstTextBox()->m_x) {        // at the y coordinate of the first line or above        // and the x coordinate is to the left of the first text box left edge        offset = firstTextBox()->offsetForPosition(point.x());        return VisiblePosition(node(), offset + firstTextBox()->start(), DOWNSTREAM);    }    if (lastTextBox() && point.y() >= lastTextBox()->root()->topOverflow() && point.x() >= lastTextBox()->m_x + lastTextBox()->m_width) {        // at the y coordinate of the last line or below        // and the x coordinate is to the right of the last text box right edge        offset = lastTextBox()->offsetForPosition(point.x());        return VisiblePosition(node(), offset + lastTextBox()->start(), DOWNSTREAM);    }    InlineTextBox* lastBoxAbove = 0;    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {        if (point.y() >= box->root()->topOverflow()) {            int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow();            if (point.y() < bottom) {                offset = box->offsetForPosition(point.x());                if (point.x() == box->m_x)                    // the x coordinate is equal to the left edge of this box                    // the affinity must be downstream so the position doesn't jump back to the previous line                    return VisiblePosition(node(), offset + box->start(), DOWNSTREAM);                if (point.x() < box->m_x + box->m_width)                    // and the x coordinate is to the left of the right edge of this box                    // check to see if position goes in this box                    return VisiblePosition(node(), offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);                if (!box->prevOnLine() && point.x() < box->m_x)                    // box is first on line                    // and the x coordinate is to the left of the first text box left edge                    return VisiblePosition(node(), offset + box->start(), DOWNSTREAM);                if (!box->nextOnLine())                    // box is last on line                    // and the x coordinate is to the right of the last text box right edge                    // generate VisiblePosition, use UPSTREAM affinity if possible                    return VisiblePosition(node(), offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);            }            lastBoxAbove = box;        }    }    return VisiblePosition(node(), lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM);}IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine){    if (!inlineBox)        return IntRect();    ASSERT(inlineBox->isInlineTextBox());    if (!inlineBox->isInlineTextBox())        return IntRect();    InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);    int height = box->root()->bottomOverflow() - box->root()->topOverflow();    int top = box->root()->topOverflow();    int left = box->positionForOffset(caretOffset);    int rootLeft = box->root()->x();    // FIXME: should we use the width of the root inline box or the    // width of the containing block for this?    if (extraWidthToEndOfLine)        *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1);    RenderBlock* cb = containingBlock();    if (style()->autoWrap()) {        int availableWidth = cb->lineWidth(top, false);        if (box->direction() == LTR)            left = min(left, rootLeft + availableWidth - 1);        else            left = max(left, rootLeft);    }    return IntRect(left, top, caretWidth, height);}ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos) const{    if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) {        int monospaceCharacterWidth = f.spaceWidth();        int tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0;        int w = 0;        bool isSpace;        bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.        for (int i = start; i < start + len; i++) {            char c = (*m_text)[i];            if (c <= ' ') {                if (c == ' ' || c == '\n') {                    w += monospaceCharacterWidth;                    isSpace = true;                } else if (c == '\t') {                    w += tabWidth ? tabWidth - ((xPos + w) % tabWidth) : monospaceCharacterWidth;                    isSpace = true;                } else                    isSpace = false;            } else {                w += monospaceCharacterWidth;                isSpace = false;            }            if (isSpace && !previousCharWasSpace)                w += f.wordSpacing();            previousCharWasSpace = isSpace;        }        return w;    }    return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos));}

⌨️ 快捷键说明

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