зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
e580b1098c
|
@ -319,15 +319,17 @@ class UrlbarController {
|
|||
break;
|
||||
case KeyEvent.DOM_VK_TAB:
|
||||
// It's always possible to tab through results when the urlbar was
|
||||
// focused with the mouse, or has a search string.
|
||||
// focused with the mouse or has a search string, or when the view
|
||||
// already has a selection.
|
||||
// We allow tabbing without a search string when in search mode preview,
|
||||
// since that means the user has interacted with the Urlbar since
|
||||
// opening it.
|
||||
// When there's no search string, we want to focus the next toolbar item
|
||||
// instead, for accessibility reasons.
|
||||
// When there's no search string and no view selection, we want to focus
|
||||
// the next toolbar item instead, for accessibility reasons.
|
||||
let allowTabbingThroughResults =
|
||||
this.input.focusedViaMousedown ||
|
||||
this.input.searchMode?.isPreview ||
|
||||
this.view.selectedElement ||
|
||||
(this.input.value &&
|
||||
this.input.getAttribute("pageproxystate") != "valid");
|
||||
if (
|
||||
|
|
|
@ -60,6 +60,80 @@ add_task(async function sponsoredHelpButton() {
|
|||
});
|
||||
});
|
||||
|
||||
// Tests keyboard selection using the arrow keys.
|
||||
add_task(async function arrowKeys() {
|
||||
await doKeySelectionTest(false);
|
||||
});
|
||||
|
||||
// Tests keyboard selection using the tab key.
|
||||
add_task(async function tabKey() {
|
||||
await doKeySelectionTest(true);
|
||||
});
|
||||
|
||||
async function doKeySelectionTest(useTabKey) {
|
||||
info(`Starting key selection test with useTabKey=${useTabKey}`);
|
||||
|
||||
let result = makeBestMatchResult({
|
||||
isSponsored: true,
|
||||
helpUrl: "https://example.com/help",
|
||||
});
|
||||
|
||||
await withProvider(result, async () => {
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
value: "test",
|
||||
});
|
||||
|
||||
await checkBestMatchRow({ result, isSponsored: true, hasHelpButton: true });
|
||||
|
||||
// Ordered list of class names of the elements that should be selected as
|
||||
// the tab key is pressed.
|
||||
let expectedClassNames = [
|
||||
"urlbarView-row-inner",
|
||||
"urlbarView-button-block",
|
||||
"urlbarView-button-help",
|
||||
];
|
||||
|
||||
let sendKey = reverse => {
|
||||
if (useTabKey) {
|
||||
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: reverse });
|
||||
} else if (reverse) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp");
|
||||
} else {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
};
|
||||
|
||||
// First tab in forward order and then in reverse order.
|
||||
for (let reverse of [false, true]) {
|
||||
info(`Doing key selection with reverse=${reverse}`);
|
||||
|
||||
let classNames = [...expectedClassNames];
|
||||
if (reverse) {
|
||||
classNames.reverse();
|
||||
}
|
||||
|
||||
for (let className of classNames) {
|
||||
sendKey(reverse);
|
||||
Assert.ok(gURLBar.view.isOpen, "View remains open");
|
||||
let { selectedElement } = gURLBar.view;
|
||||
Assert.ok(selectedElement, "Selected element exists");
|
||||
Assert.ok(
|
||||
selectedElement.classList.contains(className),
|
||||
"Expected element is selected"
|
||||
);
|
||||
}
|
||||
sendKey(reverse);
|
||||
Assert.ok(
|
||||
gURLBar.view.isOpen,
|
||||
"View remains open after keying through best match row"
|
||||
);
|
||||
}
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
});
|
||||
}
|
||||
|
||||
async function checkBestMatchRow({
|
||||
result,
|
||||
isSponsored = false,
|
||||
|
|
|
@ -1089,68 +1089,82 @@ nsresult EditorEventListener::Focus(InternalFocusEvent* aFocusEvent) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<EditorBase> editorBase(mEditorBase);
|
||||
|
||||
// Spell check a textarea the first time that it is focused.
|
||||
SpellCheckIfNeeded();
|
||||
if (DetachedFromEditor()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> eventTargetNode =
|
||||
nsCOMPtr<nsINode> originalEventTargetNode =
|
||||
nsINode::FromEventTargetOrNull(aFocusEvent->GetOriginalDOMEventTarget());
|
||||
if (NS_WARN_IF(!eventTargetNode)) {
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!originalEventTargetNode))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// If the target is a document node but it's not editable, we should ignore
|
||||
// it because actual focused element's event is going to come.
|
||||
if (eventTargetNode->IsDocument() && !eventTargetNode->IsInDesignMode()) {
|
||||
// If the target is a document node but it's not editable, we should
|
||||
// ignore it because actual focused element's event is going to come.
|
||||
if (originalEventTargetNode->IsDocument()) {
|
||||
if (!originalEventTargetNode->IsInDesignMode()) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// We should not receive focus events whose target is not a content node
|
||||
// unless the node is a document node.
|
||||
else if (MOZ_UNLIKELY(NS_WARN_IF(!originalEventTargetNode->IsContent()))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (eventTargetNode->IsContent()) {
|
||||
nsIContent* content =
|
||||
eventTargetNode->AsContent()->FindFirstNonChromeOnlyAccessContent();
|
||||
// XXX If the focus event target is a form control in contenteditable
|
||||
// element, perhaps, the parent HTML editor should do nothing by this
|
||||
// handler. However, FindSelectionRoot() returns the root element of the
|
||||
// contenteditable editor. So, the editableRoot value is invalid for
|
||||
// the plain text editor, and it will be set to the wrong limiter of
|
||||
// the selection. However, fortunately, actual bugs are not found yet.
|
||||
nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(content);
|
||||
|
||||
// make sure that the element is really focused in case an earlier
|
||||
// listener in the chain changed the focus.
|
||||
if (editableRoot) {
|
||||
nsFocusManager* focusManager = nsFocusManager::GetFocusManager();
|
||||
if (NS_WARN_IF(!focusManager)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent* focusedContent = focusManager->GetFocusedElement();
|
||||
if (!focusedContent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> originalTargetAsContent =
|
||||
do_QueryInterface(aFocusEvent->GetOriginalDOMEventTarget());
|
||||
|
||||
if (!SameCOMIdentity(
|
||||
focusedContent->FindFirstNonChromeOnlyAccessContent(),
|
||||
originalTargetAsContent->FindFirstNonChromeOnlyAccessContent())) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
RefPtr<nsFocusManager> focusManager = nsFocusManager::GetFocusManager();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!focusManager))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
editorBase->OnFocus(*eventTargetNode);
|
||||
auto CanKeepHandlingFocusEvent = [&]() -> bool {
|
||||
if (this->DetachedFromEditor()) {
|
||||
return false;
|
||||
}
|
||||
// If the event target is document mode, we only need to handle the focus
|
||||
// event when the document is still in designMode. Otherwise, the
|
||||
// mode has been disabled by somebody while we're handling the focus event.
|
||||
if (originalEventTargetNode->IsDocument()) {
|
||||
return originalEventTargetNode->IsInDesignMode();
|
||||
}
|
||||
MOZ_ASSERT(originalEventTargetNode->IsContent());
|
||||
// If nobody has focus, the focus event target has been blurred by somebody
|
||||
// else. So the editor shouldn't initialize itself to start to handle
|
||||
// anything.
|
||||
if (!focusManager->GetFocusedElement()) {
|
||||
return false;
|
||||
}
|
||||
const nsIContent* const exposedTargetContent =
|
||||
originalEventTargetNode->AsContent()
|
||||
->FindFirstNonChromeOnlyAccessContent();
|
||||
const nsIContent* const exposedFocusedContent =
|
||||
focusManager->GetFocusedElement()
|
||||
->FindFirstNonChromeOnlyAccessContent();
|
||||
return exposedTargetContent && exposedFocusedContent &&
|
||||
exposedTargetContent == exposedFocusedContent;
|
||||
};
|
||||
|
||||
RefPtr<PresShell> presShell = GetPresShell();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!presShell))) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Let's update the layout information right now because there are some
|
||||
// pending notifications and flushing them may cause destroying the editor.
|
||||
presShell->FlushPendingNotifications(FlushType::Layout);
|
||||
if (MOZ_UNLIKELY(!CanKeepHandlingFocusEvent())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Spell check a textarea the first time that it is focused.
|
||||
SpellCheckIfNeeded();
|
||||
if (MOZ_UNLIKELY(!CanKeepHandlingFocusEvent())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<EditorBase> editorBase(mEditorBase);
|
||||
editorBase->OnFocus(*originalEventTargetNode);
|
||||
if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsPresContext> presContext = GetPresContext();
|
||||
if (NS_WARN_IF(!presContext)) {
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!presContext))) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIContent> focusedContent = editorBase->GetFocusedContent();
|
||||
|
|
|
@ -2732,7 +2732,7 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
|
|||
// gesture block.
|
||||
overscrollHandoffChain->SnapBackOverscrolledApzcForMomentum(
|
||||
this, GetVelocityVector());
|
||||
// If this APZC is overscrolled, the above SnapBackOverscrolledApzcForMomemtum
|
||||
// If this APZC is overscrolled, the above SnapBackOverscrolledApzcForMomentum
|
||||
// triggers an overscroll animation, do not reset the state in such case.
|
||||
if (mState != OVERSCROLL_ANIMATION) {
|
||||
SetState(NOTHING);
|
||||
|
|
|
@ -210,10 +210,21 @@ void Axis::EndOverscrollAnimation() {
|
|||
mMSDModel.SetVelocity(0.0);
|
||||
}
|
||||
|
||||
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
|
||||
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta,
|
||||
SideBits aOverscrollSideBits) {
|
||||
mMSDModel.Simulate(aDelta);
|
||||
mOverscroll = mMSDModel.GetPosition();
|
||||
|
||||
if (((aOverscrollSideBits & (SideBits::eTop | SideBits::eLeft)) &&
|
||||
mOverscroll > 0) ||
|
||||
((aOverscrollSideBits & (SideBits::eBottom | SideBits::eRight)) &&
|
||||
mOverscroll < 0)) {
|
||||
// Stop the overscroll model immediately if it's going to get across the
|
||||
// boundary.
|
||||
mMSDModel.SetPosition(0.0);
|
||||
mMSDModel.SetVelocity(0.0);
|
||||
}
|
||||
|
||||
AXIS_LOG("%p|%s changed overscroll amount to %f\n", mAsyncPanZoomController,
|
||||
Name(), mOverscroll.value);
|
||||
|
||||
|
|
|
@ -155,9 +155,11 @@ class Axis {
|
|||
|
||||
/**
|
||||
* Sample the snap-back animation to relieve overscroll.
|
||||
* |aDelta| is the time since the last sample.
|
||||
* |aDelta| is the time since the last sample, |aOverscrollSideBits| is
|
||||
* the direction where the overscroll happens on this axis.
|
||||
*/
|
||||
bool SampleOverscrollAnimation(const TimeDuration& aDelta);
|
||||
bool SampleOverscrollAnimation(const TimeDuration& aDelta,
|
||||
SideBits aOverscrollSideBits);
|
||||
|
||||
/**
|
||||
* Stop an overscroll animation.
|
||||
|
|
|
@ -21,7 +21,12 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
|
|||
OverscrollAnimation(AsyncPanZoomController& aApzc,
|
||||
const ParentLayerPoint& aVelocity,
|
||||
SideBits aOverscrollSideBits)
|
||||
: mApzc(aApzc) {
|
||||
: mApzc(aApzc), mOverscrollSideBits(aOverscrollSideBits) {
|
||||
MOZ_ASSERT(
|
||||
(mOverscrollSideBits & SideBits::eTopBottom) != SideBits::eTopBottom &&
|
||||
(mOverscrollSideBits & SideBits::eLeftRight) !=
|
||||
SideBits::eLeftRight,
|
||||
"Don't allow overscrolling on both sides at the same time");
|
||||
if ((aOverscrollSideBits & SideBits::eLeftRight) != SideBits::eNone) {
|
||||
mApzc.mX.StartOverscrollAnimation(aVelocity.x);
|
||||
}
|
||||
|
@ -38,9 +43,11 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
|
|||
const TimeDuration& aDelta) override {
|
||||
// Can't inline these variables due to short-circuit evaluation.
|
||||
bool continueX = mApzc.mX.IsOverscrollAnimationAlive() &&
|
||||
mApzc.mX.SampleOverscrollAnimation(aDelta);
|
||||
mApzc.mX.SampleOverscrollAnimation(
|
||||
aDelta, mOverscrollSideBits & SideBits::eLeftRight);
|
||||
bool continueY = mApzc.mY.IsOverscrollAnimationAlive() &&
|
||||
mApzc.mY.SampleOverscrollAnimation(aDelta);
|
||||
mApzc.mY.SampleOverscrollAnimation(
|
||||
aDelta, mOverscrollSideBits & SideBits::eTopBottom);
|
||||
if (!continueX && !continueY) {
|
||||
// If we got into overscroll from a fling, that fling did not request a
|
||||
// fling snap to avoid a resulting scrollTo from cancelling the overscroll
|
||||
|
@ -75,6 +82,8 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
|
|||
// the pan momentum displacement is the same direction of the current
|
||||
// overscroll.
|
||||
mApzc.mX.StartOverscrollAnimation(mApzc.mX.GetVelocity());
|
||||
mOverscrollSideBits |=
|
||||
xOverscroll > 0 ? SideBits::eRight : SideBits::eLeft;
|
||||
}
|
||||
} else if ((xOverscroll > 0 && aDisplacement.x < 0) ||
|
||||
(xOverscroll < 0 && aDisplacement.x > 0)) {
|
||||
|
@ -89,6 +98,8 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
|
|||
(yOverscroll < 0 && aDisplacement.y < 0)) {
|
||||
if (!mApzc.mY.IsOverscrollAnimationRunning()) {
|
||||
mApzc.mY.StartOverscrollAnimation(mApzc.mY.GetVelocity());
|
||||
mOverscrollSideBits |=
|
||||
yOverscroll > 0 ? SideBits::eBottom : SideBits::eTop;
|
||||
}
|
||||
} else if ((yOverscroll > 0 && aDisplacement.y < 0) ||
|
||||
(yOverscroll < 0 && aDisplacement.y > 0)) {
|
||||
|
@ -118,6 +129,7 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
|
|||
|
||||
private:
|
||||
AsyncPanZoomController& mApzc;
|
||||
SideBits mOverscrollSideBits;
|
||||
};
|
||||
|
||||
// Base class for different overscroll effects;
|
||||
|
|
|
@ -1773,6 +1773,91 @@ TEST_F(APZCOverscrollTesterMock,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
||||
TEST_F(APZCOverscrollTesterMock, RetriggeredOverscrollAnimationVelocity) {
|
||||
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
||||
|
||||
// Setup two nested vertical scrollable frames.
|
||||
const char* treeShape = "x(x)";
|
||||
nsIntRegion layerVisibleRegion[] = {nsIntRegion(IntRect(0, 0, 100, 100)),
|
||||
nsIntRegion(IntRect(0, 0, 100, 50))};
|
||||
CreateScrollData(treeShape, layerVisibleRegion);
|
||||
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
||||
CSSRect(0, 0, 100, 200));
|
||||
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
||||
CSSRect(0, 0, 100, 200));
|
||||
|
||||
SetScrollHandoff(layers[1], root);
|
||||
|
||||
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
||||
UpdateHitTestingTree();
|
||||
rootApzc = ApzcOf(root);
|
||||
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
||||
|
||||
ScreenIntPoint panPoint(50, 20);
|
||||
// A vertical upward pan gesture on the child scroller which should be handed
|
||||
// off the root APZC.
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
||||
ScreenPoint(0, -2), mcc->Time());
|
||||
mcc->AdvanceByMillis(10);
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
||||
ScreenPoint(0, -10), mcc->Time());
|
||||
mcc->AdvanceByMillis(10);
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
||||
ScreenPoint(0, 0), mcc->Time());
|
||||
|
||||
// The root APZC should be overscrolled and the child APZC should not be.
|
||||
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
||||
EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled());
|
||||
|
||||
mcc->AdvanceByMillis(10);
|
||||
|
||||
// Make sure the root APZC is still overscrolled and there's an overscroll
|
||||
// animation.
|
||||
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
||||
EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning());
|
||||
|
||||
// And make sure the overscroll animation's velocity is a certain amount in
|
||||
// the upward direction.
|
||||
EXPECT_LT(rootApzc->GetVelocityVector().y, 0);
|
||||
|
||||
// Start a new downward pan gesture on the child scroller which
|
||||
// should be handled by the child APZC now.
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
||||
ScreenPoint(0, 2), mcc->Time());
|
||||
mcc->AdvanceByMillis(10);
|
||||
// The new pan-start gesture stops the overscroll animation at this moment.
|
||||
EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning());
|
||||
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
||||
ScreenPoint(0, 10), mcc->Time());
|
||||
mcc->AdvanceByMillis(10);
|
||||
// There's no overscroll animation yet even if the root APZC is still
|
||||
// overscrolled.
|
||||
EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning());
|
||||
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
||||
|
||||
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
||||
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
||||
ScreenPoint(0, 10), mcc->Time());
|
||||
|
||||
// Now an overscroll animation should have been triggered by the pan-end
|
||||
// gesture.
|
||||
EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning());
|
||||
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
||||
// And the newly created overscroll animation's positions should never exceed
|
||||
// 0.
|
||||
while (SampleAnimationsOnce()) {
|
||||
EXPECT_LE(rootApzc->GetOverscrollAmount().y, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
||||
TEST_F(APZCOverscrollTesterMock, OverscrollIntoPreventDefault) {
|
||||
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
||||
|
|
|
@ -10781,6 +10781,13 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# When this pref is true, we will use the HTTPS acceptable content encoding
|
||||
# list for trustworthy domains such as http://localhost
|
||||
- name: network.http.encoding.trustworthy_is_https
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Support http3 version1
|
||||
- name: network.http.http3.support_version1
|
||||
type: RelaxedAtomicBool
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/PerformanceStorage.h"
|
||||
#include "mozilla/dom/ProcessIsolation.h"
|
||||
|
@ -339,7 +340,10 @@ nsresult HttpBaseChannel::Init(nsIURI* aURI, uint32_t aCaps,
|
|||
// Construct connection info object
|
||||
nsAutoCString host;
|
||||
int32_t port = -1;
|
||||
bool isHTTPS = mURI->SchemeIs("https");
|
||||
bool isHTTPS =
|
||||
StaticPrefs::network_http_encoding_trustworthy_is_https()
|
||||
? nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(mURI)
|
||||
: mURI->SchemeIs("https");
|
||||
|
||||
nsresult rv = mURI->GetAsciiHost(host);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -1254,7 +1258,12 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
|
|||
break;
|
||||
}
|
||||
|
||||
if (gHttpHandler->IsAcceptableEncoding(val, mURI->SchemeIs("https"))) {
|
||||
bool isHTTPS =
|
||||
StaticPrefs::network_http_encoding_trustworthy_is_https()
|
||||
? nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(mURI)
|
||||
: mURI->SchemeIs("https");
|
||||
|
||||
if (gHttpHandler->IsAcceptableEncoding(val, isHTTPS)) {
|
||||
RefPtr<nsHTTPCompressConv> converter = new nsHTTPCompressConv();
|
||||
nsAutoCString from(val);
|
||||
ToLowerCase(from);
|
||||
|
|
|
@ -17,28 +17,55 @@ XPCOMUtils.defineLazyGetter(this, "URL", function() {
|
|||
|
||||
var httpServer = null;
|
||||
|
||||
add_task(async function test() {
|
||||
add_task(async function check_brotli() {
|
||||
httpServer = new HttpServer();
|
||||
httpServer.registerPathHandler("/content", contentHandler);
|
||||
httpServer.start(-1);
|
||||
|
||||
async function test() {
|
||||
let chan = NetUtil.newChannel({ uri: URL, loadUsingSystemPrincipal: true });
|
||||
let [, buff] = await new Promise(resolve => {
|
||||
chan.asyncOpen(
|
||||
new ChannelListener(
|
||||
(req, buff) => {
|
||||
resolve([req, buff]);
|
||||
},
|
||||
null,
|
||||
CL_IGNORE_CL
|
||||
)
|
||||
);
|
||||
});
|
||||
return buff;
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref(
|
||||
"network.http.encoding.trustworthy_is_https",
|
||||
true
|
||||
);
|
||||
equal(
|
||||
await test(),
|
||||
"hello",
|
||||
"Should decode brotli when trustworthy_is_https=true"
|
||||
);
|
||||
Services.prefs.setBoolPref(
|
||||
"network.http.encoding.trustworthy_is_https",
|
||||
false
|
||||
);
|
||||
equal(
|
||||
await test(),
|
||||
"\x0b\x02\x80hello\x03",
|
||||
"Should not decode brotli when trustworthy_is_https=false"
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"network.http.accept-encoding",
|
||||
"gzip, deflate, br"
|
||||
);
|
||||
|
||||
let chan = NetUtil.newChannel({ uri: URL, loadUsingSystemPrincipal: true });
|
||||
let [, buff] = await new Promise(resolve => {
|
||||
chan.asyncOpen(
|
||||
new ChannelListener(
|
||||
(req, buff) => {
|
||||
resolve([req, buff]);
|
||||
},
|
||||
null,
|
||||
CL_IGNORE_CL
|
||||
)
|
||||
);
|
||||
});
|
||||
equal(buff, "hello");
|
||||
equal(
|
||||
await test(),
|
||||
"hello",
|
||||
"Should decode brotli if we set the HTTP accept encoding to include brotli"
|
||||
);
|
||||
Services.prefs.clearUserPref("network.http.accept-encoding");
|
||||
Services.prefs.clearUserPref("network.http.encoding.trustworthy_is_https");
|
||||
await httpServer.stop();
|
||||
});
|
||||
|
|
|
@ -181,6 +181,7 @@ function run_test() {
|
|||
prefs = Services.prefs;
|
||||
cePref = prefs.getCharPref("network.http.accept-encoding");
|
||||
prefs.setCharPref("network.http.accept-encoding", "gzip, deflate, br");
|
||||
prefs.setBoolPref("network.http.encoding.trustworthy_is_https", false);
|
||||
|
||||
httpserver.registerPathHandler("/test/cegzip1", handler);
|
||||
httpserver.registerPathHandler("/test/cegzip2", handler);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="test-wait">
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
addEventListener("load", () => {
|
||||
const editingHost = document.querySelector("div[contenteditable]");
|
||||
editingHost.addEventListener("focus", () => {
|
||||
document.execCommand("insertText", false, "def");
|
||||
editingHost.parentElement.setAttribute("hidden", "hidden");
|
||||
setTimeout(() => document.documentElement.removeAttribute("class"), 0);
|
||||
});
|
||||
editingHost.focus();
|
||||
});
|
||||
</script>
|
||||
<div><div contenteditable>abc</div></div>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="test-wait">
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
addEventListener("load", () => {
|
||||
const parentDocument = document;
|
||||
const iframe = parentDocument.querySelector("iframe");
|
||||
iframe.contentDocument.designMode = "on";
|
||||
iframe.contentWindow.addEventListener("focus", () => {
|
||||
iframe.contentDocument.execCommand("insertText", false, "def");
|
||||
iframe.parentElement.setAttribute("hidden", "hidden");
|
||||
setTimeout(() => parentDocument.documentElement.removeAttribute("class"), 0);
|
||||
});
|
||||
iframe.contentWindow.focus();
|
||||
});
|
||||
</script>
|
||||
<div><iframe srcdoc="<div>abc</div>"></iframe></div>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="test-wait">
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
addEventListener("load", () => {
|
||||
const textarea = document.querySelector("textarea");
|
||||
textarea.addEventListener("focus", () => {
|
||||
textarea.select();
|
||||
textarea.parentElement.setAttribute("hidden", "hidden");
|
||||
setTimeout(() => document.documentElement.removeAttribute("class"), 0);
|
||||
});
|
||||
textarea.focus();
|
||||
});
|
||||
</script>
|
||||
<div><textarea>abc</textarea></div>
|
||||
</html>
|
|
@ -813,8 +813,11 @@ CSS-COLLIDING-REF-NAME: css/css-break/background-image-001-ref.html
|
|||
|
||||
# Ported crashtests from Mozilla
|
||||
SET TIMEOUT: editing/crashtests/backcolor-in-nested-editing-host-td-from-DOMAttrModified.html
|
||||
SET TIMEOUT: editing/crashtests/contenteditable-will-be-blurred-by-focus-event-listener.html
|
||||
SET TIMEOUT: editing/crashtests/designMode-document-will-be-blurred-by-focus-event-listener.html
|
||||
SET TIMEOUT: editing/crashtests/inserthtml-after-temporarily-removing-document-element.html
|
||||
SET TIMEOUT: editing/crashtests/inserthtml-in-text-adopted-to-other-document.html
|
||||
SET TIMEOUT: editing/crashtests/insertorderedlist-in-text-adopted-to-other-document.html
|
||||
SET TIMEOUT: editing/crashtests/make-editable-div-inline-and-set-contenteditable-of-input-to-false.html
|
||||
SET TIMEOUT: editing/crashtests/outdent-across-svg-boundary.html
|
||||
SET TIMEOUT: editing/crashtests/textarea-will-be-blurred-by-focus-event-listener.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче