IntRect RenderReplaced::selectionRect()
{
    if (!isSelected())
        return IntRect();
    if (!m_inlineBoxWrapper)
        // We're a block-level replaced element.  Just return our own dimensions.
        return absoluteBoundingBoxRect();

    RenderBlock* cb =  containingBlock();
    if (!cb)
        return IntRect();
    
    RootInlineBox* root = m_inlineBoxWrapper->root();
    int selectionTop = root->selectionTop();
    int selectionHeight = root->selectionHeight();
    int selectionLeft = xPos();
    int selectionRight = xPos() + width();
    
    int absx, absy;
    cb->absolutePosition(absx, absy);
    if (cb->hasOverflowClip())
        cb->layer()->subtractScrollOffset(absx, absy);

    return IntRect(selectionLeft + absx, selectionTop + absy, selectionRight - selectionLeft, selectionHeight);
}
IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
{
    // Only run-ins are allowed in here during layout.
    ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());

    if (!firstLineBox() && !continuation())
        return IntRect();

    // Find our leftmost position.
    IntRect boundingBox(linesBoundingBox());
    int left = boundingBox.x();
    int top = boundingBox.y();

    // Now invalidate a rectangle.
    int ow = style() ? style()->outlineSize() : 0;
    
    // We need to add in the relative position offsets of any inlines (including us) up to our
    // containing block.
    RenderBlock* cb = containingBlock();
    for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; 
         inlineFlow = inlineFlow->parent()) {
         if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
            toRenderBox(inlineFlow)->layer()->relativePositionOffset(left, top);
    }

    IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
    if (cb->hasColumns())
        cb->adjustRectForColumns(r);

    if (cb->hasOverflowClip()) {
        // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
        // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
        // anyway if its size does change.
        int x = r.x();
        int y = r.y();
        IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
        cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
        IntRect repaintRect(x, y, r.width(), r.height());
        r = intersection(repaintRect, boxRect);
    }
    ASSERT(repaintContainer != this);
    cb->computeRectForRepaint(r, repaintContainer);

    if (ow) {
        for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
            if (!curr->isText()) {
                IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
                r.unite(childRect);
            }
        }

        if (continuation() && !continuation()->isInline()) {
            IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
            r.unite(contRect);
        }
    }

    return r;
}
QRect RenderFlow::getAbsoluteRepaintRect()
{
    if (isInlineFlow()) {
        // Find our leftmost position.
        int left = 0;
        int top = firstLineBox() ? firstLineBox()->yPos() : 0;
        for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
            if (curr == firstLineBox() || curr->xPos() < left)
                left = curr->xPos();

        // Now invalidate a rectangle.
        int ow = style() ? style()->outlineSize() : 0;
        if (isCompact())
            left -= m_x;
        
        // We need to add in the relative position offsets of any inlines (including us) up to our
        // containing block.
        RenderBlock* cb = containingBlock();
        for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; 
             inlineFlow = inlineFlow->parent()) {
             if (inlineFlow->style()->position() == RELATIVE && inlineFlow->layer())
                inlineFlow->layer()->relativePositionOffset(left, top);
        }

        QRect r(-ow+left, -ow+top, width()+ow*2, height()+ow*2);
        if (cb->hasOverflowClip()) {
            // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
            // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
            // anyway if its size does change.
            int x = r.left();
            int y = r.top();
            QRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
            cb->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
            QRect repaintRect(x, y, r.width(), r.height());
            r = repaintRect.intersect(boxRect);
        }
        cb->computeAbsoluteRepaintRect(r);
        
        if (ow) {
            for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
                if (!curr->isText()) {
                    QRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
                    r = r.unite(childRect);
                }
            }
            
            if (continuation() && !continuation()->isInline()) {
                QRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow);
                r = r.unite(contRect);
            }
        }
        
        return r;
    }
    else {
        if (firstLineBox() && firstLineBox()->topOverflow() < 0) {
            int ow = style() ? style()->outlineSize() : 0;
            QRect r(-ow, -ow+firstLineBox()->topOverflow(),
                    overflowWidth(false)+ow*2,
                    overflowHeight(false)+ow*2-firstLineBox()->topOverflow());
            computeAbsoluteRepaintRect(r);
            return r;
        }
    }

    return RenderContainer::getAbsoluteRepaintRect();
}
VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
{
    Position p = visiblePosition.deepEquivalent();
    Node *node = p.node();
    Node* highestRoot = highestEditableRoot(p);
    if (!node)
        return VisiblePosition();
    
    node->document()->updateLayoutIgnorePendingStylesheets();

    RenderObject *renderer = node->renderer();
    if (!renderer)
        return VisiblePosition();

    RenderBlock *containingBlock = 0;
    RootInlineBox *root = 0;
    InlineBox* box;
    int ignoredCaretOffset;
    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
    if (box) {
        root = box->root()->nextRootBox();
        if (root)
            containingBlock = renderer->containingBlock();
    }

    if (!root) {
        // This containing editable block does not have a next line.
        // Need to move forward to next containing editable block in this root editable
        // block and find the first root line box in that block.
        Node* startBlock = enclosingNodeWithNonInlineRenderer(node);
        Node* n = nextLeafWithSameEditability(node, p.deprecatedEditingOffset());
        while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
            n = nextLeafWithSameEditability(n);
        while (n) {
            if (highestEditableRoot(Position(n, 0)) != highestRoot)
                break;
            Position pos(n, caretMinOffset(n));
            if (pos.isCandidate()) {
                ASSERT(n->renderer());
                pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
                if (box) {
                    // next root line box found
                    root = box->root();
                    containingBlock = n->renderer()->containingBlock();
                    break;
                }

                return VisiblePosition(pos, DOWNSTREAM);
            }
            n = nextLeafWithSameEditability(n);
        }
    }
    
    if (root) {
        // FIXME: Can be wrong for multi-column layout and with transforms.
        FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
        if (containingBlock->hasOverflowClip())
            absPos -= containingBlock->layer()->scrolledContentOffset();
        RenderObject* renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->renderer();
        Node* node = renderer->node();
        if (node && editingIgnoresContent(node))
            return Position(node->parent(), node->nodeIndex());
        return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
    }    

    // Could not find a next line. This means we must already be on the last line.
    // Move to the end of the content in this block, which effectively moves us
    // to the end of the line we're on.
    Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
    return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
}
Beispiel #5
0
int Frame::checkOverflowScroll(OverflowScrollAction action)
{
    Position extent = selection().selection().extent();
    if (extent.isNull())
        return OverflowScrollNone;

    RenderObject* renderer = extent.deprecatedNode()->renderer();
    if (!renderer)
        return OverflowScrollNone;

    FrameView* view = this->view();
    if (!view)
        return OverflowScrollNone;

    RenderBlock* containingBlock = renderer->containingBlock();
    if (!containingBlock || !containingBlock->hasOverflowClip())
        return OverflowScrollNone;
    RenderLayer* layer = containingBlock->layer();
    ASSERT(layer);

    IntRect visibleRect = IntRect(view->scrollX(), view->scrollY(), view->visibleWidth(), view->visibleHeight());
    IntPoint position = m_overflowAutoScrollPos;
    if (visibleRect.contains(position.x(), position.y()))
        return OverflowScrollNone;

    int scrollType = 0;
    int deltaX = 0;
    int deltaY = 0;
    IntPoint selectionPosition;

    // This constant will make the selection draw a little bit beyond the edge of the visible area.
    // This prevents a visual glitch, in that you can fail to select a portion of a character that
    // is being rendered right at the edge of the visible rectangle.
    // FIXME: This probably needs improvement, and may need to take the font size into account.
    static const int scrollBoundsAdjustment = 3;

    // FIXME: Make a small buffer at the end of a visible rectangle so that autoscrolling works 
    // even if the visible extends to the limits of the screen.
    if (position.x() < visibleRect.x()) {
        scrollType |= OverflowScrollLeft;
        if (action == PerformOverflowScroll) {
            deltaX -= static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setX(view->scrollX() - scrollBoundsAdjustment);
        }
    } else if (position.x() > visibleRect.maxX()) {
        scrollType |= OverflowScrollRight;
        if (action == PerformOverflowScroll) {
            deltaX += static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setX(view->scrollX() + view->visibleWidth() + scrollBoundsAdjustment);
        }
    }

    if (position.y() < visibleRect.y()) {
        scrollType |= OverflowScrollUp;
        if (action == PerformOverflowScroll) {
            deltaY -= static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setY(view->scrollY() - scrollBoundsAdjustment);
        }
    } else if (position.y() > visibleRect.maxY()) {
        scrollType |= OverflowScrollDown;
        if (action == PerformOverflowScroll) {
            deltaY += static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setY(view->scrollY() + view->visibleHeight() + scrollBoundsAdjustment);
        }
    }

    Ref<Frame> protectedThis(*this);

    if (action == PerformOverflowScroll && (deltaX || deltaY)) {
        layer->scrollToOffset(layer->scrollOffset() + IntSize(deltaX, deltaY));

        // Handle making selection.
        VisiblePosition visiblePosition(renderer->positionForPoint(selectionPosition, nullptr));
        if (visiblePosition.isNotNull()) {
            VisibleSelection visibleSelection = selection().selection();
            visibleSelection.setExtent(visiblePosition);
            if (selection().granularity() != CharacterGranularity)
                visibleSelection.expandUsingGranularity(selection().granularity());
            if (selection().shouldChangeSelection(visibleSelection))
                selection().setSelection(visibleSelection);
        }

        m_overflowAutoScrollDelta *= 1.02f; // Accelerate the scroll
    }
    return scrollType;
}
Beispiel #6
0
VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
{
    Position p = visiblePosition.deepEquivalent();
    Node *node = p.node();
    Node* highestRoot = highestEditableRoot(p);
    if (!node)
        return VisiblePosition();
    
    node->document()->updateLayoutIgnorePendingStylesheets();
    
    RenderObject *renderer = node->renderer();
    if (!renderer)
        return VisiblePosition();

    RenderBlock *containingBlock = 0;
    RootInlineBox *root = 0;
    InlineBox* box;
    int ignoredCaretOffset;
    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
    if (box) {
        root = box->root()->prevRootBox();
        if (root)
            containingBlock = renderer->containingBlock();
    }

    if (!root) {
        // This containing editable block does not have a previous line.
        // Need to move back to previous containing editable block in this root editable
        // block and find the last root line box in that block.
        Node* startBlock = enclosingBlock(node);
        Node* n = previousLeafWithSameEditability(node);
        while (n && startBlock == enclosingBlock(n))
            n = previousLeafWithSameEditability(n);
        while (n) {
            if (highestEditableRoot(Position(n, 0)) != highestRoot)
                break;
            Position pos(n, caretMinOffset(n));
            if (pos.isCandidate()) {
                ASSERT(n->renderer());
                Position maxPos(n, caretMaxOffset(n));
                maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
                if (box) {
                    // previous root line box found
                    root = box->root();
                    containingBlock = n->renderer()->containingBlock();
                    break;
                }

                return VisiblePosition(pos, DOWNSTREAM);
            }
            n = previousLeafWithSameEditability(n);
        }
    }
    
    if (root) {
        // FIXME: Can be wrong for multi-column layout.
        int absx, absy;
        containingBlock->absolutePositionForContent(absx, absy);
        if (containingBlock->hasOverflowClip())
            containingBlock->layer()->subtractScrollOffset(absx, absy);
        RenderObject *renderer = root->closestLeafChildForXPos(x - absx, isEditablePosition(p))->object();
        Node* node = renderer->element();
        if (editingIgnoresContent(node))
            return Position(node->parent(), node->nodeIndex());
        return renderer->positionForCoordinates(x - absx, root->topOverflow());
    }
    
    // Could not find a previous line. This means we must already be on the first line.
    // Move to the start of the content in this block, which effectively moves us
    // to the start of the line we're on.
    Node* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
    return VisiblePosition(rootElement, 0, DOWNSTREAM);
}