Bug 1062735 - Part 4: Support non-editable fields for selection carets. r=roc

This commit is contained in:
Morris Tseng 2014-10-16 23:17:00 +02:00
parent cadcb883aa
commit 42158b0719
2 changed files with 119 additions and 89 deletions

View File

@ -13,6 +13,7 @@
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsDOMTokenList.h"
#include "nsFocusManager.h"
#include "nsFrame.h"
#include "nsIDocument.h"
#include "nsIDocShell.h"
@ -330,7 +331,6 @@ FindFirstNodeWithFrame(nsIDocument* aDocument,
int32_t offset = aBackward ? aRange->EndOffset() : aRange->StartOffset();
nsCOMPtr<nsIContent> startContent = do_QueryInterface(startNode);
nsCOMPtr<nsIContent> endContent = do_QueryInterface(endNode);
CaretAssociationHint hintStart =
aBackward ? CARET_ASSOCIATE_BEFORE : CARET_ASSOCIATE_AFTER;
nsIFrame* startFrame = aFrameSelection->GetFrameForNodeOffset(startContent,
@ -360,6 +360,11 @@ FindFirstNodeWithFrame(nsIDocument* aDocument,
} else {
startNode = walker->NextNode(err);
}
if (!startNode) {
break;
}
startContent = do_QueryInterface(startNode);
startFrame = startContent ? startContent->GetPrimaryFrame() : nullptr;
}
@ -373,13 +378,12 @@ SelectionCarets::UpdateSelectionCarets()
return;
}
nsISelection* caretSelection = GetSelection();
if (!caretSelection) {
nsRefPtr<dom::Selection> selection = GetSelection();
if (!selection) {
SetVisibility(false);
return;
}
nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
if (selection->GetRangeCount() <= 0) {
SetVisibility(false);
return;
@ -404,30 +408,8 @@ SelectionCarets::UpdateSelectionCarets()
return;
}
// Check if caret inside the scroll frame's boundary
nsIFrame* caretFocusFrame = GetCaretFocusFrame();
if (!caretFocusFrame) {
SetVisibility(false);
return;
}
nsIContent *editableAncestor = caretFocusFrame->GetContent()->GetEditingHost();
if (!editableAncestor) {
SetVisibility(false);
return;
}
nsRect resultRect;
for (nsIFrame* frame = editableAncestor->GetPrimaryFrame();
frame != nullptr;
frame = frame->GetNextContinuation()) {
nsRect rect = frame->GetRectRelativeToSelf();
nsLayoutUtils::TransformRect(frame, rootFrame, rect);
resultRect = resultRect.Union(rect);
}
// Check start and end frame is rtl or ltr text
nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
int32_t startOffset;
nsIFrame* startFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
range, fs, false, startOffset);
@ -441,6 +423,14 @@ SelectionCarets::UpdateSelectionCarets()
return;
}
// If frame isn't editable and we don't support non-editable fields, bail
// out.
if (!kSupportNonEditableFields &&
(!startFrame->GetContent()->IsEditable() ||
!endFrame->GetContent()->IsEditable())) {
return;
}
// Check if startFrame is after endFrame.
if (nsLayoutUtils::CompareTreePosition(startFrame, endFrame) > 0) {
SetVisibility(false);
@ -458,12 +448,28 @@ SelectionCarets::UpdateSelectionCarets()
// rect's rightmost position, otherwise, put it to last rect's leftmost.
ReduceRectToVerticalEdge(collector.mLastRect, !endFrameIsRTL);
SetStartFrameVisibility(resultRect.Intersects(collector.mFirstRect));
SetEndFrameVisibility(resultRect.Intersects(collector.mLastRect));
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mFirstRect);
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mLastRect);
nsAutoTArray<nsIFrame*, 16> hitFramesInFirstRect;
nsLayoutUtils::GetFramesForArea(canvasFrame,
collector.mFirstRect,
hitFramesInFirstRect,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
nsAutoTArray<nsIFrame*, 16> hitFramesInLastRect;
nsLayoutUtils::GetFramesForArea(canvasFrame,
collector.mLastRect,
hitFramesInLastRect,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
SetStartFrameVisibility(hitFramesInFirstRect.Contains(startFrame));
SetEndFrameVisibility(hitFramesInLastRect.Contains(endFrame));
SetStartFramePos(collector.mFirstRect.BottomLeft());
SetEndFramePos(collector.mLastRect.BottomRight());
SetVisibility(true);
@ -514,11 +520,6 @@ SelectionCarets::UpdateSelectionCarets()
nsresult
SelectionCarets::SelectWord()
{
// If caret isn't visible, the word is not selectable
if (!GetCaretVisible()) {
return NS_OK;
}
if (!mPresShell) {
return NS_OK;
}
@ -535,12 +536,33 @@ SelectionCarets::SelectWord()
return NS_OK;
}
// If frame isn't editable and we don't support non-editable fields, bail
// out.
if (!kSupportNonEditableFields && !ptFrame->GetContent()->IsEditable()) {
return NS_OK;
}
nsPoint ptInFrame = mDownPoint;
nsLayoutUtils::TransformPoint(canvasFrame, ptFrame, ptInFrame);
nsIFrame* caretFocusFrame = GetCaretFocusFrame();
if (!caretFocusFrame) {
return NS_OK;
// If target frame is editable, we should move focus to targe frame. If
// target frame isn't editable and our focus content is editable, we should
// clear focus.
nsFocusManager* fm = nsFocusManager::GetFocusManager();
nsIContent* editingHost = ptFrame->GetContent()->GetEditingHost();
if (editingHost) {
nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(editingHost->GetParent());
if (elt) {
fm->SetFocus(elt, 0);
}
} else {
nsIContent* focusedContent = GetFocusedContent();
if (focusedContent && focusedContent->GetTextEditorRootContent()) {
nsIDOMWindow* win = mPresShell->GetDocument()->GetWindow();
if (win) {
fm->ClearFocus(win);
}
}
}
SetSelectionDragState(true);
@ -550,7 +572,7 @@ SelectionCarets::SelectWord()
SetSelectionDragState(false);
// Clear maintain selection otherwise we cannot select less than a word
nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
fs->MaintainSelection();
return rs;
}
@ -640,12 +662,7 @@ SelectionCarets::DragSelection(const nsPoint &movePoint)
return nsEventStatus_eConsumeNoDefault;
}
nsIFrame* caretFocusFrame = GetCaretFocusFrame();
if (!caretFocusFrame) {
return nsEventStatus_eConsumeNoDefault;
}
nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
nsresult result;
nsIFrame *newFrame = nullptr;
@ -657,14 +674,19 @@ SelectionCarets::DragSelection(const nsPoint &movePoint)
return nsEventStatus_eConsumeNoDefault;
}
bool selectable;
newFrame->IsSelectable(&selectable, nullptr);
if (!selectable) {
return nsEventStatus_eConsumeNoDefault;
}
nsFrame::ContentOffsets offsets =
newFrame->GetContentOffsetsFromPoint(newPoint);
if (!offsets.content) {
return nsEventStatus_eConsumeNoDefault;
}
nsISelection* caretSelection = GetSelection();
nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
nsRefPtr<dom::Selection> selection = GetSelection();
if (selection->GetRangeCount() <= 0) {
return nsEventStatus_eConsumeNoDefault;
}
@ -674,9 +696,15 @@ SelectionCarets::DragSelection(const nsPoint &movePoint)
return nsEventStatus_eConsumeNoDefault;
}
nsIFrame* anchorFrame;
selection->GetPrimaryFrameForAnchorNode(&anchorFrame);
if (!anchorFrame) {
return nsEventStatus_eConsumeNoDefault;
}
// Move caret postion.
nsIFrame *scrollable =
nsLayoutUtils::GetClosestFrameOfType(caretFocusFrame, nsGkAtoms::scrollFrame);
nsLayoutUtils::GetClosestFrameOfType(anchorFrame, nsGkAtoms::scrollFrame);
nsWeakFrame weakScrollable = scrollable;
fs->HandleClick(offsets.content, offsets.StartOffset(),
offsets.EndOffset(),
@ -701,18 +729,18 @@ nscoord
SelectionCarets::GetCaretYCenterPosition()
{
nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
nsIFrame* caretFocusFrame = GetCaretFocusFrame();
if (!canvasFrame || !caretFocusFrame) {
if (!canvasFrame) {
return 0;
}
nsISelection* caretSelection = GetSelection();
nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
nsRefPtr<dom::Selection> selection = GetSelection();
if (selection->GetRangeCount() <= 0) {
return 0;
}
nsRefPtr<nsRange> range = selection->GetRangeAt(0);
nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
MOZ_ASSERT(mDragMode != NONE);
nsCOMPtr<nsIContent> node;
@ -742,20 +770,14 @@ SelectionCarets::GetCaretYCenterPosition()
void
SelectionCarets::SetSelectionDragState(bool aState)
{
nsIFrame* caretFocusFrame = GetCaretFocusFrame();
if (!caretFocusFrame) {
return;
}
nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
fs->SetDragState(aState);
}
void
SelectionCarets::SetSelectionDirection(bool aForward)
{
nsISelection* caretSelection = GetSelection();
nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
nsRefPtr<dom::Selection> selection = GetSelection();
selection->SetDirection(aForward ? eDirNext : eDirPrevious);
}
@ -820,38 +842,40 @@ SelectionCarets::GetEndFrameRect()
return nsLayoutUtils::GetRectRelativeToFrame(element, canvasFrame);
}
nsIFrame*
SelectionCarets::GetCaretFocusFrame()
nsIContent*
SelectionCarets::GetFocusedContent()
{
nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
if (!caret) {
return nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
return fm->GetFocusedContent();
}
nsRect focusRect;
return caret->GetGeometry(&focusRect);
return nullptr;
}
bool
SelectionCarets::GetCaretVisible()
{
if (!mPresShell) {
return false;
}
nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
if (!caret) {
return false;
}
return caret->IsVisible();
}
nsISelection*
Selection*
SelectionCarets::GetSelection()
{
nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
return caret->GetSelection();
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
if (fs) {
return fs->GetSelection(nsISelectionController::SELECTION_NORMAL);
}
return nullptr;
}
already_AddRefed<nsFrameSelection>
SelectionCarets::GetFrameSelection()
{
nsIContent* focusNode = GetFocusedContent();
if (focusNode) {
nsIFrame* focusFrame = focusNode->GetPrimaryFrame();
if (!focusFrame) {
return nullptr;
}
return focusFrame->GetFrameSelection();
} else {
return mPresShell->FrameSelection();
}
}
nsresult

View File

@ -15,6 +15,8 @@
#include "mozilla/EventForwards.h"
class nsCanvasFrame;
class nsFrameSelection;
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsIPresShell;
@ -24,6 +26,10 @@ class nsPresContext;
namespace mozilla {
namespace dom {
class Selection;
}
/**
* The SelectionCarets draw a pair of carets when the selection is not
* collapsed, one at each end of the selection.
@ -182,9 +188,9 @@ private:
void SetTilted(bool aIsTilt);
// Utility function
nsIFrame* GetCaretFocusFrame();
bool GetCaretVisible();
nsISelection* GetSelection();
dom::Selection* GetSelection();
already_AddRefed<nsFrameSelection> GetFrameSelection();
nsIContent* GetFocusedContent();
/**
* Detecting long tap using timer