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; }
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); }
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); }
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; }
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); }