nsresult nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, nsINode* aNode, PRInt32 aNodeOffset, PRUint32* aNativeOffset) { NS_ASSERTION(aNativeOffset, "param is invalid"); nsCOMPtr<nsIRange> prev = new nsRange(); NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr<nsIDOMRange> domPrev(do_QueryInterface(prev)); NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??"); nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(aRootContent)); domPrev->SetStart(rootDOMNode, 0); nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(aNode)); NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode"); domPrev->SetEnd(startDOMNode, aNodeOffset); nsCOMPtr<nsIContentIterator> iter; nsresult rv = NS_NewContentIterator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null"); iter->Init(domPrev); nsCOMPtr<nsINode> startNode = do_QueryInterface(startDOMNode); nsINode* endNode = aNode; *aNativeOffset = 0; for (; !iter->IsDone(); iter->Next()) { nsINode* node = iter->GetCurrentNode(); if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) continue; nsIContent* content = static_cast<nsIContent*>(node); if (node->IsNodeOfType(nsINode::eTEXT)) { // Note: our range always starts from offset 0 if (node == endNode) *aNativeOffset += GetNativeTextLength(content, aNodeOffset); else *aNativeOffset += GetNativeTextLength(content); } else if (IsContentBR(content)) { #if defined(XP_WIN) // On Windows, the length of the newline is 2. *aNativeOffset += 2; #else // On other platforms, the length of the newline is 1. *aNativeOffset += 1; #endif } } return NS_OK; }
nsresult nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, nsINode* aNode, PRInt32 aNodeOffset, PRUint32* aNativeOffset) { NS_ASSERTION(aNativeOffset, "param is invalid"); nsRefPtr<nsRange> prev = new nsRange(); nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(aRootContent)); prev->SetStart(rootDOMNode, 0); nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(aNode)); NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode"); prev->SetEnd(startDOMNode, aNodeOffset); nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator(); iter->Init(prev); nsCOMPtr<nsINode> startNode = do_QueryInterface(startDOMNode); nsINode* endNode = aNode; *aNativeOffset = 0; for (; !iter->IsDone(); iter->Next()) { nsINode* node = iter->GetCurrentNode(); if (!node) break; if (!node->IsNodeOfType(nsINode::eCONTENT)) continue; nsIContent* content = static_cast<nsIContent*>(node); if (node->IsNodeOfType(nsINode::eTEXT)) { // Note: our range always starts from offset 0 if (node == endNode) *aNativeOffset += GetNativeTextLength(content, aNodeOffset); else *aNativeOffset += GetNativeTextLength(content); } else if (IsContentBR(content)) { #if defined(XP_WIN) // On Windows, the length of the newline is 2. *aNativeOffset += 2; #else // On other platforms, the length of the newline is 1. *aNativeOffset += 1; #endif } } return NS_OK; }
static nsresult GenerateFlatTextContent(nsIRange* aRange, nsAFlatString& aString) { nsCOMPtr<nsIContentIterator> iter; nsresult rv = NS_NewContentIterator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null"); nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange)); NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!"); iter->Init(domRange); 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 (startNode == endNode && startNode->IsNodeOfType(nsINode::eTEXT)) { nsIContent* content = static_cast<nsIContent*>(startNode); AppendSubString(aString, content, aRange->StartOffset(), aRange->EndOffset() - aRange->StartOffset()); ConvertToNativeNewlines(aString); return NS_OK; } nsAutoString tmpStr; for (; !iter->IsDone(); iter->Next()) { nsINode* node = iter->GetCurrentNode(); if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) continue; nsIContent* content = static_cast<nsIContent*>(node); if (content->IsNodeOfType(nsINode::eTEXT)) { if (content == startNode) AppendSubString(aString, content, aRange->StartOffset(), content->TextLength() - aRange->StartOffset()); else if (content == endNode) AppendSubString(aString, content, 0, aRange->EndOffset()); else AppendString(aString, content); } else if (IsContentBR(content)) aString.Append(PRUnichar('\n')); } ConvertToNativeNewlines(aString); return NS_OK; }
static nsresult GenerateFlatTextContent(nsRange* aRange, nsAFlatString& aString) { 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 (startNode == endNode && startNode->IsNodeOfType(nsINode::eTEXT)) { nsIContent* content = static_cast<nsIContent*>(startNode); AppendSubString(aString, content, aRange->StartOffset(), aRange->EndOffset() - aRange->StartOffset()); ConvertToNativeNewlines(aString); return NS_OK; } nsAutoString tmpStr; for (; !iter->IsDone(); iter->Next()) { nsINode* node = iter->GetCurrentNode(); if (!node) break; if (!node->IsNodeOfType(nsINode::eCONTENT)) continue; nsIContent* content = static_cast<nsIContent*>(node); if (content->IsNodeOfType(nsINode::eTEXT)) { if (content == startNode) AppendSubString(aString, content, aRange->StartOffset(), content->TextLength() - aRange->StartOffset()); else if (content == endNode) AppendSubString(aString, content, 0, aRange->EndOffset()); else AppendString(aString, content); } else if (IsContentBR(content)) aString.Append(PRUnichar('\n')); } ConvertToNativeNewlines(aString); return NS_OK; }
nsresult nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIRange> range = new nsRange(); if (!range) { return NS_ERROR_OUT_OF_MEMORY; } rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, aEvent->mInput.mLength, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); // used to iterate over all contents and their frames nsCOMPtr<nsIContentIterator> iter; rv = NS_NewContentIterator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); iter->Init(range); NS_ENSURE_SUCCESS(rv, rv); // get the starting frame PRInt32 offset = range->StartOffset(); nsINode* node = iter->GetCurrentNode(); if (!node) { node = AdjustTextRectNode(range->GetStartParent(), offset); } nsIFrame* firstFrame = nsnull; rv = GetFrameForTextRect(node, offset, PR_TRUE, &firstFrame); NS_ENSURE_SUCCESS(rv, rv); // get the starting frame rect nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size()); rv = ConvertToRootViewRelativeOffset(firstFrame, rect); NS_ENSURE_SUCCESS(rv, rv); nsRect frameRect = rect; nsPoint ptOffset; firstFrame->GetPointFromOffset(offset, &ptOffset); // minus 1 to avoid creating an empty rect rect.x += ptOffset.x - 1; rect.width -= ptOffset.x - 1; // get the ending frame offset = range->EndOffset(); node = AdjustTextRectNode(range->GetEndParent(), offset); nsIFrame* lastFrame = nsnull; rv = GetFrameForTextRect(node, offset, range->Collapsed(), &lastFrame); NS_ENSURE_SUCCESS(rv, rv); // iterate over all covered frames for (nsIFrame* frame = firstFrame; frame != lastFrame;) { frame = frame->GetNextContinuation(); if (!frame) { do { iter->Next(); node = iter->GetCurrentNode(); if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) continue; frame = static_cast<nsIContent*>(node)->GetPrimaryFrame(); } while (!frame && !iter->IsDone()); if (!frame) { // this can happen when the end offset of the range is 0. frame = lastFrame; } } frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size()); rv = ConvertToRootViewRelativeOffset(frame, frameRect); NS_ENSURE_SUCCESS(rv, rv); if (frame != lastFrame) { // not last frame, so just add rect to previous result rect.UnionRect(rect, frameRect); } } // get the ending frame rect lastFrame->GetPointFromOffset(offset, &ptOffset); // minus 1 to avoid creating an empty rect frameRect.width -= lastFrame->GetRect().width - ptOffset.x - 1; if (firstFrame == lastFrame) { rect.IntersectRect(rect, frameRect); } else { rect.UnionRect(rect, frameRect); } aEvent->mReply.mRect = rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()); aEvent->mSucceeded = PR_TRUE; return NS_OK; }
nsresult nsContentEventHandler::SetRangeFromFlatTextOffset( nsIRange* aRange, PRUint32 aNativeOffset, PRUint32 aNativeLength, PRBool aExpandToClusterBoundaries) { nsCOMPtr<nsIContentIterator> iter; nsresult rv = NS_NewContentIterator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null"); rv = iter->Init(mRootContent); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange)); NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!"); PRUint32 nativeOffset = 0; PRUint32 nativeEndOffset = aNativeOffset + aNativeLength; nsCOMPtr<nsIContent> content; for (; !iter->IsDone(); iter->Next()) { nsINode* node = iter->GetCurrentNode(); if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) continue; nsIContent* content = static_cast<nsIContent*>(node); PRUint32 nativeTextLength; nativeTextLength = GetNativeTextLength(content); if (nativeTextLength == 0) continue; if (nativeOffset <= aNativeOffset && aNativeOffset < nativeOffset + nativeTextLength) { nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content)); NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!"); PRUint32 xpOffset = content->IsNodeOfType(nsINode::eTEXT) ? ConvertToXPOffset(content, aNativeOffset - nativeOffset) : 0; if (aExpandToClusterBoundaries) { rv = ExpandToClusterBoundary(content, PR_FALSE, &xpOffset); NS_ENSURE_SUCCESS(rv, rv); } rv = domRange->SetStart(domNode, PRInt32(xpOffset)); NS_ENSURE_SUCCESS(rv, rv); if (aNativeLength == 0) { // Ensure that the end offset and the start offset are same. rv = domRange->SetEnd(domNode, PRInt32(xpOffset)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } } if (nativeEndOffset <= nativeOffset + nativeTextLength) { nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content)); NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!"); PRUint32 xpOffset; if (content->IsNodeOfType(nsINode::eTEXT)) { xpOffset = ConvertToXPOffset(content, nativeEndOffset - nativeOffset); if (aExpandToClusterBoundaries) { rv = ExpandToClusterBoundary(content, PR_TRUE, &xpOffset); NS_ENSURE_SUCCESS(rv, rv); } } else { // Use first position of next node, because the end node is ignored // by ContentIterator when the offset is zero. xpOffset = 0; iter->Next(); if (iter->IsDone()) break; domNode = do_QueryInterface(iter->GetCurrentNode()); } rv = domRange->SetEnd(domNode, PRInt32(xpOffset)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nativeOffset += nativeTextLength; } if (nativeOffset < aNativeOffset) return NS_ERROR_FAILURE; nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mRootContent)); NS_ASSERTION(domNode, "lastContent doesn't have nsIDOMNode!"); if (!content) { rv = domRange->SetStart(domNode, 0); NS_ENSURE_SUCCESS(rv, rv); } rv = domRange->SetEnd(domNode, PRInt32(mRootContent->GetChildCount())); NS_ASSERTION(NS_SUCCEEDED(rv), "nsIDOMRange::SetEnd failed"); return rv; }
{ NS_ASSERTION(!mSelection || mEditorBase, "mEditorBase should be non-null when mSelection is"); if (mSelection) { mEditorBase->StopPreservingSelection(); } } /****************************************************************************** * some helper classes for iterating the dom tree *****************************************************************************/ DOMIterator::DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; mIter = NS_NewContentIterator(); DebugOnly<nsresult> rv = mIter->Init(&aNode); MOZ_ASSERT(NS_SUCCEEDED(rv)); } nsresult DOMIterator::Init(nsRange& aRange) { mIter = NS_NewContentIterator(); return mIter->Init(&aRange); } DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; }