Merge autoland to mozilla-central. a=merge

This commit is contained in:
criss 2022-03-16 11:49:56 +02:00
Родитель 9773800dcd 9604c80ac1
Коммит b61bbd064d
46 изменённых файлов: 589 добавлений и 4840 удалений

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

@ -111,7 +111,8 @@ void a11y::ProxyStateChangeEvent(RemoteAccessible* aTarget, uint64_t aState,
}
void a11y::ProxyCaretMoveEvent(RemoteAccessible* aTarget, int32_t aOffset,
bool aIsSelectionCollapsed) {
bool aIsSelectionCollapsed,
int32_t aGranularity) {
RefPtr<SessionAccessibility> sessionAcc =
SessionAccessibility::GetInstanceFor(aTarget);

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

@ -1372,7 +1372,8 @@ void a11y::ProxyStateChangeEvent(RemoteAccessible* aTarget, uint64_t aState,
}
void a11y::ProxyCaretMoveEvent(RemoteAccessible* aTarget, int32_t aOffset,
bool aIsSelectionCollapsed) {
bool aIsSelectionCollapsed,
int32_t aGranularity) {
AtkObject* wrapper = GetWrapperFor(aTarget);
g_signal_emit_by_name(wrapper, "text_caret_moved", aOffset);
}

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

@ -127,11 +127,13 @@ AccShowEvent::AccShowEvent(LocalAccessible* aTarget)
AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
dom::Selection* aSelection,
int32_t aReason)
int32_t aReason,
int32_t aGranularity)
: AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
eAutoDetect, eCoalesceTextSelChange),
mSel(aSelection),
mReason(aReason) {}
mReason(aReason),
mGranularity(aGranularity) {}
AccTextSelChangeEvent::~AccTextSelChangeEvent() {}
@ -246,7 +248,8 @@ already_AddRefed<nsIAccessibleEvent> a11y::MakeXPCEvent(AccEvent* aEvent) {
AccCaretMoveEvent* cm = downcast_accEvent(aEvent);
xpEvent = new xpcAccCaretMoveEvent(
type, ToXPC(acc), ToXPCDocument(doc), node, fromUser,
cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine());
cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine(),
cm->GetGranularity());
return xpEvent.forget();
}

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

@ -348,12 +348,14 @@ class AccCaretMoveEvent : public AccEvent {
public:
AccCaretMoveEvent(LocalAccessible* aAccessible, int32_t aCaretOffset,
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
int32_t aGranularity,
EIsFromUserInput aIsFromUserInput = eAutoDetect)
: AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible,
aIsFromUserInput),
mCaretOffset(aCaretOffset),
mIsSelectionCollapsed(aIsSelectionCollapsed),
mIsAtEndOfLine(aIsAtEndOfLine) {}
mIsAtEndOfLine(aIsAtEndOfLine),
mGranularity(aGranularity) {}
virtual ~AccCaretMoveEvent() {}
// AccEvent
@ -368,11 +370,14 @@ class AccCaretMoveEvent : public AccEvent {
bool IsSelectionCollapsed() const { return mIsSelectionCollapsed; }
bool IsAtEndOfLine() { return mIsAtEndOfLine; }
int32_t GetGranularity() const { return mGranularity; }
private:
int32_t mCaretOffset;
bool mIsSelectionCollapsed;
bool mIsAtEndOfLine;
int32_t mGranularity;
};
/**
@ -381,7 +386,8 @@ class AccCaretMoveEvent : public AccEvent {
class AccTextSelChangeEvent : public AccEvent {
public:
AccTextSelChangeEvent(HyperTextAccessible* aTarget,
dom::Selection* aSelection, int32_t aReason);
dom::Selection* aSelection, int32_t aReason,
int32_t aGranularity);
virtual ~AccTextSelChangeEvent();
// AccEvent
@ -397,6 +403,8 @@ class AccTextSelChangeEvent : public AccEvent {
*/
bool IsCaretMoveOnly() const;
int32_t GetGranularity() const { return mGranularity; }
/**
* Return selection ranges in document/control.
*/
@ -405,6 +413,7 @@ class AccTextSelChangeEvent : public AccEvent {
private:
RefPtr<dom::Selection> mSel;
int32_t mReason;
int32_t mGranularity;
friend class EventQueue;
friend class SelectionManager;

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

@ -104,10 +104,11 @@ void ProxyStateChangeEvent(RemoteAccessible* aTarget, uint64_t aState,
void ProxyFocusEvent(RemoteAccessible* aTarget,
const LayoutDeviceIntRect& aCaretRect);
void ProxyCaretMoveEvent(RemoteAccessible* aTarget,
const LayoutDeviceIntRect& aCaretRect);
const LayoutDeviceIntRect& aCaretRect,
int32_t aGranularity);
#else
void ProxyCaretMoveEvent(RemoteAccessible* aTarget, int32_t aOffset,
bool aIsSelectionCollapsed);
bool aIsSelectionCollapsed, int32_t aGranularity);
#endif
void ProxyTextChangeEvent(RemoteAccessible* aTarget, const nsString& aStr,
int32_t aStart, uint32_t aLen, bool aIsInsert,

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

@ -24,10 +24,12 @@ using namespace mozilla::a11y;
using mozilla::dom::Selection;
struct mozilla::a11y::SelData final {
SelData(Selection* aSel, int32_t aReason) : mSel(aSel), mReason(aReason) {}
SelData(Selection* aSel, int32_t aReason, int32_t aGranularity)
: mSel(aSel), mReason(aReason), mGranularity(aGranularity) {}
RefPtr<Selection> mSel;
int16_t mReason;
int32_t mGranularity;
NS_INLINE_DECL_REFCOUNTING(SelData)
@ -148,17 +150,18 @@ void SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent) {
selection->FocusOffset());
mAccWithCaret = caretCntr;
if (mCaretOffset != -1) {
RefPtr<AccCaretMoveEvent> caretMoveEvent = new AccCaretMoveEvent(
caretCntr, mCaretOffset, selection->IsCollapsed(),
caretCntr->IsCaretAtEndOfLine(), aEvent->FromUserInput());
RefPtr<AccCaretMoveEvent> caretMoveEvent =
new AccCaretMoveEvent(caretCntr, mCaretOffset, selection->IsCollapsed(),
caretCntr->IsCaretAtEndOfLine(),
event->GetGranularity(), aEvent->FromUserInput());
nsEventShell::FireEvent(caretMoveEvent);
}
}
NS_IMETHODIMP
SelectionManager::NotifySelectionChanged(dom::Document* aDocument,
Selection* aSelection,
int16_t aReason) {
Selection* aSelection, int16_t aReason,
int32_t aAmount) {
if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
return NS_ERROR_INVALID_ARG;
}
@ -175,7 +178,7 @@ SelectionManager::NotifySelectionChanged(dom::Document* aDocument,
// Selection manager has longer lifetime than any document accessible,
// so that we are guaranteed that the notification is processed before
// the selection manager is destroyed.
RefPtr<SelData> selData = new SelData(aSelection, aReason);
RefPtr<SelData> selData = new SelData(aSelection, aReason, aAmount);
document->HandleNotification<SelectionManager, SelData>(
this, &SelectionManager::ProcessSelectionChanged, selData);
}
@ -211,8 +214,8 @@ void SelectionManager::ProcessSelectionChanged(SelData* aSelData) {
}
if (selection->GetType() == SelectionType::eNormal) {
RefPtr<AccEvent> event =
new AccTextSelChangeEvent(text, selection, aSelData->mReason);
RefPtr<AccEvent> event = new AccTextSelChangeEvent(
text, selection, aSelData->mReason, aSelData->mGranularity);
text->Document()->FireDelayedEvent(event);
} else if (selection->GetType() == SelectionType::eSpellCheck) {

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

@ -934,9 +934,9 @@ nsresult LocalAccessible::HandleAccEvent(AccEvent* aEvent) {
}
case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
AccCaretMoveEvent* event = downcast_accEvent(aEvent);
ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset(),
event->IsSelectionCollapsed(),
event->IsAtEndOfLine());
ipcDoc->SendCaretMoveEvent(
id, event->GetCaretOffset(), event->IsSelectionCollapsed(),
event->IsAtEndOfLine(), event->GetGranularity());
break;
}
case nsIAccessibleEvent::EVENT_TEXT_INSERTED:

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

@ -25,4 +25,9 @@ interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent
* Return true if the caret is at the end of a line.
*/
readonly attribute bool isAtEndOfLine;
/**
* Return caret move granularity.
*/
readonly attribute long granularity;
};

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

@ -341,7 +341,7 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent(
const LayoutDeviceIntRect& aCaretRect,
#endif // defined (XP_WIN)
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine) {
const bool& aIsAtEndOfLine, const int32_t& aGranularity) {
if (mShutdown) {
return IPC_OK();
}
@ -364,9 +364,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent(
}
#if defined(XP_WIN)
ProxyCaretMoveEvent(proxy, aCaretRect);
ProxyCaretMoveEvent(proxy, aCaretRect, aGranularity);
#else
ProxyCaretMoveEvent(proxy, aOffset, aIsSelectionCollapsed);
ProxyCaretMoveEvent(proxy, aOffset, aIsSelectionCollapsed, aGranularity);
#endif
if (!nsCoreUtils::AccEventObserversExist()) {
@ -378,9 +378,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvCaretMoveEvent(
nsINode* node = nullptr;
bool fromUser = true; // XXX fix me
uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
RefPtr<xpcAccCaretMoveEvent> event =
new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset,
aIsSelectionCollapsed, aIsAtEndOfLine);
RefPtr<xpcAccCaretMoveEvent> event = new xpcAccCaretMoveEvent(
type, xpcAcc, doc, node, fromUser, aOffset, aIsSelectionCollapsed,
aIsAtEndOfLine, aGranularity);
nsCoreUtils::DispatchAccEvent(std::move(event));
return IPC_OK();

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

@ -108,7 +108,7 @@ class DocAccessibleParent : public RemoteAccessible,
const LayoutDeviceIntRect& aCaretRect,
#endif
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine) final;
const bool& aIsAtEndOfLine, const int32_t& aGranularity) final;
virtual mozilla::ipc::IPCResult RecvTextChangeEvent(
const uint64_t& aID, const nsString& aStr, const int32_t& aStart,

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

@ -99,7 +99,8 @@ parent:
async HideEvent(uint64_t aRootID, bool aFromUser);
async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
async CaretMoveEvent(uint64_t aID, int32_t aOffset,
bool aIsSelectionCollapsed, bool aIsAtEndOfLine);
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
int32_t aGranularity);
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
bool aIsInsert, bool aFromUser);
async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);

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

@ -200,22 +200,26 @@ bool DocAccessibleChild::SendFocusEvent(const uint64_t& aID,
bool DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID,
const int32_t& aOffset,
const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine) {
const bool& aIsAtEndOfLine,
const int32_t& aGranularity) {
return SendCaretMoveEvent(aID, GetCaretRectFor(aID), aOffset,
aIsSelectionCollapsed, aIsAtEndOfLine);
aIsSelectionCollapsed, aIsAtEndOfLine,
aGranularity);
}
bool DocAccessibleChild::SendCaretMoveEvent(
const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect,
const int32_t& aOffset, const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine) {
const bool& aIsAtEndOfLine, const int32_t& aGranularity) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendCaretMoveEvent(
aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine);
aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine,
aGranularity);
}
PushDeferredEvent(MakeUnique<SerializedCaretMove>(
this, aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine));
this, aID, aCaretRect, aOffset, aIsSelectionCollapsed, aIsAtEndOfLine,
aGranularity));
return true;
}

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

@ -52,12 +52,14 @@ class DocAccessibleChild : public DocAccessibleChildBase {
const bool& aEnabled);
bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset,
const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine);
const bool& aIsAtEndOfLine,
const int32_t& aGranularity);
bool SendCaretMoveEvent(const uint64_t& aID,
const LayoutDeviceIntRect& aCaretRect,
const int32_t& aOffset,
const bool& aIsSelectionCollapsed,
const bool& aIsAtEndOfLine);
const bool& aIsAtEndOfLine,
const int32_t& aGranularity);
bool SendFocusEvent(const uint64_t& aID);
bool SendFocusEvent(const uint64_t& aID,
const LayoutDeviceIntRect& aCaretRect);
@ -175,17 +177,20 @@ class DocAccessibleChild : public DocAccessibleChildBase {
struct SerializedCaretMove final : public DeferredEvent {
SerializedCaretMove(DocAccessibleChild* aTarget, uint64_t aID,
const LayoutDeviceIntRect& aCaretRect, int32_t aOffset,
bool aIsSelectionCollapsed, bool aIsAtEndOfLine)
bool aIsSelectionCollapsed, bool aIsAtEndOfLine,
int32_t aGranularity)
: DeferredEvent(aTarget),
mID(aID),
mCaretRect(aCaretRect),
mOffset(aOffset),
mIsSelectionCollapsed(aIsSelectionCollapsed),
mIsAtEndOfLine(aIsAtEndOfLine) {}
mIsAtEndOfLine(aIsAtEndOfLine),
mGranularity(aGranularity) {}
void Dispatch(DocAccessibleChild* aIPCDoc) override {
Unused << aIPCDoc->SendCaretMoveEvent(
mID, mCaretRect, mOffset, mIsSelectionCollapsed, mIsAtEndOfLine);
Unused << aIPCDoc->SendCaretMoveEvent(mID, mCaretRect, mOffset,
mIsSelectionCollapsed,
mIsAtEndOfLine, mGranularity);
}
uint64_t mID;
@ -193,6 +198,7 @@ class DocAccessibleChild : public DocAccessibleChildBase {
int32_t mOffset;
bool mIsSelectionCollapsed;
bool mIsAtEndOfLine;
int32_t mGranularity;
};
struct SerializedFocus final : public DeferredEvent {

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

@ -70,7 +70,7 @@ parent:
async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
async CaretMoveEvent(uint64_t aID, LayoutDeviceIntRect aCaretRect,
int32_t aOffset, bool aIsAtEndOfLine,
bool aIsSelectionCollapsed);
bool aIsSelectionCollapsed, int32_t aGranularity);
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
bool aIsInsert, bool aFromUser);
sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart,

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

@ -226,7 +226,9 @@ nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) {
int32_t caretOffset = event->GetCaretOffset();
MOXTextMarkerDelegate* delegate =
[MOXTextMarkerDelegate getOrCreateForDoc:aEvent->Document()];
[delegate setCaretOffset:eventTarget at:caretOffset];
[delegate setCaretOffset:eventTarget
at:caretOffset
moveGranularity:event->GetGranularity()];
if (event->IsSelectionCollapsed()) {
// If the selection is collapsed, invalidate our text selection cache.
[delegate setSelectionFrom:eventTarget

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

@ -15,6 +15,7 @@
AXTextMarkerRangeRef mSelection;
AXTextMarkerRef mCaret;
AXTextMarkerRef mPrevCaret;
int32_t mCaretMoveGranularity;
}
+ (id)getOrCreateForDoc:(mozilla::a11y::Accessible*)aDoc;
@ -30,7 +31,9 @@
to:(mozilla::a11y::Accessible*)endContainer
at:(int32_t)endOffset;
- (void)setCaretOffset:(mozilla::a11y::Accessible*)container at:(int32_t)offset;
- (void)setCaretOffset:(mozilla::a11y::Accessible*)container
at:(int32_t)offset
moveGranularity:(int32_t)granularity;
- (NSDictionary*)selectionChangeInfo;

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

@ -12,6 +12,7 @@
#include "mozAccessible.h"
#include "mozilla/Preferences.h"
#include "nsISelectionListener.h"
using namespace mozilla::a11y;
@ -52,6 +53,8 @@ static nsTHashMap<nsPtrHashKey<mozilla::a11y::Accessible>,
mGeckoDocAccessible = aDoc;
}
mCaretMoveGranularity = nsISelectionListener::NO_AMOUNT;
return self;
}
@ -76,11 +79,14 @@ static nsTHashMap<nsPtrHashKey<mozilla::a11y::Accessible>,
}
- (void)setCaretOffset:(mozilla::a11y::Accessible*)container
at:(int32_t)offset {
at:(int32_t)offset
moveGranularity:(int32_t)granularity {
GeckoTextMarker caretMarker(container, offset);
mPrevCaret = mCaret;
mCaret = caretMarker.CreateAXTextMarker();
mCaretMoveGranularity = granularity;
CFRetain(mCaret);
}
@ -146,21 +152,43 @@ static nsTHashMap<nsPtrHashKey<mozilla::a11y::Accessible>,
}
bool isForward = prevCaretMarker < caretMarker;
uint32_t deltaLength =
GeckoTextMarkerRange(isForward ? prevCaretMarker : caretMarker,
isForward ? caretMarker : prevCaretMarker)
.Length();
int direction = isForward ? AXTextSelectionDirectionNext
: AXTextSelectionDirectionPrevious;
int32_t granularity = AXTextSelectionGranularityUnknown;
switch (mCaretMoveGranularity) {
case nsISelectionListener::CHARACTER_AMOUNT:
case nsISelectionListener::CLUSTER_AMOUNT:
granularity = AXTextSelectionGranularityCharacter;
break;
case nsISelectionListener::WORD_AMOUNT:
case nsISelectionListener::WORDNOSPACE_AMOUNT:
granularity = AXTextSelectionGranularityWord;
break;
case nsISelectionListener::LINE_AMOUNT:
granularity = AXTextSelectionGranularityLine;
break;
case nsISelectionListener::BEGINLINE_AMOUNT:
direction = AXTextSelectionDirectionBeginning;
granularity = AXTextSelectionGranularityLine;
break;
case nsISelectionListener::ENDLINE_AMOUNT:
direction = AXTextSelectionDirectionEnd;
granularity = AXTextSelectionGranularityLine;
break;
case nsISelectionListener::PARAGRAPH_AMOUNT:
granularity = AXTextSelectionGranularityParagraph;
break;
default:
break;
}
// Determine selection direction with marker comparison.
// If the delta between the two markers is more than one, consider it
// a word. Not accurate, but good enough for VO.
[info addEntriesFromDictionary:@{
@"AXTextSelectionDirection" : isForward
? @(AXTextSelectionDirectionNext)
: @(AXTextSelectionDirectionPrevious),
@"AXTextSelectionGranularity" : deltaLength == 1
? @(AXTextSelectionGranularityCharacter)
: @(AXTextSelectionGranularityWord)
@"AXTextSelectionDirection" : @(direction),
@"AXTextSelectionGranularity" : @(granularity)
}];
return info;

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

@ -111,11 +111,11 @@ void ProxyStateChangeEvent(RemoteAccessible* aProxy, uint64_t aState,
}
void ProxyCaretMoveEvent(RemoteAccessible* aTarget, int32_t aOffset,
bool aIsSelectionCollapsed) {
bool aIsSelectionCollapsed, int32_t aGranularity) {
mozAccessible* wrapper = GetNativeFromGeckoAccessible(aTarget);
MOXTextMarkerDelegate* delegate =
[MOXTextMarkerDelegate getOrCreateForDoc:aTarget->Document()];
[delegate setCaretOffset:aTarget at:aOffset];
[delegate setCaretOffset:aTarget at:aOffset moveGranularity:aGranularity];
if (aIsSelectionCollapsed) {
// If selection is collapsed, invalidate selection.
[delegate setSelectionFrom:aTarget at:aOffset to:aTarget at:aOffset];

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

@ -22,7 +22,8 @@ void a11y::ProxyEvent(RemoteAccessible*, uint32_t) {}
void a11y::ProxyStateChangeEvent(RemoteAccessible*, uint64_t, bool) {}
void a11y::ProxyCaretMoveEvent(RemoteAccessible* aTarget, int32_t aOffset,
bool aIsSelectionCollapsed) {}
bool aIsSelectionCollapsed,
int32_t aGranularity) {}
void a11y::ProxyTextChangeEvent(RemoteAccessible*, const nsString&, int32_t,
uint32_t, bool, bool) {}

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

@ -8,6 +8,7 @@ support-files =
environment =
A11YLOG=doclifecycle,events,notifications
[browser_test_caret_move_granularity.js]
[browser_test_docload.js]
skip-if = e10s
[browser_test_scrolling.js]

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

@ -0,0 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const CLUSTER_AMOUNT = Ci.nsISelectionListener.CLUSTER_AMOUNT;
const WORD_AMOUNT = Ci.nsISelectionListener.WORD_AMOUNT;
const LINE_AMOUNT = Ci.nsISelectionListener.LINE_AMOUNT;
const BEGINLINE_AMOUNT = Ci.nsISelectionListener.BEGINLINE_AMOUNT;
const ENDLINE_AMOUNT = Ci.nsISelectionListener.ENDLINE_AMOUNT;
const isMac = AppConstants.platform == "macosx";
function matchCaretMoveEvent(id, caretOffset) {
return evt => {
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
return (
getAccessibleDOMNodeID(evt.accessible) == id &&
evt.caretOffset == caretOffset
);
};
}
addAccessibleTask(
`<textarea id="textarea" style="scrollbar-width: none;" cols="15">` +
`one two three four five six seven eight` +
`</textarea>`,
async function(browser, accDoc) {
const textarea = findAccessibleChildByID(accDoc, "textarea");
let caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 0)
);
textarea.takeFocus();
let evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 1)
);
EventUtils.synthesizeKey("KEY_ArrowRight");
evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
is(evt.granularity, CLUSTER_AMOUNT, "Caret moved by cluster");
caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 15)
);
EventUtils.synthesizeKey("KEY_ArrowDown");
evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
todo(!evt.isAtEndOfLine, "Caret is not at end of line");
is(evt.granularity, LINE_AMOUNT, "Caret moved by line");
caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 14)
);
if (isMac) {
EventUtils.synthesizeKey("KEY_ArrowLeft", { metaKey: true });
} else {
EventUtils.synthesizeKey("KEY_Home");
}
evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
is(evt.granularity, BEGINLINE_AMOUNT, "Caret moved to line start");
caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 28)
);
if (isMac) {
EventUtils.synthesizeKey("KEY_ArrowRight", { metaKey: true });
} else {
EventUtils.synthesizeKey("KEY_End");
}
evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
ok(evt.isAtEndOfLine, "Caret is at end of line");
is(evt.granularity, ENDLINE_AMOUNT, "Caret moved to line end");
caretMoved = waitForEvent(
EVENT_TEXT_CARET_MOVED,
matchCaretMoveEvent("textarea", 24)
);
if (isMac) {
EventUtils.synthesizeKey("KEY_ArrowLeft", { altKey: true });
} else {
EventUtils.synthesizeKey("KEY_ArrowLeft", { ctrlKey: true });
}
evt = await caretMoved;
evt.QueryInterface(nsIAccessibleCaretMoveEvent);
ok(!evt.isAtEndOfLine, "Caret is not at end of line");
is(evt.granularity, WORD_AMOUNT, "Caret moved by word");
}
);

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

@ -224,7 +224,7 @@ async function synthKeyAndTestValueChanged(
);
}
async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
async function focusIntoInput(accDoc, inputId, innerContainerId) {
let selectionId = innerContainerId ? innerContainerId : inputId;
let input = getNativeInterface(accDoc, inputId);
ok(!input.getAttributeValue("AXFocused"), "input is not focused");
@ -249,6 +249,11 @@ async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
]);
input.setAttributeValue("AXFocused", true);
await events;
}
async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
let selectionId = innerContainerId ? innerContainerId : inputId;
await focusIntoInput(accDoc, inputId, innerContainerId);
async function testTextInput(
synthKey,
@ -337,14 +342,14 @@ async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
{ AXTextStateChangeType: AXTextStateChangeTypeSelectionMove }
);
await synthKeyAndTestSelectionChanged(
"KEY_Home",
{ shiftKey: true },
"KEY_ArrowLeft",
{ shiftKey: true, metaKey: true },
selectionId,
"hello ",
{
AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
AXTextSelectionGranularity: AXTextSelectionGranularityWord,
AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
}
);
await synthKeyAndTestSelectionChanged(
@ -372,7 +377,8 @@ addAccessibleTask(
`<a href="#">link</a> <input id="input">`,
async (browser, accDoc) => {
await focusIntoInputAndType(accDoc, "input");
}
},
{ topLevel: true, iframe: true, remoteIframe: true }
);
// Test content editable
@ -390,15 +396,6 @@ addAccessibleTask(
}
);
// Test text input in iframe
addAccessibleTask(
`<a href="#">link</a> <input id="input">`,
async (browser, accDoc) => {
await focusIntoInputAndType(accDoc, "input");
},
{ iframe: true }
);
// Test input that gets role::EDITCOMBOBOX
addAccessibleTask(`<input type="text" id="box">`, async (browser, accDoc) => {
const box = getNativeInterface(accDoc, "box");
@ -410,3 +407,48 @@ addAccessibleTask(`<input type="text" id="box">`, async (browser, accDoc) => {
);
await focusIntoInputAndType(accDoc, "box");
});
// Test multiline caret control in a text area
addAccessibleTask(
`<textarea id="input" cols="15">one two three four five six seven eight</textarea>`,
async (browser, accDoc) => {
await focusIntoInput(accDoc, "input");
await synthKeyAndTestSelectionChanged("KEY_ArrowRight", null, "input", "", {
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
AXTextSelectionDirection: AXTextSelectionDirectionNext,
AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
});
await synthKeyAndTestSelectionChanged("KEY_ArrowDown", null, "input", "", {
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
AXTextSelectionDirection: AXTextSelectionDirectionNext,
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
});
await synthKeyAndTestSelectionChanged(
"KEY_ArrowLeft",
{ metaKey: true },
"input",
"",
{
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
}
);
await synthKeyAndTestSelectionChanged(
"KEY_ArrowRight",
{ metaKey: true },
"input",
"",
{
AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
AXTextSelectionDirection: AXTextSelectionDirectionEnd,
AXTextSelectionGranularity: AXTextSelectionGranularityLine,
}
);
},
{ topLevel: true, iframe: true, remoteIframe: true }
);

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

@ -10,7 +10,9 @@
AXTextStateChangeTypeSelectionExtend, AXTextSelectionDirectionUnknown,
AXTextSelectionDirectionPrevious, AXTextSelectionDirectionNext,
AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown,
AXTextSelectionGranularityCharacter, AXTextSelectionGranularityWord */
AXTextSelectionDirectionBeginning, AXTextSelectionDirectionEnd,
AXTextSelectionGranularityCharacter, AXTextSelectionGranularityWord,
AXTextSelectionGranularityLine */
// Load the shared-head file first.
/* import-globals-from ../shared-head.js */
@ -37,6 +39,8 @@ const AXTextEditTypeTyping = 3;
// AXTextSelectionDirection enum values
const AXTextSelectionDirectionUnknown = 0;
const AXTextSelectionDirectionBeginning = 1;
const AXTextSelectionDirectionEnd = 2;
const AXTextSelectionDirectionPrevious = 3;
const AXTextSelectionDirectionNext = 4;
const AXTextSelectionDirectionDiscontiguous = 5;
@ -45,6 +49,7 @@ const AXTextSelectionDirectionDiscontiguous = 5;
const AXTextSelectionGranularityUnknown = 0;
const AXTextSelectionGranularityCharacter = 1;
const AXTextSelectionGranularityWord = 2;
const AXTextSelectionGranularityLine = 3;
function getNativeInterface(accDoc, id) {
return findAccessibleChildByID(accDoc, id).nativeInterface.QueryInterface(

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

@ -172,7 +172,8 @@ void a11y::ProxyFocusEvent(RemoteAccessible* aTarget,
}
void a11y::ProxyCaretMoveEvent(RemoteAccessible* aTarget,
const LayoutDeviceIntRect& aCaretRect) {
const LayoutDeviceIntRect& aCaretRect,
int32_t aGranularity) {
AccessibleWrap::UpdateSystemCaretFor(aTarget, aCaretRect);
MsaaAccessible::FireWinEvent(aTarget,
nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED);

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

@ -3198,6 +3198,8 @@ void Selection::NotifySelectionListeners() {
reason |= nsISelectionListener::JS_REASON;
}
int32_t amount = static_cast<int32_t>(frameSelection->GetCaretMoveAmount());
if (mNotifyAutoCopy) {
AutoCopyListener::OnSelectionChange(doc, *this, reason);
}
@ -3218,7 +3220,7 @@ void Selection::NotifySelectionListeners() {
//
// This can go away once
// https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
MOZ_KnownLive(listener)->NotifySelectionChanged(doc, this, reason);
MOZ_KnownLive(listener)->NotifySelectionChanged(doc, this, reason, amount);
}
}

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

@ -24,9 +24,21 @@ interface nsISelectionListener : nsISupports
// of Selection API or Range API.
const short JS_REASON=256;
// Values of nsSelectionAmount.
// Reflects the granularity in which the selection caret has moved.
const long CHARACTER_AMOUNT = 0;
const long CLUSTER_AMOUNT = 1;
const long WORD_AMOUNT = 2;
const long WORDNOSPACE_AMOUNT = 3;
const long LINE_AMOUNT = 4;
const long BEGINLINE_AMOUNT = 5;
const long ENDLINE_AMOUNT = 6;
const long NO_AMOUNT = 7;
const long PARAGRAPH_AMOUNT = 8;
[can_run_script]
void notifySelectionChanged(in Document doc, in Selection sel,
in short reason);
in short reason, in long amount);
};
%{C++

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

@ -195,18 +195,12 @@ nsresult CamerasParent::DispatchToVideoCaptureThread(RefPtr<Runnable> event) {
// There's a potential deadlock because the sThreadMonitor is likely
// to be taken already.
MonitorAutoLock lock(*sThreadMonitor);
MOZ_ASSERT(!sVideoCaptureThread ||
sVideoCaptureThread->thread_id() != PlatformThread::CurrentId());
while (mChildIsAlive && mWebRTCAlive &&
(!sVideoCaptureThread || !sVideoCaptureThread->IsRunning())) {
sThreadMonitor->Wait();
}
if (!sVideoCaptureThread || !sVideoCaptureThread->IsRunning()) {
LOG("Can't dispatch to video capture thread: thread not present or not "
"running");
if (!sVideoCaptureThread) {
LOG("Can't dispatch to video capture thread: thread not present");
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(sVideoCaptureThread->thread_id() != PlatformThread::CurrentId());
sVideoCaptureThread->message_loop()->PostTask(event.forget());
return NS_OK;
}
@ -230,9 +224,7 @@ void CamerasParent::StopVideoCapture() {
}
nsresult rv = NS_DispatchToMainThread(NewRunnableFrom([self, thread]() {
if (thread) {
if (thread->IsRunning()) {
thread->Stop();
}
thread->Stop();
delete thread;
}
nsresult rv = MustGetShutdownBarrier()->RemoveBlocker(self);
@ -1088,47 +1080,50 @@ NS_IMETHODIMP CamerasParent::BlockShutdown(nsIAsyncShutdownClient*) {
CamerasParent::CamerasParent()
: mName(GetNewName()),
mShmemPool(CaptureEngine::MaxEngine),
mPBackgroundEventTarget(GetCurrentSerialEventTarget()),
mChildIsAlive(true),
mDestroyed(false),
mWebRTCAlive(true) {
MOZ_ASSERT(mPBackgroundEventTarget != nullptr,
"GetCurrentThreadEventTarget failed");
LOG("CamerasParent: %p", this);
StaticMutexAutoLock slock(sMutex);
if (sNumOfCamerasParents++ == 0) {
sThreadMonitor = new Monitor("CamerasParent::sThreadMonitor");
}
}
mPBackgroundEventTarget = GetCurrentSerialEventTarget();
MOZ_ASSERT(mPBackgroundEventTarget != nullptr,
"GetCurrentThreadEventTarget failed");
ipc::IPCResult CamerasParent::RecvPCamerasConstructor() {
ipc::AssertIsOnBackgroundThread();
// Don't dispatch from the constructor a runnable that may toggle the
// reference count, because the IPC thread does not get a reference until
// after the constructor returns.
NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, [self = RefPtr(this)]() {
nsresult rv = MustGetShutdownBarrier()->AddBlocker(
self, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}));
LOG("Spinning up WebRTC Cameras Thread");
RefPtr<CamerasParent> self(this);
NS_DispatchToMainThread(NewRunnableFrom([self]() {
nsresult rv = MustGetShutdownBarrier()->AddBlocker(
self, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
// Start the thread
MonitorAutoLock lock(*(self->sThreadMonitor));
if (self->sVideoCaptureThread == nullptr) {
MOZ_ASSERT(sNumOfOpenCamerasParentEngines == 0);
self->sVideoCaptureThread = new base::Thread("VideoCapture");
base::Thread::Options options;
MonitorAutoLock lock(*sThreadMonitor);
if (sVideoCaptureThread == nullptr) {
MOZ_ASSERT(sNumOfOpenCamerasParentEngines == 0);
sVideoCaptureThread = new base::Thread("VideoCapture");
base::Thread::Options options;
#if defined(_WIN32)
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
#else
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
#endif
if (!self->sVideoCaptureThread->StartWithOptions(options)) {
MOZ_CRASH();
}
if (!sVideoCaptureThread->StartWithOptions(options)) {
MOZ_CRASH();
}
sNumOfOpenCamerasParentEngines++;
self->sThreadMonitor->NotifyAll();
return NS_OK;
}));
}
sNumOfOpenCamerasParentEngines++;
return IPC_OK();
}
CamerasParent::~CamerasParent() {

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

@ -72,7 +72,8 @@ class CamerasParent final : public PCamerasParent,
static already_AddRefed<CamerasParent> Create();
// Messages received form the child. These run on the IPC/PBackground thread.
// Messages received from the child. These run on the IPC/PBackground thread.
mozilla::ipc::IPCResult RecvPCamerasConstructor();
mozilla::ipc::IPCResult RecvAllocateCapture(
const CaptureEngine& aEngine, const nsCString& aUnique_idUTF8,
const uint64_t& aWindowID) override;
@ -137,30 +138,29 @@ class CamerasParent final : public PCamerasParent,
static nsString GetNewName();
// sEngines will be accessed by VideoCapture thread only
// sNumOfCamerasParent, sNumOfOpenCamerasParentEngines, and
// sNumOfCamerasParents, sNumOfOpenCamerasParentEngines, and
// sVideoCaptureThread will be accessed by main thread / PBackground thread /
// VideoCapture thread
// sNumOfCamerasParent and sThreadMonitor create & delete are protected by
// sNumOfCamerasParents and sThreadMonitor create & delete are protected by
// sMutex
// sNumOfOpenCamerasParentEngines and sVideoCaptureThread are protected by
// sThreadMonitor
static StaticRefPtr<VideoEngine> sEngines[CaptureEngine::MaxEngine];
static int32_t sNumOfOpenCamerasParentEngines;
static int32_t sNumOfCamerasParents;
static StaticMutex sMutex;
static Monitor* sThreadMonitor;
// video processing thread - where webrtc.org capturer code runs
static base::Thread* sVideoCaptureThread;
nsTArray<CallbackHelper*> mCallbacks;
nsString mName;
// image buffers
ShmemPool mShmemPool;
// PBackground parent thread
nsCOMPtr<nsISerialEventTarget> mPBackgroundEventTarget;
static StaticMutex sMutex;
static Monitor* sThreadMonitor;
// video processing thread - where webrtc.org capturer code runs
static base::Thread* sVideoCaptureThread;
// PBackgroundParent thread
const nsCOMPtr<nsISerialEventTarget> mPBackgroundEventTarget;
// Shutdown handling
bool mChildIsAlive;

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

@ -2178,7 +2178,8 @@ nsresult EditorBase::DeleteNodeWithTransaction(nsIContent& aContent) {
NS_IMETHODIMP EditorBase::NotifySelectionChanged(Document* aDocument,
Selection* aSelection,
int16_t aReason) {
int16_t aReason,
int32_t aAmount) {
if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
return NS_ERROR_INVALID_ARG;
}

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

@ -554,7 +554,8 @@ bool HTMLEditor::UpdateMetaCharsetWithTransaction(
NS_IMETHODIMP HTMLEditor::NotifySelectionChanged(Document* aDocument,
Selection* aSelection,
int16_t aReason) {
int16_t aReason,
int32_t aAmount) {
if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
return NS_ERROR_INVALID_ARG;
}
@ -593,8 +594,8 @@ NS_IMETHODIMP HTMLEditor::NotifySelectionChanged(Document* aDocument,
updater->OnSelectionChange();
}
nsresult rv =
EditorBase::NotifySelectionChanged(aDocument, aSelection, aReason);
nsresult rv = EditorBase::NotifySelectionChanged(aDocument, aSelection,
aReason, aAmount);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::NotifySelectionChanged() failed");
return rv;

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

@ -37,7 +37,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1053048
// synthesizing the key press. So, we don't need to check whether a
// notification actually comes here.
let selectionListener = {
notifySelectionChanged(aDocument, aSelection, aReason) {
notifySelectionChanged(aDocument, aSelection, aReason, aAmount) {
ok(true, "selectionStart: " + textarea.selectionStart);
ok(true, "selectionEnd: " + textarea.selectionEnd);
},

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

@ -1713,8 +1713,9 @@ struct NewLayerData {
ScrollableLayerGuid::ViewID mDeferredId = ScrollableLayerGuid::NULL_SCROLL_ID;
bool mTransformShouldGetOwnLayer = false;
void ComputeDeferredTransformInfo(const StackingContextHelper& aSc,
nsDisplayItem* aItem) {
void ComputeDeferredTransformInfo(
const StackingContextHelper& aSc, nsDisplayItem* aItem,
nsDisplayTransform* aLastDeferredTransform) {
// See the comments on StackingContextHelper::mDeferredTransformItem
// for an overview of what deferred transforms are.
// In the case where we deferred a transform, but have a child display
@ -1730,6 +1731,14 @@ struct NewLayerData {
// that we deferred, and a child WebRenderLayerScrollData item that
// holds the scroll metadata for the child's ASR.
mDeferredItem = aSc.GetDeferredTransformItem();
// If this deferred transform is already slated to be emitted onto an
// ancestor layer, do not emit it on this layer as well. Note that it's
// sufficient to check the most recently deferred item here, because
// there's only one per stacking context, and we emit it when changing
// stacking contexts.
if (mDeferredItem == aLastDeferredTransform) {
mDeferredItem = nullptr;
}
if (mDeferredItem) {
// It's possible the transform's ASR is not only an ancestor of
// the item's ASR, but an ancestor of stopAtAsr. In such cases,
@ -1890,7 +1899,10 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
newLayerData->mLayerCountBeforeRecursing = mLayerScrollData.size();
newLayerData->mStopAtAsr =
mAsrStack.empty() ? nullptr : mAsrStack.back();
newLayerData->ComputeDeferredTransformInfo(aSc, item);
newLayerData->ComputeDeferredTransformInfo(
aSc, item,
mDeferredTransformStack.empty() ? nullptr
: mDeferredTransformStack.back());
// Ensure our children's |stopAtAsr| is not be an ancestor of our
// |stopAtAsr|, otherwise we could get cyclic scroll metadata
@ -1910,6 +1922,13 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
newLayerData->mDeferredItem->GetActiveScrolledRoot());
}
mAsrStack.push_back(stopAtAsrForChildren);
// If we're going to emit a deferred transform onto this layer,
// keep track of that so descendant layers know not to emit the
// same deferred transform.
if (newLayerData->mDeferredItem) {
mDeferredTransformStack.push_back(newLayerData->mDeferredItem);
}
}
}
@ -1951,6 +1970,11 @@ void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
// the stack is enclosing display item's ASR (or the stack is empty)
mAsrStack.pop_back();
if (newLayerData->mDeferredItem) {
MOZ_ASSERT(!mDeferredTransformStack.empty());
mDeferredTransformStack.pop_back();
}
const ActiveScrolledRoot* stopAtAsr = newLayerData->mStopAtAsr;
int32_t descendants =

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

@ -215,6 +215,9 @@ class WebRenderCommandBuilder final {
// need this so that WebRenderLayerScrollData items that deeper in the
// tree don't duplicate scroll metadata that their ancestors already have.
std::vector<const ActiveScrolledRoot*> mAsrStack;
// A similar stack to track the deferred transform that we decided to emit
// most recently.
std::vector<nsDisplayTransform*> mDeferredTransformStack;
const ActiveScrolledRoot* mLastAsr;
WebRenderUserDataRefTable mWebRenderUserDatas;

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

@ -726,6 +726,16 @@ camera::PCamerasParent* BackgroundParentImpl::AllocPCamerasParent() {
#endif
}
#ifdef MOZ_WEBRTC
mozilla::ipc::IPCResult BackgroundParentImpl::RecvPCamerasConstructor(
camera::PCamerasParent* aActor) {
AssertIsInMainOrSocketProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
return static_cast<camera::CamerasParent*>(aActor)->RecvPCamerasConstructor();
}
#endif
bool BackgroundParentImpl::DeallocPCamerasParent(
camera::PCamerasParent* aActor) {
AssertIsInMainOrSocketProcess();

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

@ -254,7 +254,10 @@ class BackgroundParentImpl : public PBackgroundParent,
PServiceWorkerManagerParent* aActor) override;
PCamerasParent* AllocPCamerasParent() override;
#ifdef MOZ_WEBRTC
mozilla::ipc::IPCResult RecvPCamerasConstructor(
PCamerasParent* aActor) override;
#endif
bool DeallocPCamerasParent(PCamerasParent* aActor) override;
mozilla::ipc::IPCResult RecvShutdownServiceWorkerRegistrar() override;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,16 @@
<style>
#a {
line-height: 41%;
flex: -1; transform: translatex(0)
}
.b {
overflow-y: scroll;
opacity: -1;
}
</style>
<h1 id="a">
<ol class="b">
<li>
<label class="b">
<menu style="position: fixed">x</menu>

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

@ -563,8 +563,8 @@ load 1723200.html
load 1729578.html
load 1729581.html
load 1734007.html
asserts-if(Android,0-1000) load 1749190.html
load 1745860.html
pref(layout.accessiblecaret.enabled,true) load 1746989.html
load 1752649.html
load 1753779.html
pref(layout.css.backdrop-filter.enabled,true) load 1755790.html

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

@ -569,8 +569,8 @@ void nsCaret::PaintCaret(DrawTarget& aDrawTarget, nsIFrame* aForFrame,
}
NS_IMETHODIMP
nsCaret::NotifySelectionChanged(Document*, Selection* aDomSel,
int16_t aReason) {
nsCaret::NotifySelectionChanged(Document*, Selection* aDomSel, int16_t aReason,
int32_t aAmount) {
// Note that aDomSel, per the comment below may not be the same as our
// selection, but that's OK since if that is the case, it wouldn't have
// mattered what IsVisible() returns here, so we just opt for checking

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

@ -2824,7 +2824,7 @@ NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage) {
}
NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(
Document*, Selection*, int16_t aReason) {
Document*, Selection*, int16_t aReason, int32_t aAmount) {
if (!mDocViewer) {
return NS_OK;
}

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

@ -729,6 +729,8 @@ nsresult nsFrameSelection::MoveCaret(nsDirection aDirection,
SetChangeReasons(nsISelectionListener::KEYPRESS_REASON);
}
mCaretMoveAmount = aAmount;
AutoPrepareFocusRange prep(sel, false);
// we must keep this around and revalidate it when its just UP/DOWN
@ -2170,6 +2172,7 @@ void nsFrameSelection::EndBatchChanges(const char* aRequesterFuncName,
if (mBatching.mCounter == 0 && mBatching.mChangesDuringBatching) {
AddChangeReasons(aReasons);
mCaretMoveAmount = eSelectNoAmount;
mBatching.mChangesDuringBatching = false;
// Be aware, the Selection instance may be destroyed after this call.
NotifySelectionListeners(SelectionType::eNormal);
@ -2182,6 +2185,7 @@ nsresult nsFrameSelection::NotifySelectionListeners(
if (index >= 0 && mDomSelections[index]) {
RefPtr<Selection> selection = mDomSelections[index];
selection->NotifySelectionListeners();
mCaretMoveAmount = eSelectNoAmount;
return NS_OK;
}
return NS_ERROR_FAILURE;

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

@ -829,6 +829,8 @@ class nsFrameSelection final {
return retval;
}
nsSelectionAmount GetCaretMoveAmount() { return mCaretMoveAmount; }
bool IsUserSelectionReason() const {
return (mSelectionChangeReasons &
(nsISelectionListener::DRAG_REASON |
@ -1047,6 +1049,7 @@ class nsFrameSelection final {
int16_t mSelectionChangeReasons = nsISelectionListener::NO_REASON;
// For visual display purposes.
int16_t mDisplaySelection = nsISelectionController::SELECTION_OFF;
nsSelectionAmount mCaretMoveAmount = eSelectNoAmount;
struct Caret {
// Hint to tell if the selection is at the end of this line or beginning of

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

@ -737,10 +737,6 @@ optgroup:before {
input, textarea, select, button {
-moz-user-input: none !important;
}
input[type=file] {
height: 2em;
}
}
progress {

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

@ -7,6 +7,9 @@
#include "SandboxTestingChild.h"
#include "mozilla/StaticPrefs_security.h"
#ifdef XP_MACOSX
# include "nsCocoaFeatures.h"
#endif
#include "nsXULAppAPI.h"
#ifdef XP_UNIX
@ -36,7 +39,12 @@
#endif
#ifdef XP_MACOSX
# include <spawn.h>
# include <CoreFoundation/CoreFoundation.h>
# include <CoreGraphics/CoreGraphics.h>
namespace ApplicationServices {
# include <ApplicationServices/ApplicationServices.h>
}
#endif
#ifdef XP_WIN
@ -146,6 +154,86 @@ static void FileTest(const nsCString& aName, const char* aSpecialDirName,
}
#endif
#ifdef XP_MACOSX
/*
* Test if this process can launch another process with posix_spawnp,
* exec, and LSOpenCFURLRef. All launches are expected to fail. In processes
* where the sandbox permits reading of file metadata (content processes at
* this time), we expect the posix_spawnp error to be EPERM. In processes
* without that permission, we expect ENOENT. Changing the sandbox policy
* may break this assumption, but the important aspect to test for is that the
* launch is not permitted.
*/
void RunMacTestLaunchProcess(SandboxTestingChild* child,
int aPosixSpawnExpectedError = ENOENT) {
// Test that posix_spawnp fails
char* argv[2];
argv[0] = const_cast<char*>("bash");
argv[1] = NULL;
int rv = posix_spawnp(NULL, "/bin/bash", NULL, NULL, argv, NULL);
nsPrintfCString posixSpawnMessage("posix_spawnp returned %d, expected %d", rv,
aPosixSpawnExpectedError);
child->SendReportTestResults("posix_spawnp test"_ns,
rv == aPosixSpawnExpectedError,
posixSpawnMessage);
// Test that exec fails
child->ErrnoTest("execv /bin/bash test"_ns, false, [&] {
char* argvp = NULL;
return execv("/bin/bash", &argvp);
});
// Test that launching an application using LSOpenCFURLRef fails
char* uri;
if (nsCocoaFeatures::OnCatalinaOrLater()) {
uri = const_cast<char*>("/System/Applications/Utilities/Console.app");
} else {
uri = const_cast<char*>("/Applications/Utilities/Console.app");
}
CFStringRef filePath = ::CFStringCreateWithCString(kCFAllocatorDefault, uri,
kCFStringEncodingUTF8);
CFURLRef urlRef = ::CFURLCreateWithFileSystemPath(
kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
if (!urlRef) {
child->SendReportTestResults("LSOpenCFURLRef"_ns, false,
"CFURLCreateWithFileSystemPath failed"_ns);
return;
}
OSStatus status = ApplicationServices::LSOpenCFURLRef(urlRef, NULL);
::CFRelease(urlRef);
nsPrintfCString lsMessage(
"LSOpenCFURLRef returned %d, "
"expected kLSServerCommunicationErr (%d)",
status, ApplicationServices::kLSServerCommunicationErr);
child->SendReportTestResults(
"LSOpenCFURLRef"_ns,
status == ApplicationServices::kLSServerCommunicationErr, lsMessage);
}
/*
* Test if this process can connect to the macOS window server.
* When |aShouldHaveAccess| is true, the test passes if access is __permitted__.
* When |aShouldHaveAccess| is false, the test passes if access is __blocked__.
*/
void RunMacTestWindowServer(SandboxTestingChild* child,
bool aShouldHaveAccess = false) {
// CGSessionCopyCurrentDictionary() returns NULL when a
// connection to the window server is not available.
CFDictionaryRef windowServerDict = CGSessionCopyCurrentDictionary();
bool gotWindowServerDetails = (windowServerDict != nullptr);
bool testPassed = (gotWindowServerDetails == aShouldHaveAccess);
child->SendReportTestResults(
"CGSessionCopyCurrentDictionary"_ns, testPassed,
gotWindowServerDetails
? "dictionary returned, access is permitted"_ns
: "no dictionary returned, access appears blocked"_ns);
if (windowServerDict != nullptr) {
CFRelease(windowServerDict);
}
}
#endif /* XP_MACOSX */
void RunTestsContent(SandboxTestingChild* child) {
MOZ_ASSERT(child, "No SandboxTestingChild*?");
@ -296,18 +384,8 @@ void RunTestsContent(SandboxTestingChild* child) {
# endif // XP_LINUX
# ifdef XP_MACOSX
// Test that content processes can not connect to the macOS window server.
// CGSessionCopyCurrentDictionary() returns NULL when a connection to the
// window server is not available.
CFDictionaryRef windowServerDict = CGSessionCopyCurrentDictionary();
bool gotWindowServerDetails = (windowServerDict != nullptr);
child->SendReportTestResults(
"CGSessionCopyCurrentDictionary"_ns, !gotWindowServerDetails,
gotWindowServerDetails ? "Failed: dictionary unexpectedly returned"_ns
: "Succeeded: no dictionary returned"_ns);
if (windowServerDict != nullptr) {
CFRelease(windowServerDict);
}
RunMacTestLaunchProcess(child, EPERM);
RunMacTestWindowServer(child);
# endif
#elif XP_WIN
@ -385,9 +463,11 @@ void RunTestsSocket(SandboxTestingChild* child) {
child->ErrnoTest("getcpu"_ns, true,
[&] { return syscall(SYS_getcpu, &c, NULL, NULL); });
# endif // XP_LINUX
#elif XP_MACOSX
RunMacTestLaunchProcess(child);
RunMacTestWindowServer(child);
#else // XP_UNIX
child->ReportNoTests();
child->ReportNoTests();
#endif // XP_UNIX
}
@ -440,8 +520,11 @@ void RunTestsRDD(SandboxTestingChild* child) {
int c;
child->ErrnoTest("getcpu"_ns, true,
[&] { return syscall(SYS_getcpu, &c, NULL, NULL); });
# endif // XP_LINUX
#else // XP_UNIX
# elif XP_MACOSX
RunMacTestLaunchProcess(child);
RunMacTestWindowServer(child);
# endif
#else // XP_UNIX
child->ReportNoTests();
#endif
}
@ -487,8 +570,12 @@ void RunTestsGMPlugin(SandboxTestingChild* child) {
return fd;
});
}
# endif // XP_LINUX
#else // XP_UNIX
# elif XP_MACOSX // XP_LINUX
RunMacTestLaunchProcess(child);
/* The Mac GMP process requires access to the window server */
RunMacTestWindowServer(child, true /* aShouldHaveAccess */);
# endif // XP_MACOSX
#else // XP_UNIX
child->ReportNoTests();
#endif
}
@ -508,9 +595,11 @@ void RunTestsUtility(SandboxTestingChild* child) {
int rv = getrusage(RUSAGE_SELF, &res);
return rv;
});
# endif // XP_LINUX
#else // XP_UNIX
# ifdef XP_WIN
# elif XP_MACOSX // XP_LINUX
RunMacTestLaunchProcess(child);
RunMacTestWindowServer(child);
# endif // XP_MACOSX
#elif XP_WIN // XP_UNIX
child->ErrnoValueTest("write_only"_ns, EACCES, [&] {
FILE* rv = fopen("test_sandbox.txt", "w");
if (rv != nullptr) {
@ -519,10 +608,9 @@ void RunTestsUtility(SandboxTestingChild* child) {
}
return -1;
});
# else // XP_WIN
child->ReportNoTests();
# endif // XP_WIN
#endif
#else // XP_UNIX
child->ReportNoTests();
#endif // XP_MACOSX
}
} // namespace mozilla

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

@ -0,0 +1,22 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Reference case</title>
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=133984">
<style>
input[type="file"] { height: auto; }
.with-outline {
outline: 2px solid teal;
}
.wrapper {
border: 2px solid fuchsia;
}
</style>
</head>
<body>
<input type="file">
<br><br>
<input type="file" class="with-outline">
<br><br>
<div class="wrapper"><input type="file"></div>
</body>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Test that file-input widgets have 'auto' height (not some other arbitrary value) when printed</title>
<meta name="assert" content="file-input widgets should have 'auto' height (not some other arbitrary value) when printed">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=133984">
<link rel="match" href="input-file-print-ref.html">
<style>
.with-outline {
outline: 2px solid teal;
}
.wrapper {
border: 2px solid fuchsia;
}
</style>
</head>
<body>
<input type="file">
<br><br>
<input type="file" class="with-outline">
<br><br>
<div class="wrapper"><input type="file"></div>
</body>