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

📄 selection.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    setModifyBias(alter, dir);

    VisiblePosition pos;
    switch (dir) {
        // EDIT FIXME: These need to handle bidi
        case RIGHT:
        case FORWARD:
            if (alter == EXTEND)
                pos = modifyExtendingRightForward(granularity);
            else
                pos = modifyMovingRightForward(granularity);
            break;
        case LEFT:
        case BACKWARD:
            if (alter == EXTEND)
                pos = modifyExtendingLeftBackward(granularity);
            else
                pos = modifyMovingLeftBackward(granularity);
            break;
    }

    if (pos.isNull())
        return false;

    switch (alter) {
        case MOVE:
            moveTo(pos);
            break;
        case EXTEND:
            setExtent(pos);
            break;
    }

    setNeedsLayout();

    return true;
}

// FIXME: Maybe baseline would be better?
static bool caretY(const VisiblePosition &c, int &y)
{
    Position p = c.deepEquivalent();
    NodeImpl *n = p.node();
    if (!n)
        return false;
    RenderObject *r = p.node()->renderer();
    if (!r)
        return false;
    QRect rect = r->caretRect(p.offset());
    if (rect.isEmpty())
        return false;
    y = rect.y() + rect.height() / 2;
    return true;
}

bool Selection::modify(EAlter alter, int verticalDistance)
{
    if (verticalDistance == 0)
        return false;

    bool up = verticalDistance < 0;
    if (up)
        verticalDistance = -verticalDistance;

    // can dump this UPSTREAM when we have m_extentAffinity
    m_affinity = UPSTREAM;
    setModifyBias(alter, up ? BACKWARD : FORWARD);

    VisiblePosition pos;
    int xPos = 0;
    switch (alter) {
        case MOVE:
            pos = VisiblePosition(up ? m_start : m_end, m_affinity);
            xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
            break;
        case EXTEND:
            pos = VisiblePosition(m_extent, m_affinity);
            xPos = xPosForVerticalArrowNavigation(EXTENT);
            break;
    }

    int startY;
    if (!caretY(pos, startY))
        return false;
    if (up)
        startY = -startY;
    int lastY = startY;

    VisiblePosition result;
    VisiblePosition next;
    for (VisiblePosition p = pos; ; p = next) {
        next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
        if (next.isNull() || next == p)
            break;
        int nextY;
        if (!caretY(next, nextY))
            break;
        if (up)
            nextY = -nextY;
        if (nextY - startY > verticalDistance)
            break;
        if (nextY >= lastY) {
            lastY = nextY;
            result = next;
        }
    }

    if (result.isNull())
        return false;

    switch (alter) {
        case MOVE:
            moveTo(result);
            break;
        case EXTEND:
            setExtent(result);
            break;
    }

    return true;
}

bool Selection::expandUsingGranularity(ETextGranularity granularity)
{
    if (isNone())
        return false;
    validate(granularity);
    return true;
}

int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
{
    int x = 0;

    if (isNone())
        return x;

    Position pos;
    switch (type) {
        case START:
            pos = m_start;
            break;
        case END:
            pos = m_end;
            break;
        case BASE:
            pos = m_base;
            break;
        case EXTENT:
            pos = m_extent;
            break;
    }

    KHTMLPart *part = pos.node()->getDocument()->part();
    if (!part)
        return x;
        
    if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
        switch (m_affinity) {
            case DOWNSTREAM:
                pos = VisiblePosition(pos, m_affinity).downstreamDeepEquivalent();
                break;
            case UPSTREAM:
                pos = VisiblePosition(pos, m_affinity).deepEquivalent();
                break;
        }
        x = pos.node()->renderer()->caretRect(pos.offset(), m_affinity).x();
        part->setXPosForVerticalArrowNavigation(x);
    }
    else {
        x = part->xPosForVerticalArrowNavigation();
    }
    return x;
}

void Selection::clear()
{
    m_affinity = SEL_DEFAULT_AFFINITY;
    m_base.clear();
    m_extent.clear();
    validate();
}

void Selection::setBase(const VisiblePosition &pos)
{
    m_affinity = pos.affinity();
    m_base = pos.deepEquivalent();
    validate();
}

void Selection::setExtent(const VisiblePosition &pos)
{
    // FIXME: Support extentAffinity
    m_extent = pos.deepEquivalent();
    validate();
}

void Selection::setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent)
{
    // FIXME: Support extentAffinity
    m_affinity = base.affinity();
    m_base = base.deepEquivalent();
    m_extent = extent.deepEquivalent();
    validate();
}


void Selection::setBase(const Position &pos, EAffinity baseAffinity)
{
    m_affinity = baseAffinity;
    m_base = pos;
    validate();
}

void Selection::setExtent(const Position &pos, EAffinity extentAffinity)
{
    // FIXME: Support extentAffinity for real
    m_affinity = extentAffinity;
    m_extent = pos;
    validate();
}

void Selection::setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
{
    // FIXME: extentAffinity
    m_affinity = baseAffinity;
    m_base = base;
    m_extent = extent;
    validate();
}

void Selection::setNeedsLayout(bool flag)
{
    m_needsLayout = flag;
}

Range Selection::toRange() const
{
    if (isNone())
        return Range();

    // Make sure we have an updated layout since this function is called
    // in the course of running edit commands which modify the DOM.
    // Failing to call this can result in equivalentXXXPosition calls returning
    // incorrect results.
    m_start.node()->getDocument()->updateLayout();

    Position s, e;
    if (isCaret()) {
        // If the selection is a caret, move the range start upstream. This helps us match
        // the conventions of text editors tested, which make style determinations based
        // on the character before the caret, if any. 
        s = m_start.upstream(StayInBlock).equivalentRangeCompliantPosition();
        e = s;
    }
    else {
        // If the selection is a range, select the minimum range that encompasses the selection.
        // Again, this is to match the conventions of text editors tested, which make style 
        // determinations based on the first character of the selection. 
        // For instance, this operation helps to make sure that the "X" selected below is the 
        // only thing selected. The range should not be allowed to "leak" out to the end of the 
        // previous text node, or to the beginning of the next text node, each of which has a 
        // different style.
        // 
        // On a treasure map, <b>X</b> marks the spot.
        //                       ^ selected
        //
        ASSERT(isRange());
        s = m_start.downstream(StayInBlock);
        e = m_end.upstream(StayInBlock);
        if (RangeImpl::compareBoundaryPoints(s.node(), s.offset(), e.node(), e.offset()) > 0) {
            // Make sure the start is before the end.
            // The end can wind up before the start if collapsed whitespace is the only thing selected.
            Position tmp = s;
            s = e;
            e = tmp;
        }
        s = s.equivalentRangeCompliantPosition();
        e = e.equivalentRangeCompliantPosition();
    }

    // Use this roundabout way of creating the Range in order to have defined behavior
    // when there is a DOM exception.
    int exceptionCode = 0;
    Range result(s.node()->getDocument());
    RangeImpl *handle = result.handle();
    ASSERT(handle);
    handle->setStart(s.node(), s.offset(), exceptionCode);
    if (exceptionCode) {
        ERROR("Exception setting Range start from Selection: %d", exceptionCode);
        return Range();
    }
    handle->setEnd(e.node(), e.offset(), exceptionCode);
    if (exceptionCode) {
        ERROR("Exception setting Range end from Selection: %d", exceptionCode);
        return Range();
    }
    return result;
}

void Selection::layout()
{
    if (isNone() || !m_start.node()->inDocument() || !m_end.node()->inDocument()) {
        m_caretRect = QRect();
        m_expectedVisibleRect = QRect();
        return;
    }

    m_start.node()->getDocument()->updateRendering();
        
    if (isCaret()) {
        Position pos = m_start;
        switch (m_affinity) {
            case DOWNSTREAM:
                pos = VisiblePosition(m_start, m_affinity).downstreamDeepEquivalent();
                break;
            case UPSTREAM:
                pos = VisiblePosition(m_start, m_affinity).deepEquivalent();
                break;
        }
        if (pos.isNotNull()) {
            ASSERT(pos.node()->renderer());
            m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), m_affinity);
            m_expectedVisibleRect = m_caretRect;
        }
        else {
            m_caretRect = QRect();
            m_expectedVisibleRect = QRect();
        }
    }
    else {
        // Calculate which position to use based on whether the base is the start.
        // We want the position, start or end, that was calculated using the extent. 
        // This makes the selection follow the extent position while scrolling as a 
        // result of arrow navigation. 
        //
        // Note: no need to get additional help from VisiblePosition. The m_start and
        // m_end positions should already be visible, and we're only interested in 
        // a rectangle for m_expectedVisibleRect, hence affinity is not a factor
        // like it is when drawing a caret.
        //
        Position pos = m_baseIsStart ? m_end : m_start;
        ASSERT(pos.node()->renderer()); 
        m_expectedVisibleRect = pos.node()->renderer()->caretRect(pos.offset(), m_affinity);
        m_caretRect = QRect();
    }

    m_needsLayout = false;
}

QRect Selection::caretRect() const
{
    if (m_needsLayout) {
        const_cast<Selection *>(this)->layout();
    }

    return m_caretRect;
}

QRect Selection::expectedVisibleRect() const
{
    if (m_needsLayout) {
        const_cast<Selection *>(this)->layout();
    }

    return m_expectedVisibleRect;
}

QRect Selection::caretRepaintRect() const
{
    // FIXME: Add one pixel of slop on each side to make sure we don't leave behind artifacts.
    QRect r = caretRect();
    if (r.isEmpty())
        return QRect();

⌨️ 快捷键说明

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