/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CaretAssociationHint.h" #include "mozilla/RangeBoundary.h" // for RangeBoundaryBase #include "mozilla/SelectionMovementUtils.h" // for CaretFrameData #include "mozilla/intl/BidiEmbeddingLevel.h" // for BidiEmbeddingLevel #include "nsCaret.h" // for nsCaret #include "nsIContent.h" // for nsIContent #include "nsIFrame.h" // for nsIFrame #include "nsTextFrame.h" // for nsTextFrame namespace mozilla { template CaretAssociationHint ComputeCaretAssociationHint( CaretAssociationHint aDefault, intl::BidiEmbeddingLevel aBidiLevel, const RangeBoundary& aCaretPoint); template CaretAssociationHint ComputeCaretAssociationHint( CaretAssociationHint aDefault, intl::BidiEmbeddingLevel aBidiLevel, const RawRangeBoundary& aCaretPoint); template CaretAssociationHint ComputeCaretAssociationHint( CaretAssociationHint aDefault, intl::BidiEmbeddingLevel aBidiLevel, const RangeBoundaryBase& aCaretPoint) { MOZ_ASSERT(aCaretPoint.IsSetAndValid()); if (aDefault != CaretAssociationHint::Before || !aCaretPoint.GetContainer()->IsContent()) { return aDefault; } const nsCaret::CaretPosition pos{ aCaretPoint.GetContainer(), static_cast(*aCaretPoint.Offset( RangeBoundaryBase::OffsetFilter::kValidOffsets)), aDefault, aBidiLevel}; CaretFrameData frameData = nsCaret::GetFrameAndOffset(pos); nsTextFrame* f = do_QueryFrame(frameData.mFrame); if (f && f->IsAtEndOfLine() && f->HasSignificantTerminalNewline()) { // RangeBoundaryBase::Offset() causes computing offset if it's not // been done yet. However, it's called only when the container is a text // node. In such case, offset has always been set since it cannot have // any children. So, this doesn't cause computing offset with expensive // method, nsINode::ComputeIndexOf(). const bool caretPointIsAtEndOfFrame = aCaretPoint.GetContainer() == f->GetContent() && f->GetContentEnd() == static_cast(*aCaretPoint.Offset( RangeBoundaryBase::OffsetFilter::kValidOffsets)); const bool caretPointIsImmediatelyAfterFrameContent = aCaretPoint.GetContainer() == f->GetContent()->GetParentNode() && f->GetContent() == aCaretPoint.GetPreviousSiblingOfChildAtOffset(); if (caretPointIsAtEndOfFrame || caretPointIsImmediatelyAfterFrameContent) { return CaretAssociationHint::After; } } return frameData.mFrame ? frameData.mHint : aDefault; } } // namespace mozilla