// Abs x/y position of the caret ignoring transforms. // TODO(yosin) navigation with transforms should be smarter. static LayoutUnit lineDirectionPointForBlockDirectionNavigationOf( const VisiblePosition& visiblePosition) { if (visiblePosition.isNull()) return LayoutUnit(); LayoutObject* layoutObject; LayoutRect localRect = localCaretRectOfPosition( visiblePosition.toPositionWithAffinity(), layoutObject); if (localRect.isEmpty() || !layoutObject) return LayoutUnit(); // This ignores transforms on purpose, for now. Vertical navigation is done // without consulting transforms, so that 'up' in transformed text is 'up' // relative to the text, not absolute 'up'. FloatPoint caretPoint = layoutObject->localToAbsolute(FloatPoint(localRect.location())); LayoutObject* containingBlock = layoutObject->containingBlock(); if (!containingBlock) { // Just use ourselves to determine the writing mode if we have no containing // block. containingBlock = layoutObject; } return LayoutUnit(containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y()); }
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; }
void CaretBase::updateCaretRect(const PositionWithAffinity& caretPosition) { m_caretLocalRect = LayoutRect(); if (caretPosition.isNull()) return; DCHECK(caretPosition.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). LayoutBlockItem caretPainterItem = LayoutBlockItem(caretLayoutObject(caretPosition.anchorNode())); mapCaretRectToCaretPainter(LayoutItem(layoutObject), caretPainterItem, m_caretLocalRect); }
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; }
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; }