mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 1062735 - Part 4: Support non-editable fields for selection carets. r=roc
This commit is contained in:
parent
cadcb883aa
commit
42158b0719
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user