Bug 1213589 part.2 Clean up GenerateFlatTextContent(), GelerateFlatFontRanges() and GetFlatTextOffsetOfRange() of ContentEventHandler r=smaug

This commit is contained in:
Masayuki Nakano 2015-12-02 13:20:00 +09:00
Родитель 1b1d719d0f
Коммит 18395c1495
4 изменённых файлов: 242 добавлений и 129 удалений

Просмотреть файл

@ -407,37 +407,41 @@ static uint32_t ConvertToXPOffset(nsIContent* aContent, uint32_t aNativeOffset)
#endif
}
static nsresult GenerateFlatTextContent(nsRange* aRange,
nsAFlatString& aString,
LineBreakType aLineBreakType)
nsresult
ContentEventHandler::GenerateFlatTextContent(nsRange* aRange,
nsAFlatString& aString,
LineBreakType aLineBreakType)
{
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
iter->Init(aRange);
NS_ASSERTION(aString.IsEmpty(), "aString must be empty string");
nsINode* startNode = aRange->GetStartParent();
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
nsINode* endNode = aRange->GetEndParent();
NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
return NS_ERROR_FAILURE;
}
if (startNode == endNode && startNode->IsNodeOfType(nsINode::eTEXT)) {
nsIContent* content = static_cast<nsIContent*>(startNode);
nsIContent* content = startNode->AsContent();
AppendSubString(aString, content, aRange->StartOffset(),
aRange->EndOffset() - aRange->StartOffset());
ConvertToNativeNewlines(aString);
return NS_OK;
}
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
nsresult rv = iter->Init(aRange);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
for (; !iter->IsDone(); iter->Next()) {
nsINode* node = iter->GetCurrentNode();
if (!node) {
if (NS_WARN_IF(!node)) {
break;
}
if (!node->IsNodeOfType(nsINode::eCONTENT)) {
if (!node->IsContent()) {
continue;
}
nsIContent* content = static_cast<nsIContent*>(node);
nsIContent* content = node->AsContent();
if (content->IsNodeOfType(nsINode::eTEXT)) {
if (content == startNode) {
@ -578,14 +582,18 @@ ContentEventHandler::GenerateFlatFontRanges(nsRange* aRange,
nsINode* startNode = aRange->GetStartParent();
nsINode* endNode = aRange->GetEndParent();
if (NS_WARN_IF(!startNode || !endNode)) {
if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
return NS_ERROR_FAILURE;
}
// baseOffset is the flattened offset of each content node.
int32_t baseOffset = 0;
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
for (iter->Init(aRange); !iter->IsDone(); iter->Next()) {
nsresult rv = iter->Init(aRange);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
for (; !iter->IsDone(); iter->Next()) {
nsINode* node = iter->GetCurrentNode();
if (NS_WARN_IF(!node)) {
break;
@ -690,20 +698,22 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
nsresult rv = iter->Init(mRootContent);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
uint32_t offset = 0;
uint32_t endOffset = aOffset + aLength;
bool startSet = false;
for (; !iter->IsDone(); iter->Next()) {
nsINode* node = iter->GetCurrentNode();
if (!node) {
if (NS_WARN_IF(!node)) {
break;
}
if (!node->IsNodeOfType(nsINode::eCONTENT)) {
if (!node->IsContent()) {
continue;
}
nsIContent* content = static_cast<nsIContent*>(node);
nsIContent* content = node->AsContent();
uint32_t textLength =
content->IsNodeOfType(nsINode::eTEXT) ?
@ -722,25 +732,31 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
if (aLineBreakType == LINE_BREAK_TYPE_NATIVE) {
xpOffset = ConvertToXPOffset(content, xpOffset);
}
}
if (aExpandToClusterBoundaries) {
uint32_t oldXPOffset = xpOffset;
rv = ExpandToClusterBoundary(content, false, &xpOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (aNewOffset) {
// This is correct since a cluster shouldn't include line break.
*aNewOffset -= (oldXPOffset - xpOffset);
if (aExpandToClusterBoundaries) {
uint32_t oldXPOffset = xpOffset;
rv = ExpandToClusterBoundary(content, false, &xpOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aNewOffset) {
// This is correct since a cluster shouldn't include line break.
*aNewOffset -= (oldXPOffset - xpOffset);
}
}
}
rv = aRange->SetStart(content, int32_t(xpOffset));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
startSet = true;
if (aLength == 0) {
// Ensure that the end offset and the start offset are same.
rv = aRange->SetEnd(content, int32_t(xpOffset));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
}
@ -754,7 +770,9 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
}
if (aExpandToClusterBoundaries) {
rv = ExpandToClusterBoundary(content, true, &xpOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
} else {
// Use first position of next node, because the end node is ignored
@ -768,7 +786,9 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
}
rv = aRange->SetEnd(endNode, int32_t(xpOffset));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
@ -782,14 +802,18 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
if (!startSet) {
MOZ_ASSERT(!mRootContent->IsNodeOfType(nsINode::eTEXT));
rv = aRange->SetStart(mRootContent, int32_t(mRootContent->GetChildCount()));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aNewOffset) {
*aNewOffset = offset;
}
}
rv = aRange->SetEnd(mRootContent, int32_t(mRootContent->GetChildCount()));
NS_ASSERTION(NS_SUCCEEDED(rv), "nsRange::SetEnd failed");
return rv;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
/* static */ LineBreakType
@ -868,8 +892,8 @@ ContentEventHandler::OnQuerySelectedText(WidgetQueryContentEvent* aEvent)
"The reply string must be empty");
LineBreakType lineBreakType = GetLineBreakType(aEvent);
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange,
&aEvent->mReply.mOffset, lineBreakType);
rv = GetFlatTextLengthBefore(mFirstSelectedRange,
&aEvent->mReply.mOffset, lineBreakType);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> anchorNode, focusNode;
@ -1140,8 +1164,8 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
if (caretFrame) {
uint32_t offset;
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset,
lineBreakType);
rv = GetFlatTextLengthBefore(mFirstSelectedRange,
&offset, lineBreakType);
NS_ENSURE_SUCCESS(rv, rv);
if (offset == aEvent->mInput.mOffset) {
rv = ConvertToRootRelativeOffset(caretFrame, caretRect);
@ -1320,8 +1344,9 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent)
return NS_OK;
}
rv = GetFlatTextOffsetOfRange(mRootContent, tentativeCaretOffsets.content,
tentativeCaretOffsets.offset,
rv = GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
NodePosition(tentativeCaretOffsets),
mRootContent,
&aEvent->mReply.mTentativeCaretOffset,
GetLineBreakType(aEvent));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1344,10 +1369,13 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent)
textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
NS_ENSURE_TRUE(contentOffsets.content, NS_ERROR_FAILURE);
uint32_t offset;
rv = GetFlatTextOffsetOfRange(mRootContent, contentOffsets.content,
contentOffsets.offset, &offset,
rv = GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
NodePosition(contentOffsets),
mRootContent, &offset,
GetLineBreakType(aEvent));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->widget);
textRect.InitForQueryTextRect(offset, 1, aEvent->mUseNativeLineBreak);
@ -1409,76 +1437,89 @@ ContentEventHandler::OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent)
}
/* static */ nsresult
ContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
nsINode* aNode,
int32_t aNodeOffset,
uint32_t* aOffset,
LineBreakType aLineBreakType)
ContentEventHandler::GetFlatTextLengthInRange(
const NodePosition& aStartPosition,
const NodePosition& aEndPosition,
nsIContent* aRootContent,
uint32_t* aLength,
LineBreakType aLineBreakType)
{
NS_ENSURE_STATE(aRootContent);
NS_ASSERTION(aOffset, "param is invalid");
RefPtr<nsRange> prev = new nsRange(aRootContent);
nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(aRootContent));
prev->SetStart(rootDOMNode, 0);
nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(aNode));
NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode");
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
if (aNode->Length() >= static_cast<uint32_t>(aNodeOffset)) {
// Offset is within node's length; set end of range to that offset
prev->SetEnd(startDOMNode, aNodeOffset);
iter->Init(prev);
} else if (aNode != static_cast<nsINode*>(aRootContent)) {
// Offset is past node's length; set end of range to end of node
prev->SetEndAfter(startDOMNode);
iter->Init(prev);
} else {
// Offset is past the root node; set end of range to end of root node
iter->Init(aRootContent);
if (NS_WARN_IF(!aRootContent) || NS_WARN_IF(!aStartPosition.IsValid()) ||
NS_WARN_IF(!aEndPosition.IsValid()) || NS_WARN_IF(!aLength)) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsINode> startNode = do_QueryInterface(startDOMNode);
nsINode* endNode = aNode;
RefPtr<nsRange> prev = new nsRange(aRootContent);
nsresult rv = aStartPosition.SetToRangeStart(prev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
*aOffset = 0;
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
if (aEndPosition.OffsetIsValid()) {
// Offset is within node's length; set end of range to that offset
rv = aEndPosition.SetToRangeEnd(prev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = iter->Init(prev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else if (aEndPosition.mNode != aRootContent) {
// Offset is past node's length; set end of range to end of node
rv = aEndPosition.SetToRangeEndAfter(prev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = iter->Init(prev);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
// Offset is past the root node; set end of range to end of root node
rv = iter->Init(aRootContent);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
*aLength = 0;
for (; !iter->IsDone(); iter->Next()) {
nsINode* node = iter->GetCurrentNode();
if (!node) {
if (NS_WARN_IF(!node)) {
break;
}
if (!node->IsNodeOfType(nsINode::eCONTENT)) {
if (!node->IsContent()) {
continue;
}
nsIContent* content = static_cast<nsIContent*>(node);
nsIContent* content = node->AsContent();
if (node->IsNodeOfType(nsINode::eTEXT)) {
// Note: our range always starts from offset 0
if (node == endNode) {
*aOffset += GetTextLength(content, aLineBreakType, aNodeOffset);
if (node == aEndPosition.mNode) {
*aLength += GetTextLength(content, aLineBreakType,
aEndPosition.mOffset);
} else {
*aOffset += GetTextLength(content, aLineBreakType);
*aLength += GetTextLength(content, aLineBreakType);
}
} else if (IsContentBR(content)) {
*aOffset += GetBRLength(aLineBreakType);
*aLength += GetBRLength(aLineBreakType);
}
}
return NS_OK;
}
/* static */ nsresult
ContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
nsRange* aRange,
uint32_t* aOffset,
LineBreakType aLineBreakType)
nsresult
ContentEventHandler::GetFlatTextLengthBefore(nsRange* aRange,
uint32_t* aOffset,
LineBreakType aLineBreakType)
{
nsINode* startNode = aRange->GetStartParent();
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
int32_t startOffset = aRange->StartOffset();
return GetFlatTextOffsetOfRange(aRootContent, startNode, startOffset,
aOffset, aLineBreakType);
MOZ_ASSERT(aRange);
return GetFlatTextLengthInRange(
NodePosition(mRootContent, 0),
NodePosition(aRange->GetStartParent(), aRange->StartOffset()),
mRootContent, aOffset, aLineBreakType);
}
nsresult

Просмотреть файл

@ -10,6 +10,8 @@
#include "mozilla/EventForwards.h"
#include "mozilla/dom/Selection.h"
#include "nsCOMPtr.h"
#include "nsIFrame.h"
#include "nsINode.h"
#include "nsRange.h"
class nsPresContext;
@ -81,15 +83,60 @@ public:
// FlatText means the text that is generated from DOM tree. The BR elements
// are replaced to native linefeeds. Other elements are ignored.
// Get the offset in FlatText of the range. (also used by IMEContentObserver)
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
nsINode* aNode,
int32_t aNodeOffset,
uint32_t* aOffset,
LineBreakType aLineBreakType);
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
nsRange* aRange,
uint32_t* aOffset,
// NodePosition stores a pair of node and offset in the node.
// This is useful to receive one or more sets of them instead of nsRange.
struct NodePosition final
{
nsCOMPtr<nsINode> mNode;
int32_t mOffset;
NodePosition()
: mOffset(-1)
{
}
NodePosition(nsINode* aNode, int32_t aOffset)
: mNode(aNode)
, mOffset(aOffset)
{
}
explicit NodePosition(const nsIFrame::ContentOffsets& aContentOffsets)
: mNode(aContentOffsets.content)
, mOffset(aContentOffsets.offset)
{
}
bool IsValid() const
{
return mNode && mOffset >= 0;
}
bool OffsetIsValid() const
{
return IsValid() && static_cast<uint32_t>(mOffset) <= mNode->Length();
}
nsresult SetToRangeStart(nsRange* aRange) const
{
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
return aRange->SetStart(domNode, mOffset);
}
nsresult SetToRangeEnd(nsRange* aRange) const
{
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
return aRange->SetEnd(domNode, mOffset);
}
nsresult SetToRangeEndAfter(nsRange* aRange) const
{
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
return aRange->SetEndAfter(domNode);
}
};
// Get the flatten text length in the range.
static nsresult GetFlatTextLengthInRange(const NodePosition& aStartPosition,
const NodePosition& aEndPosition,
nsIContent* aRootContent,
uint32_t* aLength,
LineBreakType aLineBreakType);
// Computes the native text length between aStartOffset and aEndOffset of
// aContent. aContent must be a text node.
@ -114,6 +161,14 @@ protected:
uint32_t aXPStartOffset,
uint32_t aXPEndOffset,
LineBreakType aLineBreakType);
// Get the contents of aRange as plain text.
nsresult GenerateFlatTextContent(nsRange* aRange,
nsAFlatString& aString,
LineBreakType aLineBreakType);
// Get the text length before the start position of aRange.
nsresult GetFlatTextLengthBefore(nsRange* aRange,
uint32_t* aOffset,
LineBreakType aLineBreakType);
// Get the line breaker length.
static inline uint32_t GetBRLength(LineBreakType aLineBreakType);
static LineBreakType GetLineBreakType(WidgetQueryContentEvent* aEvent);

Просмотреть файл

@ -876,11 +876,15 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
uint32_t offset = 0;
// get offsets of change and fire notification
nsresult rv =
ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContent,
aInfo->mChangeStart,
&offset,
LINE_BREAK_TYPE_NATIVE);
NS_ENSURE_SUCCESS_VOID(rv);
ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(mRootContent, 0),
NodePosition(aContent, aInfo->mChangeStart),
mRootContent,
&offset,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
uint32_t newLength =
ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
@ -912,9 +916,11 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
nsresult rv = NS_OK;
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
mEndOfAddedTextCache.Clear();
rv = ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContainer,
aStartIndex, &offset,
LINE_BREAK_TYPE_NATIVE);
rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(mRootContent, 0),
NodePosition(aContainer, aStartIndex),
mRootContent, &offset,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED((rv)))) {
return;
}
@ -923,11 +929,12 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
}
// get offset at the end of the last added node
nsIContent* childAtStart = aContainer->GetChildAt(aStartIndex);
uint32_t addingLength = 0;
rv = ContentEventHandler::GetFlatTextOffsetOfRange(childAtStart, aContainer,
aEndIndex, &addingLength,
LINE_BREAK_TYPE_NATIVE);
rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(aContainer, aStartIndex),
NodePosition(aContainer, aEndIndex),
mRootContent, &addingLength,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED((rv)))) {
mEndOfAddedTextCache.Clear();
return;
@ -988,10 +995,12 @@ IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
uint32_t offset = 0;
nsresult rv = NS_OK;
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) {
rv =
ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, containerNode,
aIndexInContainer, &offset,
LINE_BREAK_TYPE_NATIVE);
rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(mRootContent, 0),
NodePosition(containerNode, aIndexInContainer),
mRootContent,
&offset,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED(rv))) {
mStartOfRemovingTextRangeCache.Clear();
return;
@ -1003,18 +1012,21 @@ IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
}
// get offset at the end of the deleted node
int32_t nodeLength =
aChild->IsNodeOfType(nsINode::eTEXT) ?
static_cast<int32_t>(aChild->TextLength()) :
std::max(static_cast<int32_t>(aChild->GetChildCount()), 1);
MOZ_ASSERT(nodeLength >= 0, "The node length is out of range");
uint32_t textLength = 0;
rv = ContentEventHandler::GetFlatTextOffsetOfRange(aChild, aChild,
nodeLength, &textLength,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED(rv))) {
mStartOfRemovingTextRangeCache.Clear();
return;
if (aChild->IsNodeOfType(nsINode::eTEXT)) {
textLength = ContentEventHandler::GetNativeTextLength(aChild);
} else {
uint32_t nodeLength =
std::max(static_cast<int32_t>(aChild->GetChildCount()), 1);
rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(aChild, 0),
NodePosition(aChild, nodeLength),
mRootContent, &textLength,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED(rv))) {
mStartOfRemovingTextRangeCache.Clear();
return;
}
}
if (!textLength) {
@ -1062,10 +1074,14 @@ IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
}
uint32_t start;
nsresult rv =
ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aElement,
0, &start,
ContentEventHandler::GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
NodePosition(aElement, 0),
mRootContent,
&start,
LINE_BREAK_TYPE_NATIVE);
NS_ENSURE_SUCCESS_VOID(rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
TextChangeData data(start, start + mPreAttrChangeLength,
start + postAttrChangeLength, causedByComposition,

Просмотреть файл

@ -40,6 +40,7 @@ class IMEContentObserver final : public nsISelectionListener
, public nsIEditorObserver
{
public:
typedef ContentEventHandler::NodePosition NodePosition;
typedef widget::IMENotification::SelectionChangeData SelectionChangeData;
typedef widget::IMENotification::TextChangeData TextChangeData;
typedef widget::IMENotification::TextChangeDataBase TextChangeDataBase;