PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) { if (!renderView()) return nullptr; HitTestResult result = hitTestInDocument(this, x, y); RenderObject* renderer = result.renderer(); if (!renderer) return nullptr; PositionWithAffinity positionWithAffinity = result.position(); if (positionWithAffinity.position().isNull()) return nullptr; Position rangeCompliantPosition = positionWithAffinity.position().parentAnchoredEquivalent(); return Range::create(*this, rangeCompliantPosition, rangeCompliantPosition); }
bool CaretBase::updateCaretRect(const PositionWithAffinity& caretPosition) { m_caretLocalRect = LayoutRect(); if (caretPosition.position().isNull()) return false; ASSERT(caretPosition.position().anchorNode()->layoutObject()); // First compute a rect local to the layoutObject at the selection start. LayoutObject* layoutObject; m_caretLocalRect = localCaretRectOfPosition(caretPosition, layoutObject); // Get the layoutObject that will be responsible for painting the caret // (which is either the layoutObject we just found, or one of its containers). LayoutBlock* caretPainter = caretLayoutObject(caretPosition.position().anchorNode()); mapCaretRectToCaretPainter(layoutObject, caretPainter, m_caretLocalRect); return true; }
PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) { if (!renderView()) return nullptr; HitTestResult result = hitTestInDocument(this, x, y); RenderObject* renderer = result.renderer(); if (!renderer) return nullptr; Node* node = renderer->node(); Node* shadowAncestorNode = ancestorInThisScope(node); if (shadowAncestorNode != node) { unsigned offset = shadowAncestorNode->nodeIndex(); ContainerNode* container = shadowAncestorNode->parentNode(); return Range::create(*this, container, offset, container, offset); } PositionWithAffinity positionWithAffinity = result.position(); if (positionWithAffinity.position().isNull()) return nullptr; Position rangeCompliantPosition = positionWithAffinity.position().parentAnchoredEquivalent(); return Range::create(*this, rangeCompliantPosition, rangeCompliantPosition); }
bool CaretBase::updateCaretRect(Document* document, const PositionWithAffinity& caretPosition) { m_caretLocalRect = LayoutRect(); m_caretRectNeedsUpdate = false; if (caretPosition.position().isNull()) return false; ASSERT(caretPosition.position().deprecatedNode()->renderer()); // First compute a rect local to the renderer at the selection start. RenderObject* renderer; LayoutRect localRect = localCaretRectOfPosition(caretPosition, renderer); // Get the renderer that will be responsible for painting the caret // (which is either the renderer we just found, or one of its containers). RenderBlock* caretPainter = caretRenderer(caretPosition.position().deprecatedNode()); // Compute an offset between the renderer and the caretPainter. bool unrooted = false; while (renderer != caretPainter) { RenderObject* containerObject = renderer->container(); if (!containerObject) { unrooted = true; break; } localRect.move(renderer->offsetFromContainer(containerObject, localRect.location())); renderer = containerObject; } if (!unrooted) m_caretLocalRect = localRect; return true; }
void FrameCaret::invalidateCaretRect(bool forceInvalidation) { if (!m_caretRectDirty) return; m_caretRectDirty = false; DCHECK(caretPositionIsValidForDocument(*m_frame->document())); LayoutObject* layoutObject = nullptr; LayoutRect newRect; PositionWithAffinity currentCaretPosition = caretPosition(); if (isActive()) newRect = localCaretRectOfPosition(currentCaretPosition, layoutObject); Node* newNode = layoutObject ? layoutObject->node() : nullptr; // The current selected node |newNode| could be a child multiple levels below // its associated "anchor node" ancestor, so we reference and keep around the // anchor node for checking editability. // TODO(wkorman): Consider storing previous Position, rather than Node, and // making use of EditingUtilies::isEditablePosition() directly. Node* newAnchorNode = currentCaretPosition.position().parentAnchoredEquivalent().anchorNode(); if (newNode && newAnchorNode && newNode != newAnchorNode && newAnchorNode->layoutObject() && newAnchorNode->layoutObject()->isBox()) { newNode->layoutObject()->mapToVisualRectInAncestorSpace( toLayoutBoxModelObject(newAnchorNode->layoutObject()), newRect); } // It's possible for the timer to be inactive even though we want to // invalidate the caret. For example, when running as a layout test the // caret blink interval could be zero and thus |m_caretBlinkTimer| will // never be started. We provide |forceInvalidation| for use by paint // invalidation internals where we need to invalidate the caret regardless // of timer state. if (!forceInvalidation && !m_caretBlinkTimer.isActive() && newNode == m_previousCaretNode && newRect == m_previousCaretRect && m_caretVisibility == m_previousCaretVisibility) return; if (m_previousCaretAnchorNode && shouldRepaintCaret(*m_previousCaretAnchorNode)) { invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), m_previousCaretRect); } if (newAnchorNode && shouldRepaintCaret(*newAnchorNode)) invalidateLocalCaretRect(newAnchorNode, newRect); m_previousCaretNode = newNode; m_previousCaretAnchorNode = newAnchorNode; m_previousCaretRect = newRect; m_previousCaretVisibility = m_caretVisibility; }
VisiblePosition::VisiblePosition(const PositionWithAffinity& positionWithAffinity) { init(positionWithAffinity.position(), positionWithAffinity.affinity()); }