Backed out changeset 1575904619b5 (bug 1506547) for mochitest failures on test_reftests_with_caret.html.

This commit is contained in:
Brindusan Cristian 2018-11-26 03:03:14 +02:00
parent b74c31e4d9
commit 31f0c21cca
36 changed files with 338 additions and 442 deletions

View File

@ -547,8 +547,7 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
nsPeekOffsetStruct pos(aAmount, aDirection, innerContentOffset,
nsPoint(0, 0), kIsJumpLinesOk, kIsScrollViewAStop,
kIsKeyboardSelect, kIsVisualBidi,
false, nsPeekOffsetStruct::ForceEditableRegion::No,
aWordMovementType);
false, aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos);
// PeekOffset fails on last/first lines of the text in certain cases.

View File

@ -48,6 +48,10 @@ let whitelist = [
{sourceName: /(?:res|gre-resources)\/forms\.css$/i,
errorMessage: /Error in parsing value for \u2018-moz-appearance\u2019/iu,
isFromDevTools: false},
// -moz-user-select: -moz-text is only enabled to user-agent stylesheets.
{sourceName: /contenteditable.css$/i,
errorMessage: /Error in parsing value for \u2018-moz-user-select\u2019/iu,
isFromDevTools: false},
// These variables are declared somewhere else, and error when we load the
// files directly. They're all marked intermittent because their appearance
// in the error console seems to not be consistent.

View File

@ -1358,6 +1358,7 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"-moz-none",
"-moz-text",
"all",
"auto",
"inherit",
@ -2749,6 +2750,7 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"-moz-none",
"-moz-text",
"all",
"auto",
"inherit",

View File

@ -1639,6 +1639,21 @@ Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements)
}
}
/**
* Returns the count of descendants (inclusive of aContent) in
* the uncomposed document that are explicitly set as editable.
*/
static uint32_t
EditableInclusiveDescendantCount(nsIContent* aContent)
{
auto htmlElem = nsGenericHTMLElement::FromNode(aContent);
if (htmlElem) {
return htmlElem->EditableInclusiveDescendantCount();
}
return aContent->EditableDescendantCount();
}
nsresult
Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent)
@ -1787,6 +1802,8 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
SetDirOnBind(this, aParent);
}
uint32_t editableDescendantCount = 0;
UpdateEditableState(false);
// If we had a pre-existing XBL binding, we might have anonymous children that
@ -1809,6 +1826,30 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
child = child->GetNextSibling()) {
rv = child->BindToTree(aDocument, this, aBindingParent);
NS_ENSURE_SUCCESS(rv, rv);
editableDescendantCount += EditableInclusiveDescendantCount(child);
}
if (aDocument) {
// Update our editable descendant count because we don't keep track of it
// for content that is not in the uncomposed document.
MOZ_ASSERT(EditableDescendantCount() == 0);
ChangeEditableDescendantCount(editableDescendantCount);
if (!hadParent) {
uint32_t editableDescendantChange = EditableInclusiveDescendantCount(this);
if (editableDescendantChange != 0) {
// If we are binding a subtree root to the document, we need to update
// the editable descendant count of all the ancestors.
// But we don't cross Shadow DOM boundary.
// (The expected behavior with Shadow DOM is unclear)
nsIContent* parent = GetParent();
while (parent && parent->IsElement()) {
parent->ChangeEditableDescendantCount(editableDescendantChange);
parent = parent->GetParent();
}
}
}
}
nsNodeUtils::ParentChainChanged(this);
@ -1950,6 +1991,19 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
}
if (aNullParent) {
if (GetParent() && GetParent()->IsInUncomposedDoc()) {
// Update the editable descendant count in the ancestors before we
// lose the reference to the parent.
int32_t editableDescendantChange = -1 * EditableInclusiveDescendantCount(this);
if (editableDescendantChange != 0) {
nsIContent* parent = GetParent();
while (parent) {
parent->ChangeEditableDescendantCount(editableDescendantChange);
parent = parent->GetParent();
}
}
}
if (IsRootOfNativeAnonymousSubtree()) {
nsNodeUtils::NativeAnonymousChildListChange(this, true);
}
@ -2004,6 +2058,10 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
// Editable descendant count only counts descendants that
// are in the uncomposed document.
ResetEditableDescendantCount();
if (aNullParent || !mParent->IsInShadowTree()) {
UnsetFlags(NODE_IS_IN_SHADOW_TREE);

View File

@ -488,22 +488,6 @@ Selection::GetInterlinePosition(ErrorResult& aRv)
return mFrameSelection->GetHint() == CARET_ASSOCIATE_AFTER;
}
bool
Selection::IsEditorSelection() const
{
nsINode* focusNode = GetFocusNode();
if (!focusNode) {
return false;
}
if (focusNode->IsEditable()) {
return true;
}
auto* element = Element::FromNode(focusNode);
return element && element->State().HasState(NS_EVENT_STATE_MOZ_READWRITE);
}
Nullable<int16_t>
Selection::GetCaretBidiLevel(mozilla::ErrorResult& aRv) const
{
@ -783,7 +767,7 @@ NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(Selection)
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE(Selection)
const RangeBoundary&
Selection::AnchorRef() const
Selection::AnchorRef()
{
if (!mAnchorFocusRange) {
static RangeBoundary sEmpty;
@ -798,7 +782,7 @@ Selection::AnchorRef() const
}
const RangeBoundary&
Selection::FocusRef() const
Selection::FocusRef()
{
if (!mAnchorFocusRange) {
static RangeBoundary sEmpty;
@ -1573,7 +1557,6 @@ Selection::GetPrimaryOrCaretFrameForNodeOffset(nsIContent* aContent,
return nsCaret::GetCaretFrameForNodeOffset(mFrameSelection,
aContent, aOffset, hint,
caretBidiLevel, aReturnFrame,
/* aReturnUnadjustedFrame = */ nullptr,
aOffsetUsed);
}

View File

@ -206,11 +206,7 @@ public:
return mAnchorFocusRange;
}
nsDirection GetDirection() const
{
return mDirection;
}
nsDirection GetDirection(){return mDirection;}
void SetDirection(nsDirection aDir){mDirection = aDir;}
nsresult SetAnchorFocusToRange(nsRange *aRange);
void ReplaceAnchorFocusRange(nsRange *aRange);
@ -240,22 +236,22 @@ public:
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// WebIDL methods
nsINode* GetAnchorNode() const
nsINode* GetAnchorNode()
{
const RangeBoundary& anchor = AnchorRef();
return anchor.IsSet() ? anchor.Container() : nullptr;
}
uint32_t AnchorOffset() const
uint32_t AnchorOffset()
{
const RangeBoundary& anchor = AnchorRef();
return anchor.IsSet() ? anchor.Offset() : 0;
}
nsINode* GetFocusNode() const
nsINode* GetFocusNode()
{
const RangeBoundary& focus = FocusRef();
return focus.IsSet() ? focus.Container() : nullptr;
}
uint32_t FocusOffset() const
uint32_t FocusOffset()
{
const RangeBoundary& focus = FocusRef();
return focus.IsSet() ? focus.Offset() : 0;
@ -272,8 +268,8 @@ public:
return focus.IsSet() ? focus.GetChildAtOffset() : nullptr;
}
const RangeBoundary& AnchorRef() const;
const RangeBoundary& FocusRef() const;
const RangeBoundary& AnchorRef();
const RangeBoundary& FocusRef();
/*
* IsCollapsed -- is the whole selection just one point, or unset?
@ -479,9 +475,6 @@ public:
void RemoveSelectionChangeBlocker();
bool IsBlockingSelectionChangeEvents() const;
// Whether this selection is focused in an editable element.
bool IsEditorSelection() const;
/**
* Set the painting style for the range. The range must be a range in
* the selection. The textRangeStyle will be used by text frame

View File

@ -119,7 +119,8 @@ using namespace mozilla;
using namespace mozilla::dom;
nsINode::nsSlots::nsSlots()
: mWeakReference(nullptr)
: mWeakReference(nullptr),
mEditableDescendantCount(0)
{
}
@ -1179,6 +1180,38 @@ nsINode::GetOwnerGlobal() const
return OwnerDoc()->GetScriptHandlingObject(dummy);
}
void
nsINode::ChangeEditableDescendantCount(int32_t aDelta)
{
if (aDelta == 0) {
return;
}
nsSlots* s = Slots();
MOZ_ASSERT(aDelta > 0 ||
s->mEditableDescendantCount >= (uint32_t) (-1 * aDelta));
s->mEditableDescendantCount += aDelta;
}
void
nsINode::ResetEditableDescendantCount()
{
nsSlots* s = GetExistingSlots();
if (s) {
s->mEditableDescendantCount = 0;
}
}
uint32_t
nsINode::EditableDescendantCount()
{
nsSlots* s = GetExistingSlots();
if (s) {
return s->mEditableDescendantCount;
}
return 0;
}
bool
nsINode::UnoptimizableCCNode() const
{

View File

@ -1141,6 +1141,12 @@ public:
* allocation bucket size, at the cost of some complexity.
*/
mozilla::UniquePtr<mozilla::LinkedList<nsRange>> mCommonAncestorRanges;
/**
* Number of descendant nodes in the uncomposed document that have been
* explicitly set as editable.
*/
uint32_t mEditableDescendantCount;
};
/**
@ -1176,11 +1182,28 @@ public:
nsWrapperCache::UnsetFlags(aFlagsToUnset);
}
void ChangeEditableDescendantCount(int32_t aDelta);
/**
* Returns the count of descendant nodes in the uncomposed
* document that are explicitly set as editable.
*/
uint32_t EditableDescendantCount();
/**
* Sets the editable descendant count to 0. The editable
* descendant count only counts explicitly editable nodes
* that are in the uncomposed document so this method
* should be called when nodes are are removed from it.
*/
void ResetEditableDescendantCount();
void SetEditableFlag(bool aEditable)
{
if (aEditable) {
SetFlags(NODE_IS_EDITABLE);
} else {
}
else {
UnsetFlags(NODE_IS_EDITABLE);
}
}

View File

@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=816298
<p id="test2">This<span style="-moz-user-select: none;"><span style="-moz-user-select: text"> text should</span> NOT</span> be copied.</p>
<p id="test3">This text should<span style="-moz-user-select: -moz-none;"> NOT</span> be copied.</p>
<p id="test4">This<span style="-moz-user-select: -moz-none;"><span style="-moz-user-select: text"> text should</span> NOT</span> be copied.</p>
<p id="test5">This<span style="-moz-user-select: all"> text should</span> be copied.</p>
<p id="test5">This<span style="-moz-user-select: all"> text<span style="-moz-user-select: none"> should</span></span> be copied.</p>
<div id="content" style="display: none">
</div>
@ -107,7 +107,7 @@ var clipboardHTML = [
'<p id=\"test2\">This<span style=\"-moz-user-select: text\"> text should</span> be copied.</p>',
'<p id=\"test3\">This text should be copied.</p>',
'<p id=\"test4\">This<span style=\"-moz-user-select: text\"> text should</span> be copied.</p>',
'<p id=\"test5\">This<span style=\"-moz-user-select: all\"> text should</span> be copied.</p>',
'<p id=\"test5\">This<span style=\"-moz-user-select: all\"> text<span style=\"-moz-user-select: none\"> should</span></span> be copied.</p>',
];
// expected results for clipboard text/unicode
@ -127,7 +127,7 @@ var innerHTMLStrings = [
'This<span style=\"-moz-user-select: none;\"><span style=\"-moz-user-select: text\"> text should</span> NOT</span> be copied.',
'This text should<span style=\"-moz-user-select: -moz-none;\"> NOT</span> be copied.',
'This<span style=\"-moz-user-select: -moz-none;\"><span style=\"-moz-user-select: text\"> text should</span> NOT</span> be copied.',
'This<span style=\"-moz-user-select: all\"> text should</span> be copied.',
'This<span style=\"-moz-user-select: all\"> text<span style=\"-moz-user-select: none\"> should</span></span> be copied.',
];
// expected results for pasting into a TEXTAREA

View File

@ -407,6 +407,14 @@ nsGenericHTMLElement::IntrinsicState() const
return state;
}
uint32_t
nsGenericHTMLElement::EditableInclusiveDescendantCount()
{
bool isEditable = IsInComposedDoc() && HasFlag(NODE_IS_EDITABLE) &&
GetContentEditableValue() == eTrue;
return EditableDescendantCount() + isEditable;
}
nsresult
nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent)
@ -2671,7 +2679,7 @@ MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
return;
}
Element* element = aContent->AsElement();
Element *element = aContent->AsElement();
element->UpdateEditableState(true);
@ -2695,9 +2703,18 @@ nsGenericHTMLElement::ChangeEditableState(int32_t aChange)
}
if (aChange != 0) {
if (nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(document)) {
nsCOMPtr<nsIHTMLDocument> htmlDocument =
do_QueryInterface(document);
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, aChange);
}
nsIContent* parent = GetParent();
// Don't update across Shadow DOM boundary.
while (parent && parent->IsElement()) {
parent->ChangeEditableDescendantCount(aChange);
parent = parent->GetParent();
}
}
if (document->HasFlag(NODE_IS_EDITABLE)) {

View File

@ -4681,16 +4681,10 @@ EditorBase::InitializeSelection(EventTarget* aFocusEventTarget)
if (NS_WARN_IF(!caret)) {
return NS_ERROR_FAILURE;
}
caret->SetIgnoreUserModify(false);
caret->SetSelection(SelectionRefPtr());
selectionController->SetCaretReadOnly(IsReadonly());
selectionController->SetCaretEnabled(true);
// NOTE(emilio): It's important for this call to be after
// SetCaretEnabled(true), since that would override mIgnoreUserModify to true.
//
// Also, make sure to always ignore it for designMode, since that effectively
// overrides everything and we allow to edit stuff with
// contenteditable="false" subtrees in such a document.
caret->SetIgnoreUserModify(targetNode->OwnerDoc()->HasFlag(NODE_IS_EDITABLE));
// Init selection
selectionController->SetDisplaySelection(
@ -4779,10 +4773,6 @@ EditorBase::FinalizeSelection()
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED);
if (RefPtr<nsCaret> caret = presShell->GetCaret()) {
caret->SetIgnoreUserModify(true);
}
selectionController->SetCaretEnabled(false);
nsFocusManager* fm = nsFocusManager::GetFocusManager();

View File

@ -48,7 +48,7 @@ function test() {
synthesizeKey("KEY_Enter", {shiftKey: true});
synthesizeKey("KEY_Backspace");
synthesizeKey("KEY_Backspace");
}]];
}, "A ; B ; C "]];
[
"insertorderedlist",
"insertunorderedlist",

View File

@ -99,14 +99,12 @@ AdjustCaretFrameForLineEnd(nsIFrame** aFrame, int32_t* aOffset)
for (nsIFrame* f = line->mFirstChild; count > 0; --count, f = f->GetNextSibling())
{
nsIFrame* r = CheckForTrailingTextFrameRecursive(f, *aFrame);
if (r == *aFrame) {
if (r == *aFrame)
return;
}
if (r) {
// We found our frame, but we may not be able to properly paint the caret if
// -moz-user-modify differs from our actual frame.
MOZ_ASSERT(r->IsTextFrame(), "Expected text frame");
if (r)
{
*aFrame = r;
NS_ASSERTION(r->IsTextFrame(), "Expected text frame");
*aOffset = (static_cast<nsTextFrame*>(r))->GetContentEnd();
return;
}
@ -382,13 +380,8 @@ nsCaret::GetGeometryForFrame(nsIFrame* aFrame,
nsIFrame*
nsCaret::GetFrameAndOffset(Selection* aSelection,
nsINode* aOverrideNode, int32_t aOverrideOffset,
int32_t* aFrameOffset,
nsIFrame** aUnadjustedFrame)
int32_t* aFrameOffset)
{
if (aUnadjustedFrame) {
*aUnadjustedFrame = nullptr;
}
nsINode* focusNode;
int32_t focusOffset;
@ -412,11 +405,11 @@ nsCaret::GetFrameAndOffset(Selection* aSelection,
nsIFrame* frame;
nsresult rv = nsCaret::GetCaretFrameForNodeOffset(
frameSelection, contentNode, focusOffset,
frameSelection->GetHint(), bidiLevel, &frame, aUnadjustedFrame,
aFrameOffset);
frameSelection->GetHint(), bidiLevel, &frame, aFrameOffset);
if (NS_FAILED(rv) || !frame) {
return nullptr;
}
return frame;
}
@ -500,26 +493,16 @@ nsCaret::GetPaintGeometry(nsRect* aRect)
CheckSelectionLanguageChange();
int32_t frameOffset;
nsIFrame* unadjustedFrame = nullptr;
nsIFrame* frame = GetFrameAndOffset(GetSelection(),
mOverrideContent, mOverrideOffset, &frameOffset, &unadjustedFrame);
MOZ_ASSERT(!!frame == !!unadjustedFrame);
mOverrideContent, mOverrideOffset, &frameOffset);
if (!frame) {
return nullptr;
}
// Now we have a frame, check whether it's appropriate to show the caret here.
// Note we need to check the unadjusted frame, otherwise consider the
// following case:
//
// <div contenteditable><span contenteditable=false>Text </span><br>
//
// Where the selection is targeting the <br>. We want to display the caret,
// since the <br> we're focused at is editable, but we do want to paint it at
// the adjusted frame offset, so that we can see the collapsed whitespace.
const nsStyleUI* ui = unadjustedFrame->StyleUI();
// now we have a frame, check whether it's appropriate to show the caret here
const nsStyleUI* ui = frame->StyleUI();
if ((!mIgnoreUserModify && ui->mUserModify == StyleUserModify::ReadOnly) ||
unadjustedFrame->IsContentDisabled()) {
frame->IsContentDisabled()) {
return nullptr;
}
@ -662,7 +645,6 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
CaretAssociationHint aFrameHint,
nsBidiLevel aBidiLevel,
nsIFrame** aReturnFrame,
nsIFrame** aReturnUnadjustedFrame,
int32_t* aReturnOffset)
{
if (!aFrameSelection)
@ -683,10 +665,6 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
if (!theFrame)
return NS_ERROR_FAILURE;
if (aReturnUnadjustedFrame) {
*aReturnUnadjustedFrame = theFrame;
}
// if theFrame is after a text frame that's logically at the end of the line
// (e.g. if theFrame is a <br> frame), then put the caret at the end of
// that text frame instead. This way, the caret will be positioned as if
@ -699,7 +677,8 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
// ------------------
// NS_STYLE_DIRECTION_LTR : LTR or Default
// NS_STYLE_DIRECTION_RTL
if (theFrame->PresContext()->BidiEnabled()) {
if (theFrame->PresContext()->BidiEnabled())
{
// If there has been a reflow, take the caret Bidi level to be the level of the current frame
if (aBidiLevel & BIDI_LEVEL_UNDEFINED) {
aBidiLevel = theFrame->GetEmbeddingLevel();

View File

@ -182,7 +182,6 @@ class nsCaret final : public nsISelectionListener
CaretAssociationHint aFrameHint,
uint8_t aBidiLevel,
nsIFrame** aReturnFrame,
nsIFrame** aReturnUnadjustedFrame,
int32_t* aReturnOffset);
static nsRect GetGeometryForFrame(nsIFrame* aFrame,
int32_t aFrameOffset,
@ -192,14 +191,11 @@ class nsCaret final : public nsISelectionListener
// of aSelection. If aOverrideNode and aOverride are provided, use them
// instead.
// @param aFrameOffset return the frame offset if non-null.
// @param aUnadjustedFrame return the original frame that the selection is
// targeting, without any adjustment for painting.
// @return the frame of the focus node.
static nsIFrame* GetFrameAndOffset(mozilla::dom::Selection* aSelection,
nsINode* aOverrideNode,
int32_t aOverrideOffset,
int32_t* aFrameOffset,
nsIFrame** aUnadjustedFrame = nullptr);
int32_t* aFrameOffset);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;

View File

@ -4778,7 +4778,7 @@ nsLayoutUtils::GetNonGeneratedAncestor(nsIFrame* aFrame)
}
nsIFrame*
nsLayoutUtils::GetParentOrPlaceholderFor(const nsIFrame* aFrame)
nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame)
{
if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
&& !aFrame->GetPrevInFlow()) {

View File

@ -1389,7 +1389,7 @@ public:
* If aFrame is an out of flow frame, return its placeholder, otherwise
* return its parent.
*/
static nsIFrame* GetParentOrPlaceholderFor(const nsIFrame* aFrame);
static nsIFrame* GetParentOrPlaceholderFor(nsIFrame* aFrame);
/**
* If aFrame is an out of flow frame, return its placeholder, otherwise

View File

@ -13,7 +13,7 @@
var sel = getSelection();
sel.collapse(div, 0);
// Press Right four times to set the caret right before "baz"
for (var i = 0; i < 4; ++i) {
for (var i = 0; i < 5; ++i) {
synthesizeKey("KEY_ArrowRight");
}
document.documentElement.removeAttribute("class");

View File

@ -13,7 +13,7 @@
var sel = getSelection();
sel.collapse(div, 0);
// Press Right four times to set the caret right before "bar"
for (var i = 0; i < 4; ++i) {
for (var i = 0; i < 6; ++i) {
synthesizeKey("KEY_ArrowRight");
}
document.documentElement.removeAttribute("class");

View File

@ -1,17 +1,17 @@
<!DOCTYPE html>
<html class="reftest-wait">
<title>Can drag-select non-editable content inside editable content</title>
<script src="selection-utils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<div contenteditable spellcheck="false"
style="outline: none">foo<span contenteditable=false>bar</span>baz</div>
<script>
SimpleTest.waitForFocus(function() {
const span = document.querySelector("span");
const rect = span.getBoundingClientRect();
dragSelectPoints(span, 0, rect.height / 2, rect.width, rect.height / 2);
setTimeout(() => document.documentElement.removeAttribute("class"));
});
function test() {
focus();
synthesizeMouseAtCenter(document.querySelector("span"), {});
}
function focused() {
document.documentElement.removeAttribute("class");
}
</script>
<body onload="setTimeout(test, 0)">
<div contenteditable spellcheck="false" onfocus="focused()"
style="outline: none">foo<span contenteditable=false>bar</span>baz</div>
</body>
</html>

View File

@ -1,29 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Moving the caret in an editor jumps over non-editable nodes.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true">
I am div number one
<div contenteditable="false">X X X</div>
However I am editable
</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
const noneditable = document.querySelector('div[contenteditable="false"]');
editable.focus();
synthesizeKey("KEY_ArrowDown");
setTimeout(() => document.documentElement.removeAttribute("class"), 0);
});
</script>
</html>

View File

@ -1,30 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Moving the caret in an editor jumps over non-editable nodes.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true">
I am div number one
<div contenteditable="false">X X X</div>
However I am editable
</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
// 5 words in the first line, plus the non-editable node.
for (let i = 0; i < "I am div number one".length + 2; ++i)
synthesizeKey("KEY_ArrowRight");
setTimeout(() => document.documentElement.removeAttribute("class"), 0);
});
</script>
</html>

View File

@ -1,32 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Moving the caret in an editor jumps over non-editable nodes.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true">
I am div number one
<div contenteditable="false">X X X</div>
However I am editable
</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
const noneditable = document.querySelector('div[contenteditable="false"]');
editable.focus();
synthesizeKey("KEY_End");
synthesizeKey("KEY_ArrowDown");
for (let i = 0; i < 4; ++i)
synthesizeKey("KEY_ArrowLeft", { ctrlKey: true });
setTimeout(() => document.documentElement.removeAttribute("class"), 0);
});
</script>
</html>

View File

@ -1,21 +0,0 @@
<!doctype html>
<title>Caret on editable line with non-editable content and whitespace.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true"><span>xyz </span><br>editable</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
synthesizeMouse(editable, 100, 10, {});
});
</script>

View File

@ -1,21 +0,0 @@
<!doctype html>
<title>Caret on editable line with non-editable content and whitespace.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true"><span contenteditable="false">xyz </span><br>editable</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
synthesizeMouse(editable, 100, 10, {});
});
</script>

View File

@ -1,26 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret on editable line with non-editable content and whitespace.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true"><span>xyz </span><br>editable</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
synthesizeMouse(editable, 100, 10, {});
setTimeout(() => {
sendString("xxx");
setTimeout(() => document.documentElement.className = "");
});
});
</script>

View File

@ -1,27 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret on editable line with non-editable content and whitespace.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true"><span contenteditable="false">xyz </span><br>editable</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
synthesizeMouse(editable, 100, 10, {});
setTimeout(() => {
sendString("xxx");
setTimeout(() => document.documentElement.className = "");
});
});
</script>
</html>

View File

@ -1,27 +0,0 @@
<!doctype html>
<html class="reftest-wait">
<title>Caret on editable line with non-editable content and whitespace.</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
* { outline: none }
div {
border: 1px solid red;
margin: 5px;
padding: 2px;
}
</style>
<div contenteditable="true"><span contenteditable="false">xyz </span><br>editable</div>
<script>
SimpleTest.waitForFocus(function() {
const editable = document.querySelector('div[contenteditable="true"]');
editable.focus();
synthesizeKey("KEY_ArrowDown");
synthesizeKey("KEY_ArrowLeft");
setTimeout(() => {
sendString("xxx");
setTimeout(() => document.documentElement.className = "");
});
});
</script>

View File

@ -352,15 +352,6 @@ support-files =
textarea-minlength-valid-before-change.html
textarea-minlength-valid-change.html
textarea-valid-ref.html
bug1506547-1.html
bug1506547-2.html
bug1506547-3.html
bug1506547-4.html
bug1506547-5.html
bug1506547-6.html
bug1506547-4-ref.html
bug1506547-5-ref.html
[test_remote_frame.html]
[test_resize_flush.html]
support-files = resize_flush_iframe.html

View File

@ -206,11 +206,6 @@ var tests = [
// [ 'bug1423331-4.html' , 'bug1423331-2-ref.html' ] ,
[ 'bug1484094-1.html' , 'bug1484094-1-ref.html' ] ,
[ 'bug1484094-2.html' , 'bug1484094-2-ref.html' ] ,
[ 'bug1506547-1.html' , 'bug1506547-2.html' ] ,
[ 'bug1506547-2.html' , 'bug1506547-3.html' ] ,
[ 'bug1506547-4.html' , 'bug1506547-4-ref.html' ] ,
[ 'bug1506547-5.html' , 'bug1506547-5-ref.html' ] ,
[ 'bug1506547-6.html' , 'bug1506547-5-ref.html' ] ,
function() {SpecialPowers.pushPrefEnv({'clear': [['layout.accessiblecaret.enabled']]}, nextTest);} ,
];

View File

@ -4129,30 +4129,80 @@ nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
return NS_OK;
}
static StyleUserSelect
UsedUserSelect(const nsIFrame* aFrame)
{
if (aFrame->HasAnyStateBits(NS_FRAME_GENERATED_CONTENT)) {
return StyleUserSelect::None;
}
auto style = aFrame->StyleUIReset()->mUserSelect;
if (style != StyleUserSelect::Auto) {
return style;
}
auto* parent = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
return parent ? UsedUserSelect(parent) : StyleUserSelect::Text;
}
bool
nsIFrame::IsSelectable(StyleUserSelect* aSelectStyle) const
{
auto style = UsedUserSelect(this);
if (aSelectStyle) {
*aSelectStyle = style;
// it's ok if aSelectStyle is null
// Like 'visibility', we must check all the parents: if a parent
// is not selectable, none of its children is selectable.
//
// The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
// all its children are selectable, even those with 'user-select:none'.
//
// As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
// aSelectStyle returns the first style that is not AUTO. If these values
// are present in the frame hierarchy, aSelectStyle returns the style of the
// topmost parent that has either 'none' or '-moz-all'.
//
// The -moz-text value acts as a way to override an ancestor's all/-moz-all value.
//
// For instance, if the frame hierarchy is:
// AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is ALL
// AUTO -> _MOZ_ALL -> NONE -> _MOZ_TEXT, the returned value is TEXT.
// TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is TEXT
// _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is ALL
// _MOZ_ALL -> _MOZ_TEXT -> AUTO -> AUTO, the returned value is TEXT.
// AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT
//
StyleUserSelect selectStyle = StyleUserSelect::Auto;
nsIFrame* frame = const_cast<nsIFrame*>(this);
bool containsEditable = false;
while (frame) {
const nsStyleUIReset* userinterface = frame->StyleUIReset();
switch (userinterface->mUserSelect) {
case StyleUserSelect::All: {
// override the previous values
if (selectStyle != StyleUserSelect::MozText) {
selectStyle = userinterface->mUserSelect;
}
nsIContent* frameContent = frame->GetContent();
containsEditable = frameContent &&
frameContent->EditableDescendantCount() > 0;
break;
}
default:
// otherwise return the first value which is not 'auto'
if (selectStyle == StyleUserSelect::Auto) {
selectStyle = userinterface->mUserSelect;
}
break;
}
frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
}
return style != StyleUserSelect::None;
// convert internal values to standard values
if (selectStyle == StyleUserSelect::Auto ||
selectStyle == StyleUserSelect::MozText) {
selectStyle = StyleUserSelect::Text;
}
// If user tries to select all of a non-editable content,
// prevent selection if it contains editable content.
bool allowSelection = true;
if (selectStyle == StyleUserSelect::All) {
allowSelection = !containsEditable;
}
// return stuff
if (aSelectStyle) {
*aSelectStyle = selectStyle;
}
return !(mState & NS_FRAME_GENERATED_CONTENT) &&
allowSelection &&
selectStyle != StyleUserSelect::None;
}
/**
@ -4926,21 +4976,15 @@ static FrameTarget GetSelectionClosestFrameForLine(
WritingMode wm = aLine->mWritingMode;
LogicalPoint pt(wm, aPoint, aLine->mContainerSize);
bool canSkipBr = false;
bool lastFrameWasEditable = false;
for (int32_t n = aLine->GetChildCount(); n;
--n, frame = frame->GetNextSibling()) {
// Skip brFrames. Can only skip if the line contains at least
// one selectable and non-empty frame before. Also, avoid skipping brs if
// the previous thing had a different editableness than us, since then we
// may end up not being able to select after it if the br is the last thing
// on the line.
// one selectable and non-empty frame before
if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty() ||
(canSkipBr && frame->IsBrFrame() &&
lastFrameWasEditable == frame->GetContent()->IsEditable())) {
(canSkipBr && frame->IsBrFrame())) {
continue;
}
canSkipBr = true;
lastFrameWasEditable = frame->GetContent() && frame->GetContent()->IsEditable();
LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
aLine->mContainerSize);
if (pt.I(wm) >= frameRect.IStart(wm)) {
@ -5131,14 +5175,18 @@ OffsetsForSingleFrame(nsIFrame* aFrame, const nsPoint& aPoint)
static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
nsIFrame* adjustedFrame = aFrame;
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
{
// These are the conditions that make all children not able to handle
// a cursor.
StyleUserSelect userSelect = frame->StyleUIReset()->mUserSelect;
if (userSelect != StyleUserSelect::Auto && userSelect != StyleUserSelect::All) {
if (userSelect == StyleUserSelect::MozText) {
// If we see a -moz-text element, we shouldn't look further up the parent
// chain!
break;
}
if (userSelect == StyleUserSelect::All || frame->IsGeneratedContentFrame()) {
if (userSelect == StyleUserSelect::All ||
frame->IsGeneratedContentFrame()) {
adjustedFrame = frame;
}
}
@ -5151,7 +5199,8 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(const nsPoint& aPo
nsIFrame *adjustedFrame;
if (aFlags & IGNORE_SELECTION_STYLE) {
adjustedFrame = this;
} else {
}
else {
// This section of code deals with special selection styles. Note that
// -moz-all exists, even though it doesn't need to be explicitly handled.
//
@ -5162,7 +5211,8 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(const nsPoint& aPo
// -moz-user-select: all needs special handling, because clicking on it
// should lead to the whole frame being selected
if (adjustedFrame->StyleUIReset()->mUserSelect == StyleUserSelect::All) {
if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
StyleUserSelect::All) {
nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
}
@ -8082,7 +8132,8 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
nsPeekOffsetStruct *aPos,
nsIFrame *aBlockFrame,
int32_t aLineStart,
int8_t aOutSideLimit)
int8_t aOutSideLimit
)
{
//magic numbers aLineStart will be -1 for end of block 0 will be start of block
if (!aBlockFrame || !aPos)
@ -8190,19 +8241,6 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
if (NS_FAILED(result))
return result;
auto FoundValidFrame = [aPos](const ContentOffsets& aOffsets, const nsIFrame* aFrame) {
if (!aOffsets.content) {
return false;
}
if (!aFrame->IsSelectable(nullptr)) {
return false;
}
if (aPos->mForceEditableRegion && !aOffsets.content->IsEditable()) {
return false;
}
return true;
};
nsIFrame *storeOldResultFrame = resultFrame;
while ( !found ){
nsPoint point;
@ -8256,7 +8294,8 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
}
}
if (!resultFrame->HasView()) {
if (!resultFrame->HasView())
{
nsView* view;
nsPoint offset;
resultFrame->GetOffsetFromView(offset, &view);
@ -8265,9 +8304,12 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
aPos->mResultContent = offsets.content;
aPos->mContentOffset = offsets.offset;
aPos->mAttach = offsets.associate;
if (FoundValidFrame(offsets, resultFrame)) {
found = true;
break;
if (offsets.content)
{
if (resultFrame->IsSelectable(nullptr)) {
found = true;
break;
}
}
}
@ -8304,13 +8346,16 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
aPos->mResultContent = offsets.content;
aPos->mContentOffset = offsets.offset;
aPos->mAttach = offsets.associate;
if (FoundValidFrame(offsets, resultFrame)) {
found = true;
if (resultFrame == farStoppingFrame)
aPos->mAttach = CARET_ASSOCIATE_BEFORE;
else
aPos->mAttach = CARET_ASSOCIATE_AFTER;
break;
if (offsets.content)
{
if (resultFrame->IsSelectable(nullptr)) {
found = true;
if (resultFrame == farStoppingFrame)
aPos->mAttach = CARET_ASSOCIATE_BEFORE;
else
aPos->mAttach = CARET_ASSOCIATE_AFTER;
break;
}
}
if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
break;
@ -8534,7 +8579,6 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
result =
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
aPos->mJumpLines, aPos->mScrollViewStop,
aPos->mForceEditableRegion,
&current, &offset, &jumpedLine,
&movedOverNonSelectable);
if (NS_FAILED(result))
@ -8546,7 +8590,9 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
eatingNonRenderableWS = true;
// Remember if we moved over non-selectable text when finding another frame.
movedOverNonSelectableText |= movedOverNonSelectable;
if (movedOverNonSelectable) {
movedOverNonSelectableText = true;
}
}
// Found frame, but because we moved over non selectable text we want the offset
@ -8636,7 +8682,6 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
result =
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
aPos->mJumpLines, aPos->mScrollViewStop,
aPos->mForceEditableRegion,
&nextFrame, &nextFrameOffset, &jumpedLine,
&movedOverNonSelectableText);
// We can't jump lines if we're looking for whitespace following
@ -8994,7 +9039,6 @@ nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainin
nsresult
nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
bool aJumpLines, bool aScrollViewStop,
bool aForceEditableRegion,
nsIFrame** aOutFrame, int32_t* aOutOffset,
bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText)
{
@ -9099,31 +9143,24 @@ nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
return NS_ERROR_FAILURE;
}
auto IsSelectable = [aForceEditableRegion](const nsIFrame* aFrame) {
if (!aFrame->IsSelectable(nullptr)) {
return false;
// Skip brFrames, but only if they are not the only frame in the line
if (atLineEdge && aDirection == eDirPrevious &&
traversedFrame->IsBrFrame()) {
int32_t lineFrameCount;
nsIFrame *currentBlockFrame, *currentFirstFrame;
nsRect usedRect;
int32_t currentLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &currentBlockFrame);
nsAutoLineIterator iter = currentBlockFrame->GetLineIterator();
result = iter->GetLine(currentLine, &currentFirstFrame, &lineFrameCount, usedRect);
if (NS_FAILED(result)) {
return result;
}
return !aForceEditableRegion || aFrame->GetContent()->IsEditable();
};
// Skip brFrames, but only we can select something before hitting the end of
// the line or a non-selectable region.
if (atLineEdge && aDirection == eDirPrevious && traversedFrame->IsBrFrame()) {
bool canSkipBr = false;
for (nsIFrame* current = traversedFrame->GetPrevSibling();
current;
current = current->GetPrevSibling()) {
if (IsSelectable(current)) {
canSkipBr = true;
break;
}
}
if (canSkipBr) {
if (lineFrameCount > 1) {
continue;
}
}
selectable = IsSelectable(traversedFrame);
selectable = traversedFrame->IsSelectable(nullptr);
if (!selectable) {
*aOutMovedOverNonSelectableText = true;
}

View File

@ -119,7 +119,6 @@ nsPeekOffsetStruct::nsPeekOffsetStruct(nsSelectionAmount aAmount,
bool aIsKeyboardSelect,
bool aVisual,
bool aExtend,
ForceEditableRegion aForceEditableRegion,
EWordMovementType aWordMovementType)
: mAmount(aAmount)
, mDirection(aDirection)
@ -131,7 +130,6 @@ nsPeekOffsetStruct::nsPeekOffsetStruct(nsSelectionAmount aAmount,
, mIsKeyboardSelect(aIsKeyboardSelect)
, mVisual(aVisual)
, mExtend(aExtend)
, mForceEditableRegion(aForceEditableRegion == ForceEditableRegion::Yes)
, mResultContent()
, mResultFrame(nullptr)
, mContentOffset(0)
@ -708,8 +706,12 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
return NS_ERROR_NULL_POINTER;
int32_t scrollFlags = Selection::SCROLL_FOR_CARET_MOVE;
const bool isEditorSelection = sel->IsEditorSelection();
if (isEditorSelection) {
nsINode* focusNode = sel->GetFocusNode();
if (focusNode &&
(focusNode->IsEditable() ||
(focusNode->IsElement() &&
focusNode->AsElement()->State().
HasState(NS_EVENT_STATE_MOZ_READWRITE)))) {
// If caret moves in editor, it should cause scrolling even if it's in
// overflow: hidden;.
scrollFlags |= Selection::SCROLL_OVERFLOW_HIDDEN;
@ -777,14 +779,11 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
if (NS_FAILED(result) || !frame)
return NS_FAILED(result) ? result : NS_ERROR_FAILURE;
const auto forceEditableRegion = isEditorSelection
? nsPeekOffsetStruct::ForceEditableRegion::Yes
: nsPeekOffsetStruct::ForceEditableRegion::No;
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
nsPeekOffsetStruct pos(aAmount, eDirPrevious, offsetused, desiredPos,
true, mLimiter != nullptr, true, visualMovement,
aContinueSelection, forceEditableRegion);
aContinueSelection);
nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(frame);
@ -946,7 +945,7 @@ nsFrameSelection::GetPrevNextBidiLevels(nsIContent* aNode,
int32_t offset;
bool jumpedLine, movedOverNonSelectableText;
nsresult rv = currentFrame->GetFrameFromDirection(direction, false,
aJumpLines, true, false,
aJumpLines, true,
&newFrame, &offset, &jumpedLine,
&movedOverNonSelectableText);
if (NS_FAILED(rv))

View File

@ -75,12 +75,6 @@ class nsIPresShell;
*/
struct MOZ_STACK_CLASS nsPeekOffsetStruct
{
enum class ForceEditableRegion
{
No,
Yes,
};
nsPeekOffsetStruct(nsSelectionAmount aAmount,
nsDirection aDirection,
int32_t aStartOffset,
@ -90,7 +84,6 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruct
bool aIsKeyboardSelect,
bool aVisual,
bool aExtend,
ForceEditableRegion = ForceEditableRegion::No,
mozilla::EWordMovementType aWordMovementType = mozilla::eDefaultBehavior);
// Note: Most arguments (input and output) are only used with certain values
@ -149,10 +142,6 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruct
// mExtend: Whether the selection is being extended or moved.
bool mExtend;
// mForceEditableRegion: If true, the offset has to end up in an editable
// node, otherwise we'll keep searching.
const bool mForceEditableRegion;
/*** Output arguments ***/
// mResultContent: Content reached as a result of the peek.
@ -160,7 +149,7 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruct
// mResultFrame: Frame reached as a result of the peek.
// Used with: eSelectCharacter, eSelectWord.
nsIFrame* mResultFrame;
nsIFrame *mResultFrame;
// mContentOffset: Offset into content reached as a result of the peek.
int32_t mContentOffset;

View File

@ -3288,7 +3288,6 @@ public:
*/
nsresult GetFrameFromDirection(nsDirection aDirection, bool aVisual,
bool aJumpLines, bool aScrollViewStop,
bool aForceEditableRegion,
nsIFrame** aOutFrame, int32_t* aOutOffset,
bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText);

View File

@ -9,6 +9,15 @@
cursor: text;
}
*|*:-moz-read-write :-moz-read-only {
-moz-user-select: all;
}
*|*:-moz-read-only > :-moz-read-write {
/* override the above -moz-user-select: all rule. */
-moz-user-select: -moz-text;
}
input:-moz-read-write > .anonymous-div:-moz-read-only,
textarea:-moz-read-write > .anonymous-div:-moz-read-only {
-moz-user-select: text;
@ -91,7 +100,7 @@ input[contenteditable="true"][type="hidden"] {
}
label:-moz-read-write {
-moz-user-select: all;
-moz-user-select: all;
}
*|*::-moz-display-comboboxcontrol-frame {

View File

@ -39,7 +39,6 @@ ${helpers.predefined_type(
gecko_ffi_name="mUserSelect",
alias="-webkit-user-select",
animation_value_type="discrete",
needs_context=False,
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
)}

View File

@ -141,6 +141,11 @@ impl Parse for ScrollbarColor {
}
}
fn in_ua_sheet(context: &ParserContext) -> bool {
use crate::stylesheets::Origin;
context.stylesheet_origin == Origin::UserAgent
}
/// The specified value for the `user-select` property.
///
/// https://drafts.csswg.org/css-ui-4/#propdef-user-select
@ -163,6 +168,15 @@ pub enum UserSelect {
Text,
#[parse(aliases = "-moz-none")]
None,
/// Force selection of all children.
/// Force selection of all children, unless an ancestor has `none` set.
All,
/// Like `text`, except that it won't get overridden by ancestors having
/// `all`.
///
/// FIXME(emilio): This only has one use in contenteditable.css, can we find
/// a better way to do this?
///
/// See bug 1181130.
#[parse(condition = "in_ua_sheet")]
MozText,
}