Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-06-28 13:47:29 +02:00
Родитель a124ef8738 7918eeee02
Коммит 45f2e51f0a
246 изменённых файлов: 8249 добавлений и 3563 удалений

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

@ -12,12 +12,9 @@
# Generated from ./tools/rewriting/ThirdPartyPaths.txt
# awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
^browser/components/translation/cld2/.*
^build/stlport/.*
^db/sqlite3/src/.*
^dom/media/platforms/ffmpeg/libav.*
^extensions/spellcheck/hunspell/src/.*
^gfx/2d/convolver.*
^gfx/2d/image_operations.*
^gfx/angle/.*
^gfx/cairo/.*
^gfx/graphite2/.*

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

@ -33,8 +33,7 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
MOZ_ASSERT(CheckDocTree());
if (aData.NewTree().IsEmpty()) {
NS_ERROR("no children being added");
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL(this, "No children being added");
}
ProxyAccessible* parent = GetAccessible(aData.ID());
@ -158,8 +157,7 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID,
// We shouldn't actually need this because mAccessibles shouldn't have an
// entry for the document itself, but it doesn't hurt to be explicit.
if (!aRootID) {
NS_ERROR("trying to hide entire document?");
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL(this, "Trying to hide entire document?");
}
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
@ -398,8 +396,7 @@ DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
}
if (aRole > roles::LAST_ROLE) {
NS_ERROR("child sent bad role in RoleChangedEvent");
return IPC_FAIL_NO_REASON(this);
return IPC_FAIL(this, "Child sent bad role in RoleChangedEvent");
}
mRole = static_cast<a11y::role>(aRole);

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

@ -114,6 +114,9 @@ static const uintptr_t IS_PROXY = 1;
// the accessible description (help text) of this particular instance.
- (NSString*)help;
// returns the orientation (vertical, horizontal, or undefined)
- (NSString*)orientation;
- (BOOL)isEnabled;
// information about focus.

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

@ -323,6 +323,9 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
}
if ([attribute isEqualToString:NSAccessibilityHelpAttribute])
return [self help];
if ([attribute isEqualToString:NSAccessibilityOrientationAttribute])
return [self orientation];
if ([attribute isEqualToString:NSAccessibilityDOMIdentifierAttribute]) {
nsAutoString id;
if (accWrap)
@ -1067,6 +1070,28 @@ struct RoleDescrComparator
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (NSString*)orientation
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
uint64_t state;
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
state = accWrap->InteractiveState();
else if (ProxyAccessible* proxy = [self getProxyAccessible])
state = proxy->State();
else
state = 0;
if (state & states::HORIZONTAL)
return NSAccessibilityHorizontalOrientationValue;
if (state & states::VERTICAL)
return NSAccessibilityVerticalOrientationValue;
return NSAccessibilityUnknownOrientationValue;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
// objc-style description (from NSObject); not to be confused with the accessible description above.
- (NSString*)description
{

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

@ -43,6 +43,9 @@ with Files("test/newtab/**"):
with Files("test/pageinfo/**"):
BUG_COMPONENT = ("Firefox", "Page Info Window")
with Files("test/performance/browser_appmenu_reflows.js"):
BUG_COMPONENT = ("Firefox", "Menus")
with Files("test/permissions/**"):
BUG_COMPONENT = ("Firefox", "Preferences")

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

@ -114,6 +114,7 @@ nsContextMenu.prototype = {
srcUrl: this.mediaURL,
frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
linkText: this.linkTextStr,
linkUrl: this.linkURL,
selectionText: this.isTextSelected ? this.selectionInfo.text : undefined,
frameId: this.frameOuterWindowID,

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

@ -102,6 +102,7 @@ support-files =
subsuite = clipboard
[browser_urlbarUpdateForDomainCompletion.js]
[browser_urlbar_autoFill_backspaced.js]
[browser_urlbar_canonize_on_autofill.js]
[browser_urlbar_blanking.js]
support-files =
file_blank_but_not_blank.html

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

@ -40,6 +40,41 @@ add_task(async function clickSuggestion() {
await BrowserTestUtils.removeTab(tab);
});
async function testPressEnterOnSuggestion(expectedUrl = null, keyModifiers = {}) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
gURLBar.focus();
await promiseAutocompleteResultPopup("foo");
let [idx, suggestion, engineName] = await promiseFirstSuggestion();
Assert.equal(engineName,
"browser_searchSuggestionEngine%20searchSuggestionEngine.xml",
"Expected suggestion engine");
if (!expectedUrl) {
expectedUrl = Services.search.currentEngine.getSubmission(suggestion).uri.spec;
}
let promiseLoad = waitForDocLoadAndStopIt(expectedUrl);
for (let i = 0; i < idx; ++i) {
EventUtils.synthesizeKey("VK_DOWN", {});
}
EventUtils.synthesizeKey("VK_RETURN", keyModifiers);
await promiseLoad;
await BrowserTestUtils.removeTab(tab);
}
add_task(async function plainEnterOnSuggestion() {
await testPressEnterOnSuggestion();
});
add_task(async function ctrlEnterOnSuggestion() {
await testPressEnterOnSuggestion("http://www.foofoo.com/",
AppConstants.platform === "macosx" ?
{ metaKey: true } :
{ ctrlKey: true });
});
function getFirstSuggestion() {
let controller = gURLBar.popup.input.controller;
let matchCount = controller.matchCount;

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

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* This test ensures that pressing ctrl/shift+enter bypasses the autoFilled
* value, and only considers what the user typed (but not just enter).
*/
async function test_autocomplete(data) {
let {desc, typed, autofilled, modified, waitForUrl, keys} = data;
info(desc);
await promiseAutocompleteResultPopup(typed);
is(gURLBar.textValue, autofilled, "autofilled value is as expected");
let promiseLoad = waitForDocLoadAndStopIt(waitForUrl);
keys.forEach(([key, mods]) => EventUtils.synthesizeKey(key, mods || {}));
is(gURLBar.textValue, modified, "value is as expected");
await promiseLoad;
gURLBar.blur();
}
add_task(async function() {
registerCleanupFunction(async function() {
Services.prefs.clearUserPref("browser.urlbar.autoFill");
gURLBar.handleRevert();
await PlacesTestUtils.clearHistory();
});
Services.prefs.setBoolPref("browser.urlbar.autoFill", true);
// Add a typed visit, so it will be autofilled.
await PlacesTestUtils.addVisits({
uri: "http://example.com/",
transition: Ci.nsINavHistoryService.TRANSITION_TYPED
});
await test_autocomplete({ desc: "CTRL+ENTER on the autofilled part should use autofill",
typed: "exam",
autofilled: "example.com/",
modified: "example.com/",
waitForUrl: "http://example.com/",
keys: [["VK_RETURN", {}]]
});
await test_autocomplete({ desc: "CTRL+ENTER on the autofilled part should bypass autofill",
typed: "exam",
autofilled: "example.com/",
modified: "www.exam.com",
waitForUrl: "http://www.exam.com/",
keys: [["VK_RETURN", AppConstants.platform === "macosx" ?
{ metaKey: true } :
{ ctrlKey: true }]]
});
await test_autocomplete({ desc: "SHIFT+ENTER on the autofilled part should bypass autofill",
typed: "exam",
autofilled: "example.com/",
modified: "www.exam.net",
waitForUrl: "http://www.exam.net/",
keys: [["VK_RETURN", { shiftKey: true }]]
});
});

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

@ -1317,7 +1317,19 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
if (!this._deferredKeyEventQueue.length &&
(this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery)) {
this.maybeCanonizeURL(event, this.value);
let canonizeValue = this.value;
if (event.shiftKey || (AppConstants.platform === "macosx" ?
event.metaKey :
event.ctrlKey)) {
let action = this._parseActionUrl(canonizeValue);
if (action && "searchSuggestion" in action.params) {
canonizeValue = action.params.searchSuggestion;
} else if (this.popup.selectedIndex === 0 &&
this.mController.getStyleAt(0).includes("autofill")) {
canonizeValue = this.handleEnterSearchString;
}
}
this.maybeCanonizeURL(event, canonizeValue);
let handled = this.mController.handleEnter(false, event);
this.handleEnterSearchString = null;
this.popup.overrideValue = null;

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

@ -96,11 +96,11 @@ function getObserver() {
onDeleteURI: function(uri, guid, reason) {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
},
onVisit: function(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed) {
onVisit: function(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
let data = {
id: guid,
url: uri.spec,
title: "",
title: lastKnownTitle || "",
lastVisitTime: time / 1000, // time from Places is microseconds,
visitCount,
typedCount: typed,

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

@ -529,6 +529,7 @@ MenuItem.prototype = {
setIfDefined("parentMenuItemId", this.parentId);
setIfDefined("mediaType", mediaType);
setIfDefined("linkText", contextData.linkText);
setIfDefined("linkUrl", contextData.linkUrl);
setIfDefined("srcUrl", contextData.srcUrl);
setIfDefined("pageUrl", contextData.pageUrl);

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

@ -72,6 +72,11 @@
"optional": true,
"description": "One of 'image', 'video', or 'audio' if the context menu was activated on one of these types of elements."
},
"linkText": {
"type": "string",
"optional": true,
"description": "If the element is a link, the text of that link."
},
"linkUrl": {
"type": "string",
"optional": true,

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

@ -73,7 +73,7 @@ add_task(async function() {
type: "separator",
});
let contexts = ["page", "selection", "image", "editable", "password"];
let contexts = ["page", "link", "selection", "image", "editable", "password"];
for (let i = 0; i < contexts.length; i++) {
let context = contexts[i];
let title = context;
@ -183,6 +183,30 @@ add_task(async function() {
checkClickInfo(result);
// Test "link" context and OnClick data property.
extensionMenuRoot = await openExtensionContextMenu("[href=some-link]");
// Click on ext-link and check the click results
items = extensionMenuRoot.getElementsByAttribute("label", "link");
is(items.length, 1, "contextMenu item for parent was found (context=link)");
let link = items[0];
expectedClickInfo = {
menuItemId: "ext-link",
linkUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/some-link",
linkText: "Some link",
pageUrl: PAGE,
editable: false,
};
await closeExtensionContextMenu(link);
result = await extension.awaitMessage("onclick");
checkClickInfo(result);
result = await extension.awaitMessage("browser.contextMenus.onClicked");
checkClickInfo(result);
// Test "editable" context and OnClick data property.
extensionMenuRoot = await openExtensionContextMenu("#edit-me");

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

@ -473,7 +473,7 @@ add_task(async function test_on_visited() {
equal(onVisited.url, expected.url, "onVisited received the expected url");
// Title will be blank until bug 1287928 lands
// https://bugzilla.mozilla.org/show_bug.cgi?id=1287928
equal(onVisited.title, "", "onVisited received a blank title");
equal(onVisited.title, expected.title, "onVisited received the expected title");
equal(onVisited.lastVisitTime, expected.time, "onVisited received the expected time");
equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
}

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

@ -43,13 +43,13 @@
<div class="radioRestoreContainer">
<input class="radioRestoreButton" id="radioRestoreAll" type="radio"
name="restore" checked="checked"/>
<label class="radioRestoreLabel" for="radioRestoreAll">&welcomeback2.label.restoreAll;</label>
<label class="radioRestoreLabel" for="radioRestoreAll">&welcomeback2.restoreAll.label;</label>
</div>
<div class="radioRestoreContainer">
<input class="radioRestoreButton" id="radioRestoreChoose" type="radio"
name="restore"/>
<label class="radioRestoreLabel" for="radioRestoreChoose">&welcomeback2.label.restoreSome;</label>
<label class="radioRestoreLabel" for="radioRestoreChoose">&welcomeback2.restoreSome.label;</label>
</div>
</div>
</div>

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

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.8.480
Current extension version is: 1.8.497
Taken from upstream commit: 2f2e539b
Taken from upstream commit: f2fcf2a5

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

@ -1128,7 +1128,8 @@ MessageHandler.prototype = {
let startCapability = createPromiseCapability();
this.streamControllers[streamId] = {
controller,
startCall: startCapability
startCall: startCapability,
isClosed: false
};
this.postMessage({
sourceName,
@ -1155,6 +1156,7 @@ MessageHandler.prototype = {
cancel: reason => {
let cancelCapability = createPromiseCapability();
this.streamControllers[streamId].cancelCall = cancelCapability;
this.streamControllers[streamId].isClosed = true;
this.postMessage({
sourceName,
targetName,
@ -1284,9 +1286,15 @@ MessageHandler.prototype = {
});
break;
case 'enqueue':
if (!this.streamControllers[data.streamId].isClosed) {
this.streamControllers[data.streamId].controller.enqueue(data.chunk);
}
break;
case 'close':
if (this.streamControllers[data.streamId].isClosed) {
break;
}
this.streamControllers[data.streamId].isClosed = true;
this.streamControllers[data.streamId].controller.close();
deleteStreamController();
break;
@ -1299,6 +1307,9 @@ MessageHandler.prototype = {
deleteStreamController();
break;
case 'cancel':
if (!this.streamSinks[data.streamId]) {
break;
}
resolveCall(this.streamSinks[data.streamId].onCancel, [data.reason]).then(() => {
sendStreamResponse({
stream: 'cancel_complete',
@ -2371,6 +2382,7 @@ function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallb
var params = {};
var rangeTransport = null;
var worker = null;
var CMapReaderFactory = _dom_utils.DOMCMapReaderFactory;
for (var key in source) {
if (key === 'url' && typeof window !== 'undefined') {
params[key] = new URL(source[key], window.location).href;
@ -2393,12 +2405,14 @@ function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallb
(0, _util.error)('Invalid PDF binary data: either typed array, string or ' + 'array-like object is expected in the data property.');
}
continue;
} else if (key === 'CMapReaderFactory') {
CMapReaderFactory = source[key];
continue;
}
params[key] = source[key];
}
params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
params.ignoreErrors = params.stopAtErrors !== true;
var CMapReaderFactory = params.CMapReaderFactory || _dom_utils.DOMCMapReaderFactory;
if (params.disableNativeImageDecoder !== undefined) {
(0, _util.deprecated)('parameter disableNativeImageDecoder, ' + 'use nativeImageDecoderSupport instead');
}
@ -2743,12 +2757,40 @@ var PDFPageProxy = function PDFPageProxyClosure() {
}
return intentState.opListReadCapability.promise;
},
getTextContent: function PDFPageProxy_getTextContent(params) {
params = params || {};
return this.transport.messageHandler.sendWithPromise('GetTextContent', {
streamTextContent(params = {}) {
const TEXT_CONTENT_CHUNK_SIZE = 100;
return this.transport.messageHandler.sendWithStream('GetTextContent', {
pageIndex: this.pageNumber - 1,
normalizeWhitespace: params.normalizeWhitespace === true,
combineTextItems: params.disableCombineTextItems !== true
}, {
highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
size(textContent) {
return textContent.items.length;
}
});
},
getTextContent: function PDFPageProxy_getTextContent(params) {
params = params || {};
let readableStream = this.streamTextContent(params);
return new Promise(function (resolve, reject) {
function pump() {
reader.read().then(function ({ value, done }) {
if (done) {
resolve(textContent);
return;
}
_util.Util.extendObj(textContent.styles, value.styles);
_util.Util.appendToArray(textContent.items, value.items);
pump();
}, reject);
}
let reader = readableStream.getReader();
let textContent = {
items: [],
styles: Object.create(null)
};
pump();
});
},
_destroy: function PDFPageProxy_destroy() {
@ -3656,8 +3698,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
}();
var version, build;
{
exports.version = version = '1.8.480';
exports.build = build = '2f2e539b';
exports.version = version = '1.8.497';
exports.build = build = 'f2fcf2a5';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@ -3775,6 +3817,9 @@ var renderTextLayer = function renderTextLayerClosure() {
}
}
task._textDivProperties.set(textDiv, textDivProperties);
if (task._textContentStream) {
task._layoutText(textDiv);
}
if (task._enhanceTextSelection) {
var angleCos = 1,
angleSin = 0;
@ -3806,7 +3851,6 @@ var renderTextLayer = function renderTextLayerClosure() {
if (task._canceled) {
return;
}
var textLayerFrag = task._container;
var textDivs = task._textDivs;
var capability = task._capability;
var textDivsLength = textDivs.length;
@ -3815,39 +3859,10 @@ var renderTextLayer = function renderTextLayerClosure() {
capability.resolve();
return;
}
var canvas = document.createElement('canvas');
canvas.mozOpaque = true;
var ctx = canvas.getContext('2d', { alpha: false });
var lastFontSize;
var lastFontFamily;
if (!task._textContentStream) {
for (var i = 0; i < textDivsLength; i++) {
var textDiv = textDivs[i];
var textDivProperties = task._textDivProperties.get(textDiv);
if (textDivProperties.isWhitespace) {
continue;
task._layoutText(textDivs[i]);
}
var fontSize = textDiv.style.fontSize;
var fontFamily = textDiv.style.fontFamily;
if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
ctx.font = fontSize + ' ' + fontFamily;
lastFontSize = fontSize;
lastFontFamily = fontFamily;
}
var width = ctx.measureText(textDiv.textContent).width;
textLayerFrag.appendChild(textDiv);
var transform = '';
if (textDivProperties.canvasWidth !== 0 && width > 0) {
textDivProperties.scale = textDivProperties.canvasWidth / width;
transform = 'scaleX(' + textDivProperties.scale + ')';
}
if (textDivProperties.angle !== 0) {
transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform;
}
if (transform !== '') {
textDivProperties.originalTransform = transform;
_dom_utils.CustomStyle.setProp('transform', textDiv, transform);
}
task._textDivProperties.set(textDiv, textDivProperties);
}
task._renderingDone = true;
capability.resolve();
@ -4077,24 +4092,34 @@ var renderTextLayer = function renderTextLayerClosure() {
}
});
}
function TextLayerRenderTask(textContent, container, viewport, textDivs, enhanceTextSelection) {
function TextLayerRenderTask({ textContent, textContentStream, container, viewport, textDivs, textContentItemsStr, enhanceTextSelection }) {
this._textContent = textContent;
this._textContentStream = textContentStream;
this._container = container;
this._viewport = viewport;
this._textDivs = textDivs || [];
this._textContentItemsStr = textContentItemsStr || [];
this._enhanceTextSelection = !!enhanceTextSelection;
this._reader = null;
this._layoutTextLastFontSize = null;
this._layoutTextLastFontFamily = null;
this._layoutTextCtx = null;
this._textDivProperties = new WeakMap();
this._renderingDone = false;
this._canceled = false;
this._capability = (0, _util.createPromiseCapability)();
this._renderTimer = null;
this._bounds = [];
this._enhanceTextSelection = !!enhanceTextSelection;
}
TextLayerRenderTask.prototype = {
get promise() {
return this._capability.promise;
},
cancel: function TextLayer_cancel() {
if (this._reader) {
this._reader.cancel();
this._reader = null;
}
this._canceled = true;
if (this._renderTimer !== null) {
clearTimeout(this._renderTimer);
@ -4102,12 +4127,71 @@ var renderTextLayer = function renderTextLayerClosure() {
}
this._capability.reject('canceled');
},
_render: function TextLayer_render(timeout) {
var textItems = this._textContent.items;
var textStyles = this._textContent.styles;
for (var i = 0, len = textItems.length; i < len; i++) {
appendText(this, textItems[i], textStyles);
_processItems(items, styleCache) {
for (let i = 0, len = items.length; i < len; i++) {
this._textContentItemsStr.push(items[i].str);
appendText(this, items[i], styleCache);
}
},
_layoutText(textDiv) {
let textLayerFrag = this._container;
let textDivProperties = this._textDivProperties.get(textDiv);
if (textDivProperties.isWhitespace) {
return;
}
let fontSize = textDiv.style.fontSize;
let fontFamily = textDiv.style.fontFamily;
if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) {
this._layoutTextCtx.font = fontSize + ' ' + fontFamily;
this._lastFontSize = fontSize;
this._lastFontFamily = fontFamily;
}
let width = this._layoutTextCtx.measureText(textDiv.textContent).width;
let transform = '';
if (textDivProperties.canvasWidth !== 0 && width > 0) {
textDivProperties.scale = textDivProperties.canvasWidth / width;
transform = 'scaleX(' + textDivProperties.scale + ')';
}
if (textDivProperties.angle !== 0) {
transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform;
}
if (transform !== '') {
textDivProperties.originalTransform = transform;
_dom_utils.CustomStyle.setProp('transform', textDiv, transform);
}
this._textDivProperties.set(textDiv, textDivProperties);
textLayerFrag.appendChild(textDiv);
},
_render: function TextLayer_render(timeout) {
let capability = (0, _util.createPromiseCapability)();
let styleCache = Object.create(null);
let canvas = document.createElement('canvas');
canvas.mozOpaque = true;
this._layoutTextCtx = canvas.getContext('2d', { alpha: false });
if (this._textContent) {
let textItems = this._textContent.items;
let textStyles = this._textContent.styles;
this._processItems(textItems, textStyles);
capability.resolve();
} else if (this._textContentStream) {
let pump = () => {
this._reader.read().then(({ value, done }) => {
if (done) {
capability.resolve();
return;
}
_util.Util.extendObj(styleCache, value.styles);
this._processItems(value.items, styleCache);
pump();
}, capability.reject);
};
this._reader = this._textContentStream.getReader();
pump();
} else {
throw new Error('Neither "textContent" nor "textContentStream"' + ' parameters specified.');
}
capability.promise.then(() => {
styleCache = null;
if (!timeout) {
render(this);
} else {
@ -4116,6 +4200,7 @@ var renderTextLayer = function renderTextLayerClosure() {
this._renderTimer = null;
}, timeout);
}
}, this._capability.reject);
},
expandTextDivs: function TextLayer_expandTextDivs(expandDivs) {
if (!this._enhanceTextSelection || !this._renderingDone) {
@ -4168,7 +4253,15 @@ var renderTextLayer = function renderTextLayerClosure() {
}
};
function renderTextLayer(renderParameters) {
var task = new TextLayerRenderTask(renderParameters.textContent, renderParameters.container, renderParameters.viewport, renderParameters.textDivs, renderParameters.enhanceTextSelection);
var task = new TextLayerRenderTask({
textContent: renderParameters.textContent,
textContentStream: renderParameters.textContentStream,
container: renderParameters.container,
viewport: renderParameters.viewport,
textDivs: renderParameters.textDivs,
textContentItemsStr: renderParameters.textContentItemsStr,
enhanceTextSelection: renderParameters.enhanceTextSelection
});
task._render(renderParameters.timeout);
return task;
}
@ -4659,8 +4752,8 @@ if (!_util.globalScope.PDFJS) {
}
var PDFJS = _util.globalScope.PDFJS;
{
PDFJS.version = '1.8.480';
PDFJS.build = '2f2e539b';
PDFJS.version = '1.8.497';
PDFJS.build = 'f2fcf2a5';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {
@ -10007,8 +10100,8 @@ exports.TilingPattern = TilingPattern;
"use strict";
var pdfjsVersion = '1.8.480';
var pdfjsBuild = '2f2e539b';
var pdfjsVersion = '1.8.497';
var pdfjsBuild = 'f2fcf2a5';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);

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

@ -1128,7 +1128,8 @@ MessageHandler.prototype = {
let startCapability = createPromiseCapability();
this.streamControllers[streamId] = {
controller,
startCall: startCapability
startCall: startCapability,
isClosed: false
};
this.postMessage({
sourceName,
@ -1155,6 +1156,7 @@ MessageHandler.prototype = {
cancel: reason => {
let cancelCapability = createPromiseCapability();
this.streamControllers[streamId].cancelCall = cancelCapability;
this.streamControllers[streamId].isClosed = true;
this.postMessage({
sourceName,
targetName,
@ -1284,9 +1286,15 @@ MessageHandler.prototype = {
});
break;
case 'enqueue':
if (!this.streamControllers[data.streamId].isClosed) {
this.streamControllers[data.streamId].controller.enqueue(data.chunk);
}
break;
case 'close':
if (this.streamControllers[data.streamId].isClosed) {
break;
}
this.streamControllers[data.streamId].isClosed = true;
this.streamControllers[data.streamId].controller.close();
deleteStreamController();
break;
@ -1299,6 +1307,9 @@ MessageHandler.prototype = {
deleteStreamController();
break;
case 'cancel':
if (!this.streamSinks[data.streamId]) {
break;
}
resolveCall(this.streamSinks[data.streamId].onCancel, [data.reason]).then(() => {
sendStreamResponse({
stream: 'cancel_complete',
@ -17476,7 +17487,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
throw reason;
});
},
getTextContent({ stream, task, resources, stateManager = null, normalizeWhitespace = false, combineTextItems = false }) {
getTextContent({ stream, task, resources, stateManager = null, normalizeWhitespace = false, combineTextItems = false, sink, seenStyles = Object.create(null) }) {
resources = resources || _primitives.Dict.empty;
stateManager = stateManager || new StateManager(new TextState());
var WhitespaceRegexp = /\s/g;
@ -17507,7 +17518,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
var self = this;
var xref = this.xref;
var xobjs = null;
var xobjsCache = Object.create(null);
var skipEmptyXObjs = Object.create(null);
var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
var textState;
function ensureTextContentItem() {
@ -17515,7 +17526,8 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
return textContentItem;
}
var font = textState.font;
if (!(font.loadedName in textContent.styles)) {
if (!(font.loadedName in seenStyles)) {
seenStyles[font.loadedName] = true;
textContent.styles[font.loadedName] = {
fontFamily: font.fallbackName,
ascent: font.ascent,
@ -17670,10 +17682,19 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
textContentItem.initialized = false;
textContentItem.str.length = 0;
}
function enqueueChunk() {
let length = textContent.items.length;
if (length > 0) {
sink.enqueue(textContent, length);
textContent.items = [];
textContent.styles = Object.create(null);
}
}
var timeSlotManager = new TimeSlotManager();
return new Promise(function promiseBody(resolve, reject) {
var next = function (promise) {
promise.then(function () {
let next = function (promise) {
enqueueChunk();
Promise.all([promise, sink.ready]).then(function () {
try {
promiseBody(resolve, reject);
} catch (ex) {
@ -17828,11 +17849,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
xobjs = resources.get('XObject') || _primitives.Dict.empty;
}
var name = args[0].name;
if (xobjsCache.key === name) {
if (xobjsCache.texts) {
_util.Util.appendToArray(textContent.items, xobjsCache.texts.items);
_util.Util.extendObj(textContent.styles, xobjsCache.texts.styles);
}
if (name in skipEmptyXObjs) {
break;
}
var xobj = xobjs.get(name);
@ -17843,8 +17860,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
var type = xobj.dict.get('Subtype');
(0, _util.assert)((0, _primitives.isName)(type), 'XObject should have a Name subtype');
if (type.name !== 'Form') {
xobjsCache.key = name;
xobjsCache.texts = null;
skipEmptyXObjs[name] = true;
break;
}
var currentState = stateManager.state.clone();
@ -17853,18 +17869,33 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
if ((0, _util.isArray)(matrix) && matrix.length === 6) {
xObjStateManager.transform(matrix);
}
enqueueChunk();
let sinkWrapper = {
enqueueInvoked: false,
enqueue(chunk, size) {
this.enqueueInvoked = true;
sink.enqueue(chunk, size);
},
get desiredSize() {
return sink.desiredSize;
},
get ready() {
return sink.ready;
}
};
next(self.getTextContent({
stream: xobj,
task,
resources: xobj.dict.get('Resources') || resources,
stateManager: xObjStateManager,
normalizeWhitespace,
combineTextItems
}).then(function (formTextContent) {
_util.Util.appendToArray(textContent.items, formTextContent.items);
_util.Util.extendObj(textContent.styles, formTextContent.styles);
xobjsCache.key = name;
xobjsCache.texts = formTextContent;
combineTextItems,
sink: sinkWrapper,
seenStyles
}).then(function () {
if (!sinkWrapper.enqueueInvoked) {
skipEmptyXObjs[name] = true;
}
}));
return;
case _util.OPS.setGState:
@ -17887,18 +17918,24 @@ var PartialEvaluator = function PartialEvaluatorClosure() {
}
break;
}
if (textContent.items.length >= sink.desiredSize) {
stop = true;
break;
}
}
if (stop) {
next(deferred);
return;
}
flushTextContentItem();
resolve(textContent);
enqueueChunk();
resolve();
}).catch(reason => {
if (this.options.ignoreErrors) {
(0, _util.warn)('getTextContent - ignoring errors during task: ' + task.name);
flushTextContentItem();
return textContent;
enqueueChunk();
return;
}
throw reason;
});
@ -24126,27 +24163,31 @@ var WorkerMessageHandler = {
});
});
}, this);
handler.on('GetTextContent', function wphExtractText(data) {
handler.on('GetTextContent', function wphExtractText(data, sink) {
var pageIndex = data.pageIndex;
return pdfManager.getPage(pageIndex).then(function (page) {
sink.onPull = function (desiredSize) {};
sink.onCancel = function (reason) {};
pdfManager.getPage(pageIndex).then(function (page) {
var task = new WorkerTask('GetTextContent: page ' + pageIndex);
startWorkerTask(task);
var pageNum = pageIndex + 1;
var start = Date.now();
return page.extractTextContent({
page.extractTextContent({
handler,
task,
sink,
normalizeWhitespace: data.normalizeWhitespace,
combineTextItems: data.combineTextItems
}).then(function (textContent) {
}).then(function () {
finishWorkerTask(task);
(0, _util.info)('text indexing: page=' + pageNum + ' - time=' + (Date.now() - start) + 'ms');
return textContent;
sink.close();
}, function (reason) {
finishWorkerTask(task);
if (task.terminated) {
return;
}
sink.error(reason);
throw reason;
});
});
@ -29061,7 +29102,7 @@ var Page = function PageClosure() {
});
});
},
extractTextContent({ handler, task, normalizeWhitespace, combineTextItems }) {
extractTextContent({ handler, task, normalizeWhitespace, sink, combineTextItems }) {
var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
var resourcesPromise = this.loadResources(['ExtGState', 'XObject', 'Font']);
var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
@ -29081,7 +29122,8 @@ var Page = function PageClosure() {
task,
resources: this.resources,
normalizeWhitespace,
combineTextItems
combineTextItems,
sink
});
});
},
@ -30512,24 +30554,24 @@ var Font = function FontClosure() {
type = 'Type1';
}
} else if (isOpenTypeFile(file)) {
type = subtype = 'OpenType';
subtype = 'OpenType';
}
}
if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') {
type = 'CIDFontType0';
}
if (subtype === 'OpenType') {
type = 'OpenType';
}
if (type === 'CIDFontType0') {
if (isType1File(file)) {
subtype = 'CIDFontType0';
} else if (isOpenTypeFile(file)) {
type = subtype = 'OpenType';
subtype = 'OpenType';
} else {
subtype = 'CIDFontType0C';
}
}
if (subtype === 'OpenType' && type !== 'OpenType') {
type = 'OpenType';
}
var data;
switch (type) {
case 'MMType1':
@ -31672,7 +31714,7 @@ var Font = function FontClosure() {
}
var isTrueType = !tables['CFF '];
if (!isTrueType) {
if (header.version === 'OTTO' && !properties.composite || !tables['head'] || !tables['hhea'] || !tables['maxp'] || !tables['post']) {
if (header.version === 'OTTO' && !(properties.composite && properties.cidToGidMap) || !tables['head'] || !tables['hhea'] || !tables['maxp'] || !tables['post']) {
cffFile = new _stream.Stream(tables['CFF '].data);
cff = new CFFFont(cffFile, properties);
adjustWidths(properties);
@ -39776,8 +39818,8 @@ exports.Type1Parser = Type1Parser;
"use strict";
var pdfjsVersion = '1.8.480';
var pdfjsBuild = '2f2e539b';
var pdfjsVersion = '1.8.497';
var pdfjsBuild = 'f2fcf2a5';
var pdfjsCoreWorker = __w_pdfjs_require__(17);
;
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;

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

@ -4886,7 +4886,6 @@ var _dom_events = __webpack_require__(2);
var _pdf_rendering_queue = __webpack_require__(3);
const TEXT_LAYER_RENDER_DELAY = 200;
class PDFPageView {
constructor(options) {
let container = options.container;
@ -5190,10 +5189,9 @@ class PDFPageView {
let resultPromise = paintTask.promise.then(function () {
return finishPaintTask(null).then(function () {
if (textLayer) {
pdfPage.getTextContent({ normalizeWhitespace: true }).then(function textContentResolved(textContent) {
textLayer.setTextContent(textContent);
textLayer.render(TEXT_LAYER_RENDER_DELAY);
});
let readableStream = pdfPage.streamTextContent({ normalizeWhitespace: true });
textLayer.setTextContentStream(readableStream);
textLayer.render();
}
});
}, function (reason) {
@ -7392,6 +7390,8 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
this.textLayerDiv = options.textLayerDiv;
this.eventBus = options.eventBus || (0, _dom_events.getGlobalEventBus)();
this.textContent = null;
this.textContentItemsStr = [];
this.textContentStream = null;
this.renderingDone = false;
this.pageIdx = options.pageIndex;
this.pageNumber = this.pageIdx + 1;
@ -7418,7 +7418,7 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
});
},
render: function TextLayerBuilder_render(timeout) {
if (!this.textContent || this.renderingDone) {
if (!(this.textContent || this.textContentStream) || this.renderingDone) {
return;
}
this.cancel();
@ -7426,9 +7426,11 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
var textLayerFrag = document.createDocumentFragment();
this.textLayerRenderTask = (0, _pdfjsLib.renderTextLayer)({
textContent: this.textContent,
textContentStream: this.textContentStream,
container: textLayerFrag,
viewport: this.viewport,
textDivs: this.textDivs,
textContentItemsStr: this.textContentItemsStr,
timeout,
enhanceTextSelection: this.enhanceTextSelection
});
@ -7444,6 +7446,10 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
this.textLayerRenderTask = null;
}
},
setTextContentStream(readableStream) {
this.cancel();
this.textContentStream = readableStream;
},
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
this.cancel();
this.textContent = textContent;
@ -7451,8 +7457,8 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
convertMatches: function TextLayerBuilder_convertMatches(matches, matchesLength) {
var i = 0;
var iIndex = 0;
var bidiTexts = this.textContent.items;
var end = bidiTexts.length - 1;
let textContentItemsStr = this.textContentItemsStr;
var end = textContentItemsStr.length - 1;
var queryLen = this.findController === null ? 0 : this.findController.state.query.length;
var ret = [];
if (!matches) {
@ -7460,11 +7466,11 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
}
for (var m = 0, len = matches.length; m < len; m++) {
var matchIdx = matches[m];
while (i !== end && matchIdx >= iIndex + bidiTexts[i].str.length) {
iIndex += bidiTexts[i].str.length;
while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) {
iIndex += textContentItemsStr[i].length;
i++;
}
if (i === bidiTexts.length) {
if (i === textContentItemsStr.length) {
console.error('Could not find a matching mapping');
}
var match = {
@ -7478,8 +7484,8 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
} else {
matchIdx += queryLen;
}
while (i !== end && matchIdx > iIndex + bidiTexts[i].str.length) {
iIndex += bidiTexts[i].str.length;
while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) {
iIndex += textContentItemsStr[i].length;
i++;
}
match.end = {
@ -7494,7 +7500,7 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
if (matches.length === 0) {
return;
}
var bidiTexts = this.textContent.items;
let textContentItemsStr = this.textContentItemsStr;
var textDivs = this.textDivs;
var prevEnd = null;
var pageIdx = this.pageIdx;
@ -7512,7 +7518,7 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
}
function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
var div = textDivs[divIdx];
var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
var content = textContentItemsStr[divIdx].substring(fromOffset, toOffset);
var node = document.createTextNode(content);
if (className) {
var span = document.createElement('span');
@ -7569,14 +7575,14 @@ var TextLayerBuilder = function TextLayerBuilderClosure() {
}
var matches = this.matches;
var textDivs = this.textDivs;
var bidiTexts = this.textContent.items;
let textContentItemsStr = this.textContentItemsStr;
var clearedUntilDivIdx = -1;
for (var i = 0, len = matches.length; i < len; i++) {
var match = matches[i];
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
for (var n = begin, end = match.end.divIdx; n <= end; n++) {
var div = textDivs[n];
div.textContent = bidiTexts[n].str;
div.textContent = textContentItemsStr[n];
div.className = '';
}
clearedUntilDivIdx = match.end.divIdx + 1;
@ -7689,9 +7695,8 @@ class Toolbar {
this._updateUIState(true);
}
_bindListeners() {
let eventBus = this.eventBus;
let { eventBus, items } = this;
let self = this;
let items = this.items;
items.previous.addEventListener('click', function () {
eventBus.dispatch('previouspage');
});
@ -7748,31 +7753,9 @@ class Toolbar {
if (!this._wasLocalized) {
return;
}
let selectScaleOption = (value, scale) => {
let customScale = Math.round(scale * 10000) / 100;
this.l10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%').then(msg => {
let options = items.scaleSelect.options;
let predefinedValueFound = false;
for (let i = 0, ii = options.length; i < ii; i++) {
let option = options[i];
if (option.value !== value) {
option.selected = false;
continue;
}
option.selected = true;
predefinedValueFound = true;
}
if (!predefinedValueFound) {
items.customScaleOption.textContent = msg;
items.customScaleOption.selected = true;
}
});
};
let pageNumber = this.pageNumber;
let { pageNumber, pagesCount, items } = this;
let scaleValue = (this.pageScaleValue || this.pageScale).toString();
let scale = this.pageScale;
let items = this.items;
let pagesCount = this.pagesCount;
if (resetNumPages) {
if (this.hasPageLabels) {
items.pageNumber.type = 'text';
@ -7799,7 +7782,24 @@ class Toolbar {
items.next.disabled = pageNumber >= pagesCount;
items.zoomOut.disabled = scale <= _ui_utils.MIN_SCALE;
items.zoomIn.disabled = scale >= _ui_utils.MAX_SCALE;
selectScaleOption(scaleValue, scale);
let customScale = Math.round(scale * 10000) / 100;
this.l10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%').then(msg => {
let options = items.scaleSelect.options;
let predefinedValueFound = false;
for (let i = 0, ii = options.length; i < ii; i++) {
let option = options[i];
if (option.value !== scaleValue) {
option.selected = false;
continue;
}
option.selected = true;
predefinedValueFound = true;
}
if (!predefinedValueFound) {
items.customScaleOption.textContent = msg;
items.customScaleOption.selected = true;
}
});
}
updateLoadingIndicatorState(loading = false) {
let pageNumberInput = this.items.pageNumber;

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

@ -34,8 +34,8 @@
<!ENTITY welcomeback2.pageTitle "Success!">
<!ENTITY welcomeback2.pageInfo1 "&brandShortName; is ready to go.">
<!ENTITY welcomeback2.label.restoreAll "Restore all Windows and Tabs">
<!ENTITY welcomeback2.label.restoreSome "Restore only the ones you want">
<!ENTITY welcomeback2.restoreAll.label "Restore all windows &amp; tabs">
<!ENTITY welcomeback2.restoreSome.label "Restore only the ones you want">
<!-- LOCALIZATION NOTE (welcomeback2.beforelink.pageInfo2,

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

@ -19,12 +19,6 @@
# define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
#endif
// Code built with !_HAS_EXCEPTIONS calls std::_Throw(), but the win2k
// CRT doesn't export std::_Throw(). So we define it.
#ifndef mozilla_Throw_h
# include "mozilla/throw_msvc.h"
#endif
#ifdef _DEBUG
// From
// http://msdn.microsoft.com/en-us/library/aa985982%28VS.80%29.aspx

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

@ -895,19 +895,14 @@ StyleEditorUI.prototype = {
this._jumpToLocation.bind(this, location));
let cond = this._panelDoc.createElement("div");
cond.textContent = rule.conditionText;
cond.className = "media-rule-condition";
if (!rule.matches) {
cond.classList.add("media-condition-unmatched");
}
if (this._target.tab.tagName == "tab") {
const minMaxPattern = /(min\-|max\-)(width|height):\s\d+(px)/ig;
const replacement =
"<a href='#' class='media-responsive-mode-toggle'>$&</a>";
cond.innerHTML = cond.textContent.replace(minMaxPattern, replacement);
cond.addEventListener("click",
this._onMediaConditionClick.bind(this));
this._setConditionContents(cond, rule.conditionText);
} else {
cond.textContent = rule.conditionText;
}
div.appendChild(cond);
@ -927,6 +922,43 @@ StyleEditorUI.prototype = {
}.bind(this)).catch(e => console.error(e));
},
/**
* Used to safely inject media query links
*
* @param {HTMLElement} element
* The element corresponding to the media sidebar condition
* @param {String} rawText
* The raw condition text to parse
*/
_setConditionContents(element, rawText) {
const minMaxPattern = /(min\-|max\-)(width|height):\s\d+(px)/ig;
let match = minMaxPattern.exec(rawText);
let lastParsed = 0;
while (match && match.index != minMaxPattern.lastIndex) {
let matchEnd = match.index + match[0].length;
let node = this._panelDoc.createTextNode(
rawText.substring(lastParsed, match.index)
);
element.appendChild(node);
let link = this._panelDoc.createElement("a");
link.href = "#";
link.className = "media-responsive-mode-toggle";
link.textContent = rawText.substring(match.index, matchEnd);
link.addEventListener("click", this._onMediaConditionClick.bind(this));
element.appendChild(link);
match = minMaxPattern.exec(rawText);
lastParsed = matchEnd;
}
let node = this._panelDoc.createTextNode(
rawText.substring(lastParsed, rawText.length)
);
element.appendChild(node);
},
/**
* Called when a media condition is clicked
* If a responsive mode link is clicked, it will launch it.
@ -935,9 +967,6 @@ StyleEditorUI.prototype = {
* Event object
*/
_onMediaConditionClick: function (e) {
if (!e.target.matches(".media-responsive-mode-toggle")) {
return;
}
let conditionText = e.target.textContent;
let isWidthCond = conditionText.toLowerCase().indexOf("width") > -1;
let mediaVal = parseInt(/\d+/.exec(conditionText), 10);

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

@ -209,6 +209,7 @@
#include "nsINode.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/Element.h"
#include "nsIDOMHTMLDocument.h"
@ -432,6 +433,7 @@ class nsTextNodeDirectionalityMap
public:
explicit nsTextNodeDirectionalityMap(nsINode* aTextNode)
: mElementToBeRemoved(nullptr)
{
MOZ_ASSERT(aTextNode, "Null text node");
MOZ_COUNT_CTOR(nsTextNodeDirectionalityMap);
@ -445,11 +447,28 @@ public:
MOZ_COUNT_DTOR(nsTextNodeDirectionalityMap);
}
static void
nsTextNodeDirectionalityMapPropertyDestructor(void* aObject,
nsIAtom* aProperty,
void* aPropertyValue,
void* aData)
{
nsTextNode* textNode =
static_cast<nsTextNode*>(aPropertyValue);
nsTextNodeDirectionalityMap* map = GetDirectionalityMap(textNode);
if (map) {
map->RemoveEntryForProperty(static_cast<Element*>(aObject));
}
NS_RELEASE(textNode);
}
void AddEntry(nsTextNode* aTextNode, Element* aElement)
{
if (!mElements.Contains(aElement)) {
mElements.Put(aElement);
aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode);
NS_ADDREF(aTextNode);
aElement->SetProperty(nsGkAtoms::dirAutoSetBy, aTextNode,
nsTextNodeDirectionalityMapPropertyDestructor);
aElement->SetHasDirAutoSet();
}
}
@ -461,11 +480,21 @@ public:
mElements.Remove(aElement);
aElement->ClearHasDirAutoSet();
aElement->UnsetProperty(nsGkAtoms::dirAutoSetBy);
aElement->DeleteProperty(nsGkAtoms::dirAutoSetBy);
}
void RemoveEntryForProperty(Element* aElement)
{
if (mElementToBeRemoved != aElement) {
mElements.Remove(aElement);
}
aElement->ClearHasDirAutoSet();
}
private:
nsCheapSet<nsPtrHashKey<Element>> mElements;
// Only used for comparison.
Element* mElementToBeRemoved;
static nsTextNodeDirectionalityMap* GetDirectionalityMap(nsINode* aTextNode)
{
@ -489,18 +518,29 @@ private:
return OpNext;
}
struct nsTextNodeDirectionalityMapAndElement
{
nsTextNodeDirectionalityMap* mMap;
nsCOMPtr<nsINode> mNode;
};
static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey<Element>* aEntry, void* aData)
{
MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element");
// run the downward propagation algorithm
// and remove the text node from the map
nsINode* oldTextNode = static_cast<Element*>(aData);
nsTextNodeDirectionalityMapAndElement* data =
static_cast<nsTextNodeDirectionalityMapAndElement*>(aData);
nsINode* oldTextNode = data->mNode;
Element* rootNode = aEntry->GetKey();
nsTextNode* newTextNode = nullptr;
if (rootNode->GetParentNode() && rootNode->HasDirAuto()) {
newTextNode = WalkDescendantsSetDirectionFromText(rootNode, true,
oldTextNode);
}
AutoRestore<Element*> restore(data->mMap->mElementToBeRemoved);
data->mMap->mElementToBeRemoved = rootNode;
if (newTextNode) {
nsINode* oldDirAutoSetBy =
static_cast<nsTextNode*>(rootNode->GetProperty(nsGkAtoms::dirAutoSetBy));
@ -511,7 +551,7 @@ private:
nsTextNodeDirectionalityMap::AddEntryToMap(newTextNode, rootNode);
} else {
rootNode->ClearHasDirAutoSet();
rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy);
rootNode->DeleteProperty(nsGkAtoms::dirAutoSetBy);
}
return OpRemove;
}
@ -520,7 +560,7 @@ private:
{
Element* rootNode = aEntry->GetKey();
rootNode->ClearHasDirAutoSet();
rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy);
rootNode->DeleteProperty(nsGkAtoms::dirAutoSetBy);
return OpRemove;
}
@ -532,11 +572,13 @@ public:
void ResetAutoDirection(nsINode* aTextNode)
{
mElements.EnumerateEntries(ResetNodeDirection, aTextNode);
nsTextNodeDirectionalityMapAndElement data = { this, aTextNode };
mElements.EnumerateEntries(ResetNodeDirection, &data);
}
void EnsureMapIsClear(nsINode* aTextNode)
{
AutoRestore<Element*> restore(mElementToBeRemoved);
DebugOnly<uint32_t> clearedEntries =
mElements.EnumerateEntries(ClearEntry, aTextNode);
MOZ_ASSERT(clearedEntries == 0, "Map should be empty already");
@ -572,7 +614,8 @@ public:
{
MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(),
"Map missing in ResetTextNodeDirection");
GetDirectionalityMap(aTextNode)->ResetAutoDirection(aChangedTextNode);
RefPtr<nsTextNode> textNode = aTextNode;
GetDirectionalityMap(textNode)->ResetAutoDirection(aChangedTextNode);
}
static void EnsureMapIsClearFor(nsINode* aTextNode)

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

@ -3324,6 +3324,7 @@ static nsIAtom** sPropertiesToTraverseAndUnlink[] =
{
&nsGkAtoms::sandbox,
&nsGkAtoms::sizes,
&nsGkAtoms::dirAutoSetBy,
nullptr
};

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

@ -326,6 +326,7 @@ nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
bool nsContentUtils::sFragmentParsingActive = false;
nsISerialEventTarget* nsContentUtils::sStableStateEventTarget = nullptr;
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
bool nsContentUtils::sDOMWindowDumpEnabled;
@ -519,6 +520,52 @@ class SameOriginCheckerImpl final : public nsIChannelEventSink,
NS_DECL_NSIINTERFACEREQUESTOR
};
class StableStateEventTarget final : public nsISerialEventTarget
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET_FULL
private:
~StableStateEventTarget() {}
};
NS_IMPL_ISUPPORTS(StableStateEventTarget, nsISerialEventTarget);
bool
StableStateEventTarget::IsOnCurrentThreadInfallible()
{
return true;
}
NS_IMETHODIMP
StableStateEventTarget::IsOnCurrentThread(bool* aResult)
{
*aResult = true;
return NS_OK;
}
NS_IMETHODIMP
StableStateEventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
{
if (NS_WARN_IF(!CycleCollectedJSContext::Get())) {
return NS_ERROR_UNEXPECTED;
}
nsContentUtils::RunInStableState(Move(aEvent));
return NS_OK;
}
NS_IMETHODIMP
StableStateEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
NS_IMETHODIMP
StableStateEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aDelay)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace
/**
@ -730,6 +777,9 @@ nsContentUtils::Init()
Unused << nsRFPService::GetOrCreate();
RefPtr<StableStateEventTarget> stableStateEventTarget = new StableStateEventTarget();
stableStateEventTarget.forget(&sStableStateEventTarget);
nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -2156,6 +2206,8 @@ nsContentUtils::Shutdown()
NS_IF_RELEASE(sSameOriginChecker);
NS_IF_RELEASE(sStableStateEventTarget);
if (sUserInteractionObserver) {
sUserInteractionObserver->Shutdown();
NS_RELEASE(sUserInteractionObserver);
@ -5661,6 +5713,13 @@ nsContentUtils::RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable)
CycleCollectedJSContext::Get()->RunInMetastableState(Move(aRunnable));
}
/* static */
nsISerialEventTarget*
nsContentUtils::GetStableStateEventTarget()
{
return sStableStateEventTarget;
}
void
nsContentUtils::EnterMicroTask()
{

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

@ -1879,6 +1879,16 @@ public:
*/
static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable);
/**
* Returns a nsISerialEventTarget which will run any event dispatched to it
* once the event loop has reached a "stable state". Runnables dispatched to
* this event target must not cause any queued events to be processed (i.e.
* must not spin the event loop).
*
* See RunInStableState for more information about stable states
*/
static nsISerialEventTarget* GetStableStateEventTarget();
// Call EnterMicroTask when you're entering JS execution.
// Usually the best way to do this is to use nsAutoMicroTask.
static void EnterMicroTask();
@ -3227,6 +3237,8 @@ private:
*/
static bool sFragmentParsingActive;
static nsISerialEventTarget* sStableStateEventTarget;
static nsString* sShiftText;
static nsString* sControlText;
static nsString* sMetaText;

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

@ -36,11 +36,13 @@
#include "mozilla/BasicEvents.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsIClipboardDragDropHooks.h"
#include "nsIClipboardDragDropHookList.h"
using namespace mozilla;
using namespace mozilla::layers;
constexpr const char * sSelectAllString = "cmd_selectAll";
constexpr const char * sSelectNoneString = "cmd_selectNone";
@ -271,33 +273,44 @@ IsCaretOnInWindow(nsPIDOMWindowOuter* aWindow, nsISelectionController* aSelCont)
static constexpr struct BrowseCommand {
const char *reverse, *forward;
KeyboardScrollAction::KeyboardScrollActionType scrollAction;
nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
nsresult (NS_STDCALL nsISelectionController::*move)(bool, bool);
} browseCommands[] = {
{ sScrollTopString, sScrollBottomString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll },
{ sScrollPageUpString, sScrollPageDownString,
KeyboardScrollAction::eScrollPage,
&nsISelectionController::ScrollPage },
{ sScrollLineUpString, sScrollLineDownString,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine },
{ sScrollLeftString, sScrollRightString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter },
{ sMoveTopString, sMoveBottomString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll,
&nsISelectionController::CompleteMove },
{ sMovePageUpString, sMovePageDownString,
KeyboardScrollAction::eScrollPage,
&nsISelectionController::ScrollPage,
&nsISelectionController::PageMove },
{ sLinePreviousString, sLineNextString,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine,
&nsISelectionController::LineMove },
{ sWordPreviousString, sWordNextString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter,
&nsISelectionController::WordMove },
{ sCharPreviousString, sCharNextString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter,
&nsISelectionController::CharacterMove },
{ sBeginLineString, sEndLineString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll,
&nsISelectionController::IntraLineMove }
};
@ -334,23 +347,32 @@ nsSelectMoveScrollCommand::DoCommand(const char *aCommandName, nsISupports *aCom
static const struct PhysicalBrowseCommand {
const char *command;
int16_t direction, amount;
KeyboardScrollAction::KeyboardScrollActionType scrollAction;
nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
} physicalBrowseCommands[] = {
{ sMoveLeftString, nsISelectionController::MOVE_LEFT, 0,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter },
{ sMoveRightString, nsISelectionController::MOVE_RIGHT, 0,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter },
{ sMoveUpString, nsISelectionController::MOVE_UP, 0,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine },
{ sMoveDownString, nsISelectionController::MOVE_DOWN, 0,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine },
{ sMoveLeft2String, nsISelectionController::MOVE_LEFT, 1,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter },
{ sMoveRight2String, nsISelectionController::MOVE_RIGHT, 1,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter },
{ sMoveUp2String, nsISelectionController::MOVE_UP, 1,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll },
{ sMoveDown2String, nsISelectionController::MOVE_DOWN, 1,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll },
};
@ -1262,3 +1284,36 @@ nsWindowCommandRegistration::RegisterWindowCommands(
return rv;
}
/* static */ bool
nsGlobalWindowCommands::FindScrollCommand(const char* aCommandName,
KeyboardScrollAction* aOutAction)
{
// Search for a keyboard scroll action to do for this command in browseCommands
// and physicalBrowseCommands. Each command exists in only one of them, so the
// order we examine browseCommands and physicalBrowseCommands doesn't matter.
for (size_t i = 0; i < ArrayLength(browseCommands); i++) {
const BrowseCommand& cmd = browseCommands[i];
bool forward = !strcmp(aCommandName, cmd.forward);
bool reverse = !strcmp(aCommandName, cmd.reverse);
if (forward || reverse) {
*aOutAction = KeyboardScrollAction(cmd.scrollAction, forward);
return true;
}
}
for (size_t i = 0; i < ArrayLength(physicalBrowseCommands); i++) {
const PhysicalBrowseCommand& cmd = physicalBrowseCommands[i];
if (!strcmp(aCommandName, cmd.command)) {
int16_t dir = cmd.direction;
bool forward = (dir == nsISelectionController::MOVE_RIGHT ||
dir == nsISelectionController::MOVE_DOWN);
*aOutAction = KeyboardScrollAction(cmd.scrollAction, forward);
return true;
}
}
return false;
}

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

@ -9,6 +9,12 @@
#include "nscore.h"
namespace mozilla {
namespace layers {
struct KeyboardScrollAction;
} // namespace layers
} // namespace mozilla
class nsIControllerCommandTable;
class nsWindowCommandRegistration
@ -17,6 +23,22 @@ public:
static nsresult RegisterWindowCommands(nsIControllerCommandTable *ccm);
};
class nsGlobalWindowCommands
{
public:
typedef mozilla::layers::KeyboardScrollAction KeyboardScrollAction;
/**
* Search through nsGlobalWindowCommands to find the keyboard scrolling action
* that would be done in response to a command.
*
* @param aCommandName the name of the command
* @param aOutAction the result of searching for this command, must not be null
* @returns whether a keyboard action was found or not
*/
static bool FindScrollCommand(const char* aCommandName,
KeyboardScrollAction* aOutAction);
};
// XXX find a better home for these
#define NS_WINDOWCONTROLLER_CID \

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

@ -41,7 +41,7 @@ class nsWindowRoot;
// This may waste space for some other nsWrapperCache-derived objects that have
// a 32-bit field as their first member, but those objects are unlikely to be as
// numerous or performance-critical as DOM nodes.
#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__)
#if defined(_M_X64) || defined(__LP64__)
static_assert(sizeof(void*) == 8, "These architectures should be 64-bit");
#define BOOL_FLAGS_ON_WRAPPER_CACHE
#else

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

@ -97,10 +97,12 @@ FormatForPackingInfo(const PackingInfo& pi)
case LOCAL_GL_RGB:
case LOCAL_GL_RGB_INTEGER:
case LOCAL_GL_SRGB:
return WebGLTexelFormat::RGB8;
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA_INTEGER:
case LOCAL_GL_SRGB_ALPHA:
return WebGLTexelFormat::RGBA8;
case LOCAL_GL_RG:
@ -434,11 +436,11 @@ bool
TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum* const out_error) const
GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
GLenum* const out_error) const
{
WebGLContext* webgl = tex->mContext;
const auto pi = dui->ToPacking();
const auto format = FormatForPackingInfo(pi);
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
@ -613,7 +615,8 @@ bool
TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum* const out_error) const
GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
GLenum* const out_error) const
{
MOZ_ASSERT_IF(needsRespec, !isSubImage);
@ -739,7 +742,7 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
mSrcAlphaType);
return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
dui, xOffset, yOffset, zOffset, out_error);
dui, xOffset, yOffset, zOffset, pi, out_error);
}
////////////////////////////////////////////////////////////////////////////////
@ -821,8 +824,8 @@ TexUnpackSurface::Validate(WebGLContext* webgl, const char* funcName,
bool
TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dstDUI, GLint xOffset,
GLint yOffset, GLint zOffset,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset, const webgl::PackingInfo& dstPI,
GLenum* const out_error) const
{
const auto& webgl = tex->mContext;
@ -832,7 +835,6 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
const auto rowLength = mSurf->GetSize().width;
const auto rowCount = mSurf->GetSize().height;
const auto& dstPI = dstDUI->ToPacking();
const auto& dstBPP = webgl::BytesPerPixel(dstPI);
const auto dstFormat = FormatForPackingInfo(dstPI);
@ -892,7 +894,7 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
}
*out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dstDUI, xOffset,
*out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
yOffset, zOffset, mWidth, mHeight, mDepth, dstBegin);
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, webgl->mPixelStore_UnpackAlignment);

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

@ -86,7 +86,7 @@ public:
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
GLenum* const out_error) const = 0;
const webgl::PackingInfo& pi, GLenum* const out_error) const = 0;
};
class TexUnpackBytes final : public TexUnpackBlob
@ -108,7 +108,7 @@ public:
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
GLenum* const out_error) const override;
const webgl::PackingInfo& pi, GLenum* const out_error) const override;
};
class TexUnpackImage final : public TexUnpackBlob
@ -128,7 +128,7 @@ public:
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
GLenum* const out_error) const override;
const webgl::PackingInfo& dstPI, GLenum* const out_error) const override;
};
class TexUnpackSurface final : public TexUnpackBlob
@ -146,7 +146,7 @@ public:
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
GLenum* const out_error) const override;
const webgl::PackingInfo& dstPI, GLenum* const out_error) const override;
};
} // namespace webgl

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

@ -1292,7 +1292,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
GLenum glError;
if (!blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level,
driverUnpackInfo, xOffset, yOffset, zOffset, &glError))
driverUnpackInfo, xOffset, yOffset, zOffset, pi, &glError))
{
return;
}
@ -1380,7 +1380,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
GLenum glError;
if (!blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level,
driverUnpackInfo, xOffset, yOffset, zOffset, &glError))
driverUnpackInfo, xOffset, yOffset, zOffset, pi, &glError))
{
return;
}

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

@ -7378,7 +7378,6 @@ skip-if = (os == 'android' || os == 'linux')
[generated/test_2_conformance__textures__misc__tex-image-webgl.html]
skip-if = (os == 'android' || os == 'linux')
[generated/test_2_conformance__textures__misc__tex-image-with-format-and-type.html]
fail-if = (os == 'mac')
skip-if = (os == 'android' || os == 'linux')
[generated/test_2_conformance__textures__misc__tex-image-with-invalid-data.html]
skip-if = (os == 'android' || os == 'linux')

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

@ -130,8 +130,6 @@ skip-if = (os == 'mac' && os_version == '10.6')
# application crashed [@ mozilla::gl::GLContext::AfterGLCall]
skip-if = (os == 'android') || (os == 'win')
[generated/test_2_conformance__textures__misc__tex-image-with-format-and-type.html]
fail-if = (os == 'mac')
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_conformance__extensions__oes-texture-half-float.html]

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

@ -1767,6 +1767,23 @@ EventListenerManager::TraceListeners(JSTracer* aTrc)
}
}
bool
EventListenerManager::HasUntrustedOrNonSystemGroupKeyEventListeners()
{
uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; ++i) {
Listener* listener = &mListeners.ElementAt(i);
if (!listener->mFlags.mInSystemGroup &&
listener->mFlags.mAllowUntrustedEvents &&
(listener->mTypeAtom == nsGkAtoms::onkeydown ||
listener->mTypeAtom == nsGkAtoms::onkeypress ||
listener->mTypeAtom == nsGkAtoms::onkeyup)) {
return true;
}
}
return false;
}
bool
EventListenerManager::HasApzAwareListeners()
{

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

@ -470,6 +470,8 @@ public:
dom::EventTarget* GetTarget() { return mTarget; }
bool HasUntrustedOrNonSystemGroupKeyEventListeners();
bool HasApzAwareListeners();
bool IsApzAwareListener(Listener* aListener);
bool IsApzAwareEvent(nsIAtom* aEvent);

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

@ -5287,7 +5287,7 @@ EventStateManager::DoContentCommandScrollEvent(
aEvent->mSucceeded = true;
nsIScrollableFrame* sf =
ps->GetFrameToScrollAsScrollable(nsIPresShell::eEither);
ps->GetScrollableFrameToScroll(nsIPresShell::eEither);
aEvent->mIsEnabled = sf ?
(aEvent->mScroll.mIsHorizontal ?
WheelHandlingUtils::CanScrollOn(sf, aEvent->mScroll.mAmount, 0) :

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

@ -57,6 +57,13 @@ EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
GetOrCreateListenerManager()->SetEventHandler(aType, aTypeString, aHandler);
}
bool
EventTarget::HasUntrustedOrNonSystemGroupKeyEventListeners() const
{
EventListenerManager* elm = GetExistingListenerManager();
return elm && elm->HasUntrustedOrNonSystemGroupKeyEventListeners();
}
bool
EventTarget::IsApzAware() const
{

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

@ -99,6 +99,10 @@ public:
// Called from AsyncEventDispatcher to notify it is running.
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {}
// Used by FocusTarget to determine whether this event target has listeners
// for untrusted or non system group key events.
bool HasUntrustedOrNonSystemGroupKeyEventListeners() const;
virtual bool IsApzAware() const;
protected:

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

@ -859,6 +859,17 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
uint32_t maxTouchPoints = 0;
DimensionInfo dimensionInfo;
nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
if (aParent) {
nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow =
nsPIDOMWindowOuter::From(aParent)->GetTop();
if (parentTopWindow) {
parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
}
}
// Send down the request to open the window.
RefPtr<CreateWindowPromise> windowCreated;
if (aIframeMoz) {
MOZ_ASSERT(aTabOpener);
nsAutoCString url;
@ -871,10 +882,11 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
url.SetIsVoid(true);
}
// NOTE: BrowserFrameOpenWindowPromise is the same type as
// CreateWindowPromise, and this code depends on that fact.
windowCreated =
newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame, NS_ConvertUTF8toUTF16(url),
name, NS_ConvertUTF8toUTF16(features),
aWindowIsNew, &textureFactoryIdentifier,
&layersId, &compositorOptions, &maxTouchPoints);
name, NS_ConvertUTF8toUTF16(features));
} else {
nsAutoCString baseURIString;
float fullZoom;
@ -883,30 +895,98 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
return rv;
}
if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
windowCreated =
SendCreateWindow(aTabOpener, newChild, renderFrame,
aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified,
features,
baseURIString,
fullZoom,
&rv,
aWindowIsNew,
&frameScripts,
&urlToLoad,
&textureFactoryIdentifier,
&layersId,
&compositorOptions,
&maxTouchPoints,
&dimensionInfo)) {
PRenderFrameChild::Send__delete__(renderFrame);
return NS_ERROR_NOT_AVAILABLE;
fullZoom);
}
// Await the promise being resolved. When the promise is resolved, we'll set
// the `ready` local variable, which will cause us to exit our nested event
// loop.
//
// NOTE: We need to run this callback on the StableStateEventTarget because we
// need to resolve our runnable and exit from the nested event loop before
// processing any events which were sent after the reply to CreateWindow was
// sent.
bool ready = false;
windowCreated->Then(nsContentUtils::GetStableStateEventTarget(), __func__,
[&] (const CreatedWindowInfo& info) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"windowCreated->Then must run on the main thread");
rv = info.rv();
*aWindowIsNew = info.windowOpened();
frameScripts = info.frameScripts();
urlToLoad = info.urlToLoad();
textureFactoryIdentifier = info.textureFactoryIdentifier();
layersId = info.layersId();
compositorOptions = info.compositorOptions();
maxTouchPoints = info.maxTouchPoints();
dimensionInfo = info.dimensions();
ready = true;
},
[&] (const CreateWindowPromise::RejectValueType aReason) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"windowCreated->Then must run on the main thread");
NS_WARNING("windowCreated promise rejected");
rv = NS_ERROR_NOT_AVAILABLE;
ready = true;
});
// =======================
// Begin Nested Event Loop
// =======================
// We have to wait for a response from either SendCreateWindow or
// SendBrowserFrameOpenWindow with information we're going to need to return
// from this function, So we spin a nested event loop until they get back to
// us.
// Prevent the docshell from becoming active while the nested event loop is
// spinning.
newChild->AddPendingDocShellBlocker();
auto removePendingDocShellBlocker = MakeScopeExit([&] {
if (newChild) {
newChild->RemovePendingDocShellBlocker();
}
});
// Suspend our window if we have one to make sure we don't re-enter it.
if (parentTopInnerWindow) {
parentTopInnerWindow->Suspend();
}
{
AutoNoJSAPI nojsapi;
// Spin the event loop until we get a response. Callers of this function
// already have to guard against an inner event loop spinning in the
// non-e10s case because of the need to spin one to create a new chrome
// window.
SpinEventLoopUntil([&] () { return ready; });
MOZ_RELEASE_ASSERT(ready,
"We are on the main thread, so we should not exit this "
"loop without ready being true.");
}
if (parentTopInnerWindow) {
parentTopInnerWindow->Resume();
}
// =====================
// End Nested Event Loop
// =====================
// Handle the error which we got back from the parent process, if we got
// one.
if (NS_FAILED(rv)) {
PRenderFrameChild::Send__delete__(renderFrame);
return rv;
}
}
if (!*aWindowIsNew) {
PRenderFrameChild::Send__delete__(renderFrame);
return NS_ERROR_ABORT;

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

@ -1539,19 +1539,18 @@ ContentParent::RemoveFromList()
}
}
} else if (sBrowserContentParents) {
nsTArray<ContentParent*>* contentParents =
sBrowserContentParents->Get(mRemoteType);
if (contentParents) {
if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
nsTArray<ContentParent*>* contentParents = entry.Data();
contentParents->RemoveElement(this);
if (contentParents->IsEmpty()) {
sBrowserContentParents->Remove(mRemoteType);
entry.Remove();
}
}
if (sBrowserContentParents->IsEmpty()) {
delete sBrowserContentParents;
sBrowserContentParents = nullptr;
}
}
}
}
if (sPrivateContent) {
sPrivateContent->RemoveElement(this);
@ -4665,25 +4664,30 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
const nsCString& aFeatures,
const nsCString& aBaseURI,
const float& aFullZoom,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId,
CompositorOptions* aCompositorOptions,
uint32_t* aMaxTouchPoints,
DimensionInfo* aDimensions)
CreateWindowResolver&& aResolve)
{
nsresult rv = NS_OK;
CreatedWindowInfo cwi;
// We always expect to open a new window here. If we don't, it's an error.
*aWindowIsNew = true;
*aResult = NS_OK;
cwi.windowOpened() = true;
cwi.layersId() = 0;
cwi.maxTouchPoints() = 0;
// Make sure to resolve the resolver when this function exits, even if we
// failed to generate a valid response.
auto resolveOnExit = MakeScopeExit([&] {
// Copy over the nsresult, and then resolve.
cwi.rv() = rv;
aResolve(cwi);
});
TabParent* newTab = TabParent::GetFrom(aNewTab);
MOZ_ASSERT(newTab);
auto destroyNewTabOnError = MakeScopeExit([&] {
if (!*aWindowIsNew || NS_FAILED(*aResult)) {
// We always expect to open a new window here. If we don't, it's an error.
if (!cwi.windowOpened() || NS_FAILED(rv)) {
if (newTab) {
newTab->Destroy();
}
@ -4694,7 +4698,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
// we must have an opener.
newTab->SetHasContentOpener(true);
TabParent::AutoUseNewTab aunt(newTab, aURLToLoad);
TabParent::AutoUseNewTab aunt(newTab, &cwi.urlToLoad());
const uint64_t nextTabParentId = ++sNextTabParentId;
sNextTabParents.Put(nextTabParentId, newTab);
@ -4703,35 +4707,35 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
CommonCreateWindow(aThisTab, /* aSetOpener = */ true, aChromeFlags,
aCalledFromJS, aPositionSpecified, aSizeSpecified,
nullptr, aFeatures, aBaseURI, aFullZoom,
nextTabParentId, NullString(), *aResult,
newRemoteTab, aWindowIsNew);
nextTabParentId, NullString(), rv,
newRemoteTab, &cwi.windowOpened());
if (!ipcResult) {
return ipcResult;
}
if (NS_WARN_IF(NS_FAILED(*aResult))) {
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_OK();
}
if (sNextTabParents.GetAndRemove(nextTabParentId).valueOr(nullptr)) {
*aWindowIsNew = false;
cwi.windowOpened() = false;
}
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
newTab->SwapFrameScriptsFrom(*aFrameScripts);
newTab->SwapFrameScriptsFrom(cwi.frameScripts());
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
if (!newTab->SetRenderFrame(rfp) ||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
*aResult = NS_ERROR_FAILURE;
!newTab->GetRenderFrameInfo(&cwi.textureFactoryIdentifier(), &cwi.layersId())) {
rv = NS_ERROR_FAILURE;
}
*aCompositorOptions = rfp->GetCompositorOptions();
cwi.compositorOptions() = rfp->GetCompositorOptions();
nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
*aMaxTouchPoints = widget ? widget->GetMaxTouchPoints() : 0;
// NOTE: widget must be set for this to return a meaningful value.
*aDimensions = widget ? newTab->GetDimensionInfo() : DimensionInfo();
if (widget) {
cwi.maxTouchPoints() = widget->GetMaxTouchPoints();
cwi.dimensions() = newTab->GetDimensionInfo();
}
return IPC_OK();
}
@ -5090,11 +5094,7 @@ ContentParent::RecvGetFilesRequest(const nsID& aUUID,
mozilla::ipc::IPCResult
ContentParent::RecvDeleteGetFilesRequest(const nsID& aUUID)
{
GetFilesHelper* helper = mGetFilesPendingRequests.GetWeak(aUUID);
if (helper) {
mGetFilesPendingRequests.Remove(aUUID);
}
return IPC_OK();
}
@ -5102,9 +5102,8 @@ void
ContentParent::SendGetFilesResponseAndForget(const nsID& aUUID,
const GetFilesResponseResult& aResult)
{
GetFilesHelper* helper = mGetFilesPendingRequests.GetWeak(aUUID);
if (helper) {
mGetFilesPendingRequests.Remove(aUUID);
if (auto entry = mGetFilesPendingRequests.Lookup(aUUID)) {
entry.Remove();
Unused << SendGetFilesResponse(aUUID, aResult);
}
}

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

@ -536,15 +536,7 @@ public:
const nsCString& aFeatures,
const nsCString& aBaseURI,
const float& aFullZoom,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad,
layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId,
mozilla::layers::CompositorOptions* aCompositorOptions,
uint32_t* aMaxTouchPoints,
DimensionInfo* aDimensions) override;
CreateWindowResolver&& aResolve) override;
virtual mozilla::ipc::IPCResult RecvCreateWindowInDifferentProcess(
PBrowserParent* aThisTab,

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

@ -22,6 +22,8 @@ using CSSRect from "Units.h";
using CSSSize from "Units.h";
using mozilla::LayoutDeviceIntPoint from "Units.h";
using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
namespace mozilla {
namespace dom {
@ -96,5 +98,27 @@ struct DimensionInfo
LayoutDeviceIntPoint chromeDisp;
};
struct FrameScriptInfo
{
nsString url;
bool runInGlobalScope;
};
/**
* The information required to complete a window creation request.
*/
struct CreatedWindowInfo
{
nsresult rv;
bool windowOpened;
FrameScriptInfo[] frameScripts;
nsCString urlToLoad;
TextureFactoryIdentifier textureFactoryIdentifier;
uint64_t layersId;
CompositorOptions compositorOptions;
uint32_t maxTouchPoints;
DimensionInfo dimensions;
};
} // namespace dom
} // namespace mozilla

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

@ -149,11 +149,6 @@ parent:
async PPaymentRequest();
/**
* Return native data of root widget
*/
nested(inside_cpow) sync GetWidgetNativeData() returns (WindowsHandle value);
/**
* Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
* widget's shareable window on the chrome side. Only used on Windows.
@ -459,13 +454,9 @@ parent:
*
* @param opener the PBrowser whose content called window.open.
*/
sync BrowserFrameOpenWindow(PBrowser opener, PRenderFrame renderFrame,
async BrowserFrameOpenWindow(PBrowser opener, PRenderFrame renderFrame,
nsString aURL, nsString aName, nsString aFeatures)
returns (bool windowOpened,
TextureFactoryIdentifier textureFactoryIdentifier,
uint64_t layersId,
CompositorOptions compositorOptions,
uint32_t maxTouchPoints);
returns (CreatedWindowInfo window);
/**
* Tells the containing widget whether the given input block results in a
@ -898,6 +889,12 @@ child:
*/
async SetOriginAttributes(OriginAttributes aOriginAttributes);
/**
* Pass the current handle for the current native widget to the content
* process, so it can be used by PuppetWidget.
*/
async SetWidgetNativeData(WindowsHandle aHandle);
/*
* FIXME: write protocol!

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

@ -177,14 +177,6 @@ struct DomainPolicyClone
URIParams[] superWhitelist;
};
struct FrameScriptInfo
{
nsString url;
bool runInGlobalScope;
};
struct AndroidSystemInfo
{
nsString device;
@ -990,7 +982,7 @@ parent:
sync GetGraphicsDeviceInitData()
returns (ContentDeviceData aData);
sync CreateWindow(nullable PBrowser aThisTab,
async CreateWindow(nullable PBrowser aThisTab,
PBrowser aNewTab,
PRenderFrame aRenderFrame,
uint32_t aChromeFlags,
@ -1000,15 +992,7 @@ parent:
nsCString aFeatures,
nsCString aBaseURI,
float aFullZoom)
returns (nsresult rv,
bool windowOpened,
FrameScriptInfo[] frameScripts,
nsCString urlToLoad,
TextureFactoryIdentifier textureFactoryIdentifier,
uint64_t layersId,
CompositorOptions compositorOptions,
uint32_t maxTouchPoints,
DimensionInfo dimensions);
returns (CreatedWindowInfo window);
async CreateWindowInDifferentProcess(
PBrowser aThisTab,

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

@ -407,6 +407,11 @@ TabChild::TabChild(nsIContentChild* aManager,
#if defined(ACCESSIBILITY)
, mTopLevelDocAccessibleChild(nullptr)
#endif
, mPendingDocShellIsActive(false)
, mPendingDocShellPreserveLayers(false)
, mPendingDocShellReceivedMessage(false)
, mPendingDocShellBlockers(0)
, mWidgetNativeData(0)
{
nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this))); // for capture by the lambda
mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
@ -2362,20 +2367,26 @@ TabChild::RecvDestroy()
return IPC_OK();
}
mozilla::ipc::IPCResult
TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
const bool& aPreserveLayers,
const uint64_t& aLayerObserverEpoch)
void
TabChild::AddPendingDocShellBlocker()
{
// Since SetDocShellIsActive requests come in from both the hang monitor
// channel and the PContent channel, we have an ordering problem. This code
// ensures that we respect the order in which the requests were made and
// ignore stale requests.
if (mLayerObserverEpoch >= aLayerObserverEpoch) {
return IPC_OK();
mPendingDocShellBlockers++;
}
mLayerObserverEpoch = aLayerObserverEpoch;
void
TabChild::RemovePendingDocShellBlocker()
{
mPendingDocShellBlockers--;
if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
mPendingDocShellReceivedMessage = false;
InternalSetDocShellIsActive(mPendingDocShellIsActive,
mPendingDocShellPreserveLayers);
}
}
void
TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
{
auto clearForcePaint = MakeScopeExit([&] {
// We might force a paint, or we might already have painted and this is a
// no-op. In either case, once we exit this scope, we need to alert the
@ -2401,7 +2412,7 @@ TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
// We send the current layer observer epoch to the compositor so that
// TabParent knows whether a layer update notification corresponds to the
// latest SetDocShellIsActive request that was made.
mPuppetWidget->GetLayerManager()->SetLayerObserverEpoch(aLayerObserverEpoch);
mPuppetWidget->GetLayerManager()->SetLayerObserverEpoch(mLayerObserverEpoch);
}
// docshell is consider prerendered only if not active yet
@ -2415,8 +2426,8 @@ TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
// notification to fire in the parent (so that it knows that the child has
// updated its epoch). ForcePaintNoOp does that.
if (IPCOpen()) {
Unused << SendForcePaintNoOp(aLayerObserverEpoch);
return IPC_OK();
Unused << SendForcePaintNoOp(mLayerObserverEpoch);
return;
}
}
@ -2457,7 +2468,33 @@ TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
} else if (!aPreserveLayers) {
MakeHidden();
}
}
mozilla::ipc::IPCResult
TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
const bool& aPreserveLayers,
const uint64_t& aLayerObserverEpoch)
{
// Since requests to change the active docshell come in from both the hang
// monitor channel and the PContent channel, we have an ordering problem. This
// code ensures that we respect the order in which the requests were made and
// ignore stale requests.
if (mLayerObserverEpoch >= aLayerObserverEpoch) {
return IPC_OK();
}
mLayerObserverEpoch = aLayerObserverEpoch;
// If we're currently waiting for window opening to complete, we need to hold
// off on setting the docshell active. We queue up the values we're receiving
// in the mWindowOpenDocShellActiveStatus.
if (mPendingDocShellBlockers > 0) {
mPendingDocShellReceivedMessage = true;
mPendingDocShellIsActive = aIsActive;
mPendingDocShellPreserveLayers = aPreserveLayers;
return IPC_OK();
}
InternalSetDocShellIsActive(aIsActive, aPreserveLayers);
return IPC_OK();
}
@ -3175,6 +3212,13 @@ TabChild::RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes)
return IPC_OK();
}
mozilla::ipc::IPCResult
TabChild::RecvSetWidgetNativeData(const WindowsHandle& aWidgetNativeData)
{
mWidgetNativeData = aWidgetNativeData;
return IPC_OK();
}
mozilla::plugins::PPluginWidgetChild*
TabChild::AllocPPluginWidgetChild()
{

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

@ -694,6 +694,15 @@ public:
}
#endif
void AddPendingDocShellBlocker();
void RemovePendingDocShellBlocker();
// The HANDLE object for the widget this TabChild in.
WindowsHandle WidgetNativeData()
{
return mWidgetNativeData;
}
protected:
virtual ~TabChild();
@ -735,6 +744,8 @@ protected:
virtual mozilla::ipc::IPCResult RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes) override;
virtual mozilla::ipc::IPCResult RecvSetWidgetNativeData(const WindowsHandle& aWidgetNativeData) override;
private:
void HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
const ScrollableLayerGuid& aGuid);
@ -790,6 +801,9 @@ private:
const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId);
void InternalSetDocShellIsActive(bool aIsActive,
bool aPreserveLayers);
class DelayedDeleteRunnable;
TextureFactoryIdentifier mTextureFactoryIdentifier;
@ -870,6 +884,13 @@ private:
PDocAccessibleChild* mTopLevelDocAccessibleChild;
#endif
bool mPendingDocShellIsActive;
bool mPendingDocShellPreserveLayers;
bool mPendingDocShellReceivedMessage;
uint32_t mPendingDocShellBlockers;
WindowsHandle mWidgetNativeData;
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};

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

@ -292,6 +292,17 @@ TabParent::SetOwnerElement(Element* aElement)
AddWindowListeners();
TryCacheDPIAndScale();
// Try to send down WidgetNativeData, now that this TabParent is associated
// with a widget.
nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
if (widget) {
WindowsHandle widgetNativeData = reinterpret_cast<WindowsHandle>(
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
if (widgetNativeData) {
Unused << SendSetWidgetNativeData(widgetNativeData);
}
}
}
void
@ -2315,18 +2326,6 @@ TabParent::GetTopLevelWidget()
return nullptr;
}
mozilla::ipc::IPCResult
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
{
*aValue = 0;
nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
if (widget) {
*aValue = reinterpret_cast<WindowsHandle>(
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
}
return IPC_OK();
}
mozilla::ipc::IPCResult
TabParent::RecvSetNativeChildOfShareableWindow(const uintptr_t& aChildWindow)
{
@ -2580,21 +2579,31 @@ TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
const nsString& aURL,
const nsString& aName,
const nsString& aFeatures,
bool* aOutWindowOpened,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId,
CompositorOptions* aCompositorOptions,
uint32_t* aMaxTouchPoints)
BrowserFrameOpenWindowResolver&& aResolve)
{
CreatedWindowInfo cwi;
cwi.rv() = NS_OK;
cwi.layersId() = 0;
cwi.maxTouchPoints() = 0;
BrowserElementParent::OpenWindowResult opened =
BrowserElementParent::OpenWindowOOP(TabParent::GetFrom(aOpener),
this, aRenderFrame, aURL, aName, aFeatures,
aTextureFactoryIdentifier, aLayersId);
*aCompositorOptions = static_cast<RenderFrameParent*>(aRenderFrame)->GetCompositorOptions();
*aOutWindowOpened = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
&cwi.textureFactoryIdentifier(),
&cwi.layersId());
cwi.compositorOptions() =
static_cast<RenderFrameParent*>(aRenderFrame)->GetCompositorOptions();
cwi.windowOpened() = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
nsCOMPtr<nsIWidget> widget = GetWidget();
*aMaxTouchPoints = widget ? widget->GetMaxTouchPoints() : 0;
if (!*aOutWindowOpened) {
if (widget) {
cwi.maxTouchPoints() = widget->GetMaxTouchPoints();
cwi.dimensions() = GetDimensionInfo();
}
// Resolve the request with the information we collected.
aResolve(cwi);
if (!cwi.windowOpened()) {
Destroy();
}
return IPC_OK();

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

@ -165,16 +165,13 @@ public:
virtual mozilla::ipc::IPCResult
RecvSetHasBeforeUnload(const bool& aHasBeforeUnload) override;
virtual mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
virtual mozilla::ipc::IPCResult
RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
PRenderFrameParent* aRenderFrame,
const nsString& aURL,
const nsString& aName,
const nsString& aFeatures,
bool* aOutWindowOpened,
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId,
CompositorOptions* aCompositorOptions,
uint32_t* aMaxTouchPoints) override;
BrowserFrameOpenWindowResolver&& aResolve) override;
virtual mozilla::ipc::IPCResult
RecvSyncMessage(const nsString& aMessage,
@ -308,8 +305,6 @@ public:
virtual mozilla::ipc::IPCResult RecvGetWidgetRounding(int32_t* aValue) override;
virtual mozilla::ipc::IPCResult RecvGetWidgetNativeData(WindowsHandle* aValue) override;
virtual mozilla::ipc::IPCResult RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
virtual mozilla::ipc::IPCResult RecvDispatchFocusToTopLevelWindow() override;

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

@ -12,18 +12,18 @@ support-files =
[test_has_permissions.html]
[test_permissions.html]
[test_register.html]
skip-if = os == "win" && !debug # Bug 1373346
skip-if = os == "win" # Bug 1373346
[test_register_key.html]
[test_multiple_register.html]
[test_multiple_register_during_service_activation.html]
[test_unregister.html]
[test_multiple_register_different_scope.html]
[test_subscription_change.html]
skip-if = os == "win" && !debug # Bug 1373346
skip-if = os == "win" # Bug 1373346
[test_data.html]
skip-if = os == "win" && !debug # Bug 1373346
skip-if = os == "win" # Bug 1373346
[test_try_registering_offline_disabled.html]
skip-if = os == "win" && !debug # Bug 1373346
skip-if = os == "win" # Bug 1373346
[test_serviceworker_lifetime.html]
skip-if = os == "win" && !debug # Bug 1373346
skip-if = os == "win" # Bug 1373346
[test_error_reporting.html]

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

@ -13,6 +13,7 @@ EXPORTS += [
'nsBindingManager.h',
'nsXBLBinding.h',
'nsXBLService.h',
'nsXBLWindowKeyHandler.h',
]
EXPORTS.mozilla.dom += [

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

@ -17,9 +17,7 @@ class nsIDOMKeyEvent;
class nsXBLPrototypeHandler;
namespace mozilla {
namespace dom {
struct IgnoreModifierState;
} // namespace dom
} // namespace mozilla
class nsXBLEventHandler : public nsIDOMEventListener
@ -55,7 +53,7 @@ private:
class nsXBLKeyEventHandler : public nsIDOMEventListener
{
typedef mozilla::dom::IgnoreModifierState IgnoreModifierState;
typedef mozilla::IgnoreModifierState IgnoreModifierState;
public:
nsXBLKeyEventHandler(nsIAtom* aEventType, uint8_t aPhase, uint8_t aType);

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

@ -12,6 +12,7 @@
#include "nsXBLPrototypeBinding.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsGlobalWindowCommands.h"
#include "nsIContent.h"
#include "nsIAtom.h"
#include "nsIDOMKeyEvent.h"
@ -46,13 +47,16 @@
#include "mozilla/BasicEvents.h"
#include "mozilla/JSEventHandler.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/EventHandlerBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/layers/KeyboardMap.h"
#include "xpcpublic.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
@ -136,6 +140,66 @@ nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLPrototypeHandler, this, mNextHandler);
}
bool
nsXBLPrototypeHandler::TryConvertToKeyboardShortcut(
KeyboardShortcut* aOut) const
{
// Convert the event type
KeyboardInput::KeyboardEventType eventType;
if (mEventName == nsGkAtoms::keydown) {
eventType = KeyboardInput::KEY_DOWN;
} else if (mEventName == nsGkAtoms::keypress) {
eventType = KeyboardInput::KEY_PRESS;
} else if (mEventName == nsGkAtoms::keyup) {
eventType = KeyboardInput::KEY_UP;
} else {
return false;
}
// Convert the modifiers
Modifiers modifiersMask = GetModifiers();
Modifiers modifiers = GetModifiersMask();
// Mask away any bits that won't be compared
modifiers &= modifiersMask;
// Convert the keyCode or charCode
uint32_t keyCode;
uint32_t charCode;
if (mMisc) {
keyCode = 0;
charCode = static_cast<uint32_t>(mDetail);
} else {
keyCode = static_cast<uint32_t>(mDetail);
charCode = 0;
}
NS_LossyConvertUTF16toASCII commandText(mHandlerText);
KeyboardScrollAction action;
if (!nsGlobalWindowCommands::FindScrollCommand(commandText.get(), &action)) {
// This action doesn't represent a scroll so we need to create a dispatch
// to content keyboard shortcut so APZ handles this command correctly
*aOut = KeyboardShortcut(eventType,
keyCode,
charCode,
modifiers,
modifiersMask);
return true;
}
// This prototype is a command which represents a scroll action, so create
// a keyboard shortcut to handle it
*aOut = KeyboardShortcut(eventType,
keyCode,
charCode,
modifiers,
modifiersMask,
action);
return true;
}
already_AddRefed<nsIContent>
nsXBLPrototypeHandler::GetHandlerElement()
{
@ -539,6 +603,54 @@ nsXBLPrototypeHandler::DispatchXULKeyCommand(nsIDOMEvent* aEvent)
return NS_OK;
}
Modifiers
nsXBLPrototypeHandler::GetModifiers() const
{
Modifiers modifiers = 0;
if (mKeyMask & cMeta) {
modifiers |= MODIFIER_META;
}
if (mKeyMask & cOS) {
modifiers |= MODIFIER_OS;
}
if (mKeyMask & cShift) {
modifiers |= MODIFIER_SHIFT;
}
if (mKeyMask & cAlt) {
modifiers |= MODIFIER_ALT;
}
if (mKeyMask & cControl) {
modifiers |= MODIFIER_CONTROL;
}
return modifiers;
}
Modifiers
nsXBLPrototypeHandler::GetModifiersMask() const
{
Modifiers modifiersMask = 0;
if (mKeyMask & cMetaMask) {
modifiersMask |= MODIFIER_META;
}
if (mKeyMask & cOSMask) {
modifiersMask |= MODIFIER_OS;
}
if (mKeyMask & cShiftMask) {
modifiersMask |= MODIFIER_SHIFT;
}
if (mKeyMask & cAltMask) {
modifiersMask |= MODIFIER_ALT;
}
if (mKeyMask & cControlMask) {
modifiersMask |= MODIFIER_CONTROL;
}
return modifiersMask;
}
already_AddRefed<nsIAtom>
nsXBLPrototypeHandler::GetEventName()
{

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

@ -7,6 +7,7 @@
#ifndef nsXBLPrototypeHandler_h__
#define nsXBLPrototypeHandler_h__
#include "mozilla/EventForwards.h"
#include "nsIAtom.h"
#include "nsString.h"
#include "nsCOMPtr.h"
@ -27,10 +28,18 @@ class nsIObjectOutputStream;
class nsXBLPrototypeBinding;
namespace mozilla {
struct IgnoreModifierState;
namespace dom {
class AutoJSAPI;
class EventTarget;
} // namespace dom
namespace layers {
class KeyboardShortcut;
} // namespace layers
} // namespace mozilla
#define NS_HANDLER_TYPE_XBL_JS (1 << 0)
@ -46,29 +55,11 @@ class EventTarget;
#define NS_PHASE_TARGET 2
#define NS_PHASE_BUBBLING 3
namespace mozilla {
namespace dom {
struct IgnoreModifierState
{
// When mShift is true, Shift key state will be ignored.
bool mShift;
// When mOS is true, OS key state will be ignored.
bool mOS;
IgnoreModifierState()
: mShift(false)
, mOS(false)
{
}
};
} // namespace dom
} // namespace mozilla
class nsXBLPrototypeHandler
{
typedef mozilla::dom::IgnoreModifierState IgnoreModifierState;
typedef mozilla::IgnoreModifierState IgnoreModifierState;
typedef mozilla::layers::KeyboardShortcut KeyboardShortcut;
typedef mozilla::Modifiers Modifiers;
public:
// This constructor is used by XBL handlers (both the JS and command shorthand variety)
@ -90,6 +81,17 @@ public:
~nsXBLPrototypeHandler();
/**
* Try and convert this XBL handler into an APZ KeyboardShortcut for handling
* key events on the compositor thread. This only works for XBL handlers that
* represent scroll commands.
*
* @param aOut the converted KeyboardShortcut, must be non null
* @return whether the handler was converted into a KeyboardShortcut
*/
bool TryConvertToKeyboardShortcut(
KeyboardShortcut* aOut) const;
bool EventTypeEquals(nsIAtom* aEventType) const
{
return mEventName == aEventType;
@ -186,6 +188,10 @@ protected:
nsresult DispatchXULKeyCommand(nsIDOMEvent* aEvent);
nsresult EnsureEventHandler(mozilla::dom::AutoJSAPI& jsapi, nsIAtom* aName,
JS::MutableHandle<JSObject*> aHandler);
Modifiers GetModifiers() const;
Modifiers GetModifiersMask() const;
static int32_t KeyToMask(int32_t key);
static int32_t AccelKeyMask();

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

@ -25,17 +25,21 @@
#include "nsIPresShell.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/Move.h"
#include "nsISelectionController.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsIEditor.h"
#include "nsIHTMLEditor.h"
#include "nsIDOMDocument.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
class nsXBLSpecialDocInfo : public nsIObserver
{
@ -146,9 +150,18 @@ nsXBLSpecialDocInfo::GetAllHandlers(const char* aType,
}
// Init statics
nsXBLSpecialDocInfo* nsXBLWindowKeyHandler::sXBLSpecialDocInfo = nullptr;
static StaticRefPtr<nsXBLSpecialDocInfo> sXBLSpecialDocInfo;
uint32_t nsXBLWindowKeyHandler::sRefCnt = 0;
/* static */ void
nsXBLWindowKeyHandler::EnsureSpecialDocInfo()
{
if (!sXBLSpecialDocInfo) {
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
}
sXBLSpecialDocInfo->LoadDocInfo();
}
nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement,
EventTarget* aTarget)
: mTarget(aTarget),
@ -167,7 +180,7 @@ nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
--sRefCnt;
if (!sRefCnt) {
NS_IF_RELEASE(sXBLSpecialDocInfo);
sXBLSpecialDocInfo = nullptr;
}
}
@ -228,11 +241,7 @@ nsXBLWindowKeyHandler::EnsureHandlers()
nsCOMPtr<nsIContent> content(do_QueryInterface(el));
BuildHandlerChain(content, &mHandler);
} else { // We are an XBL file of handlers.
if (!sXBLSpecialDocInfo) {
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
NS_ADDREF(sXBLSpecialDocInfo);
}
sXBLSpecialDocInfo->LoadDocInfo();
EnsureSpecialDocInfo();
// Now determine which handlers we should be using.
if (IsHTMLEditableFieldFocused()) {
@ -397,6 +406,41 @@ nsXBLWindowKeyHandler::RemoveKeyboardEventListenersFrom(
TrustedEventsAtSystemGroupBubble());
}
/* static */ KeyboardMap
nsXBLWindowKeyHandler::CollectKeyboardShortcuts()
{
// Load the XBL handlers
EnsureSpecialDocInfo();
nsXBLPrototypeHandler* handlers = nullptr;
nsXBLPrototypeHandler* userHandlers = nullptr;
sXBLSpecialDocInfo->GetAllHandlers("browser", &handlers, &userHandlers);
// Convert the handlers into keyboard shortcuts, using an AutoTArray with
// the maximum amount of shortcuts used on any platform to minimize allocations
AutoTArray<KeyboardShortcut, 46> shortcuts;
for (nsXBLPrototypeHandler* handler = handlers;
handler;
handler = handler->GetNextHandler()) {
KeyboardShortcut shortcut;
if (handler->TryConvertToKeyboardShortcut(&shortcut)) {
shortcuts.AppendElement(shortcut);
}
}
for (nsXBLPrototypeHandler* handler = userHandlers;
handler;
handler = handler->GetNextHandler()) {
KeyboardShortcut shortcut;
if (handler->TryConvertToKeyboardShortcut(&shortcut)) {
shortcuts.AppendElement(shortcut);
}
}
return KeyboardMap(mozilla::Move(shortcuts));
}
nsIAtom*
nsXBLWindowKeyHandler::ConvertEventToDOMEventType(
const WidgetKeyboardEvent& aWidgetKeyboardEvent) const

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

@ -8,28 +8,29 @@
#define nsXBLWindowKeyHandler_h__
#include "mozilla/EventForwards.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsWeakPtr.h"
#include "nsIDOMEventListener.h"
class nsIAtom;
class nsIDOMElement;
class nsIDOMKeyEvent;
class nsXBLSpecialDocInfo;
class nsXBLPrototypeHandler;
namespace mozilla {
class EventListenerManager;
struct IgnoreModifierState;
namespace dom {
class Element;
class EventTarget;
struct IgnoreModifierState;
} // namespace dom
} // namespace mozilla
class nsXBLWindowKeyHandler : public nsIDOMEventListener
{
typedef mozilla::dom::IgnoreModifierState IgnoreModifierState;
typedef mozilla::EventListenerManager EventListenerManager;
typedef mozilla::IgnoreModifierState IgnoreModifierState;
typedef mozilla::layers::KeyboardMap KeyboardMap;
public:
nsXBLWindowKeyHandler(nsIDOMElement* aElement, mozilla::dom::EventTarget* aTarget);
@ -39,6 +40,8 @@ public:
void RemoveKeyboardEventListenersFrom(
EventListenerManager* aEventListenerManager);
static KeyboardMap CollectKeyboardShortcuts();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
@ -80,6 +83,9 @@ protected:
nsIAtom* ConvertEventToDOMEventType(
const mozilla::WidgetKeyboardEvent& aWidgetKeyboardEvent) const;
// lazily load the special doc info for loading handlers
static void EnsureSpecialDocInfo();
// lazily load the handlers. Overridden to handle being attached
// to a particular element rather than the document
nsresult EnsureHandlers();
@ -120,8 +126,7 @@ protected:
nsXBLPrototypeHandler* mHandler; // platform bindings
nsXBLPrototypeHandler* mUserHandler; // user-specific bindings
// holds document info about bindings
static nsXBLSpecialDocInfo* sXBLSpecialDocInfo;
// holds reference count to document info about bindings
static uint32_t sRefCnt;
};

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

@ -197,6 +197,18 @@ struct TextureFactoryIdentifier
, mUsingAdvancedLayers(false)
, mSyncHandle(aSyncHandle)
{}
bool operator==(const TextureFactoryIdentifier& aOther) const {
return
mParentBackend == aOther.mParentBackend &&
mParentProcessType == aOther.mParentProcessType &&
mMaxTextureSize == aOther.mMaxTextureSize &&
mCompositorUseANGLE == aOther.mCompositorUseANGLE &&
mSupportsTextureBlitting == aOther.mSupportsTextureBlitting &&
mSupportsPartialUploads == aOther.mSupportsPartialUploads &&
mSupportsComponentAlpha == aOther.mSupportsComponentAlpha &&
mSyncHandle == aOther.mSyncHandle;
}
};
/**

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

@ -690,6 +690,12 @@ struct ScrollSnapInfo {
mScrollSnapCoordinates == aOther.mScrollSnapCoordinates;
}
bool HasScrollSnapping() const
{
return mScrollSnapTypeY != NS_STYLE_SCROLL_SNAP_TYPE_NONE ||
mScrollSnapTypeX != NS_STYLE_SCROLL_SNAP_TYPE_NONE;
}
// The scroll frame's scroll-snap-type.
// One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}.
uint8_t mScrollSnapTypeX;

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

@ -2102,6 +2102,15 @@ Layer::RemoveUserData(void* aKey)
return d;
}
void
Layer::SetManager(LayerManager* aManager, HostLayer* aSelf)
{
// No one should be calling this for weird reasons.
MOZ_ASSERT(aSelf);
MOZ_ASSERT(aSelf->GetLayer() == this);
mManager = aManager;
}
void
PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{

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

@ -97,6 +97,7 @@ class ReadbackLayer;
class ReadbackProcessor;
class RefLayer;
class HostLayer;
class FocusTarget;
class KnowsCompositor;
class ShadowableLayer;
class ShadowLayerForwarder;
@ -599,6 +600,11 @@ public:
*/
virtual void SetIsFirstPaint() {}
/**
* Set the current focus target to be sent with the next paint.
*/
virtual void SetFocusTarget(const FocusTarget& aFocusTarget) {}
/**
* Make sure that the previous transaction has been entirely
* completed.
@ -844,6 +850,11 @@ public:
*/
LayerManager* Manager() { return mManager; }
/**
* This should only be called when changing layer managers from HostLayers.
*/
void SetManager(LayerManager* aManager, HostLayer* aSelf);
enum {
/**
* If this is set, the caller is promising that by the end of this

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

@ -11,6 +11,7 @@
#include "mozilla/EventStateManager.h" // for WheelPrefs
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc
#include "mozilla/MouseEvents.h" // for WidgetMouseEvent
#include "mozilla/TextEvents.h" // for WidgetKeyboardEvent
#include "mozilla/TouchEvents.h" // for WidgetTouchEvent
namespace mozilla {
@ -69,11 +70,12 @@ IAPZCTreeManager::ReceiveInputEvent(
mouseEvent.mRefPoint.x = input.mOrigin.x;
mouseEvent.mRefPoint.y = input.mOrigin.y;
mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
mouseEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
return status;
}
TransformEventRefPoint(&mouseEvent.mRefPoint, aOutTargetGuid);
ProcessUnhandledEvent(&mouseEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore;
}
case eTouchEventClass: {
@ -92,6 +94,7 @@ IAPZCTreeManager::ReceiveInputEvent(
touchInput.mTouches[i].ToNewDOMTouch();
}
touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
touchEvent.mFocusSequenceNumber = touchInput.mFocusSequenceNumber;
return result;
}
@ -133,18 +136,30 @@ IAPZCTreeManager::ReceiveInputEvent(
wheelEvent.mRefPoint.x = input.mOrigin.x;
wheelEvent.mRefPoint.y = input.mOrigin.y;
wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
return status;
}
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid);
ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore;
}
case eKeyboardEventClass: {
WidgetKeyboardEvent& keyboardEvent = *aEvent.AsKeyboardEvent();
KeyboardInput input(keyboardEvent);
nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
keyboardEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
keyboardEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
return status;
}
default: {
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid);
ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore;
}

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

@ -21,6 +21,8 @@ class InputData;
namespace layers {
class KeyboardMap;
enum AllowedTouchBehavior {
NONE = 0,
VERTICAL_PAN = 1 << 0,
@ -104,6 +106,11 @@ public:
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId);
/**
* Set the keyboard shortcuts to use for translating keyboard events.
*/
virtual void SetKeyboardMap(const KeyboardMap& aKeyboardMap) = 0;
/**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set
@ -204,9 +211,10 @@ protected:
// Methods to help process WidgetInputEvents (or manage conversion to/from InputData)
virtual void TransformEventRefPoint(
virtual void ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) = 0;
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) = 0;
virtual void UpdateWheelTransaction(
LayoutDeviceIntPoint aRefPoint,

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

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stack>
#include <unordered_set>
#include "APZCTreeManager.h"
#include "AsyncPanZoomController.h"
#include "Compositor.h" // for Compositor
@ -21,6 +22,7 @@
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
#include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
#include "mozilla/layers/FocusState.h" // for FocusState
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/WebRenderScrollDataWrapper.h"
#include "mozilla/MouseEvents.h"
@ -82,6 +84,11 @@ struct APZCTreeManager::TreeBuildingState {
// This is initialized with all nodes in the old tree, and nodes are removed
// from it as we reuse them in the new tree.
nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy;
// A set of layer trees that are no longer in the hit testing tree. This is
// used to destroy unneeded focus targets at the end of tree building. This
// is needed in addition to mNodesToDestroy because a hit testing node for a
// layer tree can be removed without the whole layer tree being removed.
std::unordered_set<uint64_t> mLayersIdsToDestroy;
// This map is populated as we place APZCs into the new tree. Its purpose is
// to facilitate re-using the same APZC for different layers that scroll
@ -158,6 +165,35 @@ APZCTreeManager::CheckerboardFlushObserver::Observe(nsISupports* aSubject,
return NS_OK;
}
/**
* A RAII class used for setting the focus sequence number on input events
* as they are being processed. Any input event is assumed to be potentially
* focus changing unless explicitly marked otherwise.
*/
class MOZ_RAII AutoFocusSequenceNumberSetter
{
public:
AutoFocusSequenceNumberSetter(FocusState& aFocusState, InputData& aEvent)
: mFocusState(aFocusState)
, mEvent(aEvent)
, mMayChangeFocus(true)
{ }
void MarkAsNonFocusChanging() { mMayChangeFocus = false; }
~AutoFocusSequenceNumberSetter()
{
if (mMayChangeFocus) {
mFocusState.ReceiveFocusChangingEvent();
}
mEvent.mFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
}
private:
FocusState& mFocusState;
InputData& mEvent;
bool mMayChangeFocus;
};
/*static*/ const ScreenMargin
APZCTreeManager::CalculatePendingDisplayPort(
@ -263,6 +299,7 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
{
state.mNodesToDestroy.AppendElement(aNode);
});
state.mLayersIdsToDestroy = mFocusState.GetFocusTargetLayerIds();
mRootNode = nullptr;
if (aRoot) {
@ -273,6 +310,8 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
uint64_t layersId = aRootLayerTreeId;
ancestorTransforms.push(Matrix4x4());
state.mLayersIdsToDestroy.erase(aRootLayerTreeId);
mApzcTreeLog << "[start]\n";
mTreeLock.AssertCurrentThreadOwns();
@ -310,7 +349,15 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
MOZ_ASSERT(!node->GetFirstChild());
parent = node;
next = nullptr;
layersId = aLayerMetrics.GetReferentId().valueOr(layersId);
// Update the layersId if we have a new one
if (Maybe<uint64_t> newLayersId = aLayerMetrics.GetReferentId()) {
layersId = *newLayersId;
// Mark that this layer tree is being used
state.mLayersIdsToDestroy.erase(layersId);
}
indents.push(gfx::TreeAutoIndent(mApzcTreeLog));
},
[&](ScrollNode aLayerMetrics)
@ -335,6 +382,11 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
state.mNodesToDestroy[i]->Destroy();
}
// Clear out any focus targets that are no longer needed
for (auto layersId : state.mLayersIdsToDestroy) {
mFocusState.RemoveFocusTarget(layersId);
}
#if ENABLE_APZCTM_LOGGING
// Make the hit-test tree line up with the layer dump
printf_stderr("APZCTreeManager (%p)\n", this);
@ -342,6 +394,20 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
#endif
}
void
APZCTreeManager::UpdateFocusState(uint64_t aRootLayerTreeId,
uint64_t aOriginatingLayersId,
const FocusTarget& aFocusTarget)
{
if (!gfxPrefs::APZKeyboardEnabled()) {
return;
}
mFocusState.Update(aRootLayerTreeId,
aOriginatingLayersId,
aFocusTarget);
}
void
APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
Layer* aRoot,
@ -868,6 +934,9 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
{
APZThreadUtils::AssertOnControllerThread();
// Use a RAII class for updating the focus sequence number of this event
AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
#if defined(MOZ_WIDGET_ANDROID)
MOZ_ASSERT(mToolbarAnimator);
ScreenPoint scrollOffset;
@ -1035,7 +1104,6 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
FlushRepaintsToClearScreenToGeckoTransform();
ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
if (!wheelInput.mHandledByAPZ) {
return result;
@ -1176,6 +1244,91 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
apzc->GetGuid(aOutTargetGuid);
tapInput.mPoint = *untransformedPoint;
}
break;
} case KEYBOARD_INPUT: {
// Disable async keyboard scrolling when accessibility.browsewithcaret is enabled
if (!gfxPrefs::APZKeyboardEnabled() ||
gfxPrefs::AccessibilityBrowseWithCaret()) {
return result;
}
KeyboardInput& keyInput = aEvent.AsKeyboardInput();
// Try and find a matching shortcut for this keyboard input
Maybe<KeyboardShortcut> shortcut = mKeyboardMap.FindMatch(keyInput);
if (!shortcut) {
// If we don't have a shortcut for this key event, then we can keep our focus
// only if we know there are no key event listeners for this target
if (mFocusState.CanIgnoreKeyboardShortcutMisses()) {
focusSetter.MarkAsNonFocusChanging();
}
return result;
}
// Check if this shortcut needs to be dispatched to content. Anything matching
// this is assumed to be able to change focus.
if (shortcut->mDispatchToContent) {
return result;
}
// We know we have an action to execute on whatever is the current focus target
const KeyboardScrollAction& action = shortcut->mAction;
// The current focus target depends on which direction the scroll is to happen
Maybe<ScrollableLayerGuid> targetGuid;
switch (action.mType)
{
case KeyboardScrollAction::eScrollCharacter: {
targetGuid = mFocusState.GetHorizontalTarget();
break;
}
case KeyboardScrollAction::eScrollLine:
case KeyboardScrollAction::eScrollPage:
case KeyboardScrollAction::eScrollComplete: {
targetGuid = mFocusState.GetVerticalTarget();
break;
}
case KeyboardScrollAction::eSentinel: {
MOZ_ASSERT_UNREACHABLE("Invalid KeyboardScrollActionType");
}
}
// If we don't have a scroll target then either we have a stale focus target,
// the focused element has event listeners, or the focused element doesn't have a
// layerized scroll frame. In any case we need to dispatch to content.
if (!targetGuid) {
return result;
}
RefPtr<AsyncPanZoomController> targetApzc = GetTargetAPZC(targetGuid->mLayersId,
targetGuid->mScrollId);
// Scroll snapping behavior with keyboard input is more complicated, so
// ignore any input events that are targeted at an Apzc with scroll snap
// points.
if (!targetApzc || targetApzc->HasScrollSnapping()) {
return result;
}
// Attach the keyboard scroll action to the input event for processing
// by the input queue.
keyInput.mAction = action;
// Dispatch the event to the input queue.
result = mInputQueue->ReceiveInputEvent(
targetApzc,
/* aTargetConfirmed = */ true,
keyInput, aOutInputBlockId);
// Any keyboard event that is dispatched to the input queue at this point
// should have been consumed
MOZ_ASSERT(result == nsEventStatus_eConsumeNoDefault);
keyInput.mHandledByAPZ = true;
focusSetter.MarkAsNonFocusChanging();
break;
} case SENTINEL_INPUT: {
MOZ_ASSERT_UNREACHABLE("Invalid InputType.");
@ -1404,8 +1557,9 @@ APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
}
void
APZCTreeManager::TransformEventRefPoint(LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid)
APZCTreeManager::ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber)
{
// Transform the aRefPoint.
// If the event hits an overscrolled APZC, instruct the caller to ignore it.
@ -1427,6 +1581,10 @@ APZCTreeManager::TransformEventRefPoint(LayoutDeviceIntPoint* aRefPoint,
ViewAs<LayoutDevicePixel>(*untransformedRefPoint, LDIsScreen);
}
}
// Update the focus sequence number and attach it to the event
mFocusState.ReceiveFocusChangingEvent();
*aOutFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
}
void
@ -1437,6 +1595,12 @@ APZCTreeManager::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
}
}
void
APZCTreeManager::SetKeyboardMap(const KeyboardMap& aKeyboardMap)
{
mKeyboardMap = aKeyboardMap;
}
void
APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
const CSSRect& aRect,

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

@ -14,6 +14,8 @@
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/layers/TouchCounter.h"// for TouchCounter
#include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager
#include "mozilla/layers/KeyboardMap.h" // for KeyboardMap
#include "mozilla/layers/FocusState.h" // for FocusState
#include "mozilla/Mutex.h" // for Mutex
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for mozilla::TimeStamp
@ -40,6 +42,7 @@ class APZCTreeManagerParent;
class CompositorBridgeParent;
class OverscrollHandoffChain;
struct OverscrollHandoffState;
class FocusTarget;
struct FlingHandoffState;
struct ScrollableLayerGuidHash;
class LayerMetricsWrapper;
@ -111,6 +114,19 @@ public:
*/
static void InitializeGlobalState();
/**
* Rebuild the focus state based on the focus target from the layer tree update
* that just occurred.
*
* @param aRootLayerTreeId The layer tree ID of the root layer corresponding
* to this APZCTreeManager
* @param aOriginatingLayersId The layer tree ID of the layer corresponding to
* this layer tree update.
*/
void UpdateFocusState(uint64_t aRootLayerTreeId,
uint64_t aOriginatingLayersId,
const FocusTarget& aFocusTarget);
/**
* Rebuild the hit-testing tree based on the layer update that just came up.
* Preserve nodes and APZC instances where possible, but retire those whose
@ -211,6 +227,11 @@ public:
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override;
/**
* Set the keyboard shortcuts to use for translating keyboard events.
*/
void SetKeyboardMap(const KeyboardMap& aKeyboardMap) override;
/**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set
@ -430,9 +451,10 @@ public:
// Methods to help process WidgetInputEvents (or manage conversion to/from InputData)
void TransformEventRefPoint(
void ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) override;
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) override;
void UpdateWheelTransaction(
LayoutDeviceIntPoint aRefPoint,
@ -550,6 +572,14 @@ private:
/* Holds the zoom constraints for scrollable layers, as determined by the
* the main-thread gecko code. */
std::unordered_map<ScrollableLayerGuid, ZoomConstraints, ScrollableLayerGuidHash> mZoomConstraints;
/* A list of keyboard shortcuts to use for translating keyboard inputs into
* keyboard actions. This is gathered on the main thread from XBL bindings.
*/
KeyboardMap mKeyboardMap;
/* This tracks the focus targets of chrome and content and whether we have
* a current focus target or whether we are waiting for a new confirmation.
*/
FocusState mFocusState;
/* This tracks the APZC that should receive all inputs for the current input event block.
* This allows touch points to move outside the thing they started on, but still have the
* touch events delivered to the same initial APZC. This will only ever be touched on the

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

@ -18,6 +18,7 @@ namespace mozilla {
namespace layers {
class WheelScrollAnimation;
class KeyboardScrollAnimation;
class SmoothScrollAnimation;
class AsyncPanZoomAnimation {
@ -50,6 +51,9 @@ public:
return Move(mDeferredTasks);
}
virtual KeyboardScrollAnimation* AsKeyboardScrollAnimation() {
return nullptr;
}
virtual WheelScrollAnimation* AsWheelScrollAnimation() {
return nullptr;
}

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

@ -77,6 +77,7 @@
#include "SharedMemoryBasic.h" // for SharedMemoryBasic
#include "ScrollSnap.h" // for ScrollSnapUtils
#include "WheelScrollAnimation.h"
#include "KeyboardScrollAnimation.h"
#if defined(MOZ_WIDGET_ANDROID)
#include "AndroidAPZ.h"
#include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
@ -1005,6 +1006,11 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
rv = HandleGestureEvent(tapInput);
break;
}
case KEYBOARD_INPUT: {
KeyboardInput keyInput = aEvent.AsKeyboardInput();
rv = OnKeyboard(keyInput);
break;
}
case SENTINEL_INPUT: {
MOZ_ASSERT_UNREACHABLE("Invalid value");
break;
@ -1067,6 +1073,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
case SMOOTH_SCROLL:
case OVERSCROLL_ANIMATION:
case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case PAN_MOMENTUM:
MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
@ -1142,6 +1149,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case OVERSCROLL_ANIMATION:
// Should not receive a touch-move in the OVERSCROLL_ANIMATION state
// as touch blocks that begin in an overscrolled state cancel the
@ -1222,6 +1230,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case OVERSCROLL_ANIMATION:
// Should not receive a touch-end in the OVERSCROLL_ANIMATION state
// as touch blocks that begin in an overscrolled state cancel the
@ -1656,6 +1665,152 @@ AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent) cons
return delta;
}
static
void ReportKeyboardScrollAction(const KeyboardScrollAction& aAction)
{
ScrollInputMethod scrollMethod;
switch (aAction.mType) {
case KeyboardScrollAction::eScrollLine: {
scrollMethod = ScrollInputMethod::ApzScrollLine;
break;
}
case KeyboardScrollAction::eScrollCharacter: {
scrollMethod = ScrollInputMethod::ApzScrollCharacter;
break;
}
case KeyboardScrollAction::eScrollPage: {
scrollMethod = ScrollInputMethod::ApzScrollPage;
break;
}
case KeyboardScrollAction::eScrollComplete: {
scrollMethod = ScrollInputMethod::ApzCompleteScroll;
break;
}
case KeyboardScrollAction::eSentinel: {
MOZ_ASSERT_UNREACHABLE("Invalid KeyboardScrollAction.");
return;
}
}
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
(uint32_t)scrollMethod);
}
nsEventStatus
AsyncPanZoomController::OnKeyboard(const KeyboardInput& aEvent)
{
// Report the type of scroll action to telemetry
ReportKeyboardScrollAction(aEvent.mAction);
// Calculate the destination for this keyboard scroll action
nsPoint destination = CSSPoint::ToAppUnits(GetKeyboardDestination(aEvent.mAction));
// The lock must be held across the entire update operation, so the
// compositor doesn't end the animation before we get a chance to
// update it.
ReentrantMonitorAutoEnter lock(mMonitor);
// Use a keyboard scroll animation to scroll, reusing an existing one if it exists
if (mState != KEYBOARD_SCROLL) {
CancelAnimation();
SetState(KEYBOARD_SCROLL);
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
StartAnimation(new KeyboardScrollAnimation(*this, initialPosition, aEvent.mAction.mType));
}
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to
// appunits/second. We perform a cast to ParentLayerPoints/ms without a
// conversion so that the scroll duration isn't affected by zoom
nsPoint velocity =
CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), mY.GetVelocity())) * 1000.0f;
KeyboardScrollAnimation* animation = mAnimation->AsKeyboardScrollAnimation();
MOZ_ASSERT(animation);
animation->UpdateDestination(aEvent.mTimeStamp, destination, nsSize(velocity.x, velocity.y));
return nsEventStatus_eConsumeNoDefault;
}
CSSPoint
AsyncPanZoomController::GetKeyboardDestination(const KeyboardScrollAction& aAction) const
{
CSSSize lineScrollSize;
CSSSize pageScrollSize;
CSSPoint scrollOffset;
CSSRect scrollRect;
{
// Grab the lock to access the frame metrics.
ReentrantMonitorAutoEnter lock(mMonitor);
lineScrollSize = mScrollMetadata.GetLineScrollAmount() /
mFrameMetrics.GetDevPixelsPerCSSPixel();
pageScrollSize = mScrollMetadata.GetPageScrollAmount() /
mFrameMetrics.GetDevPixelsPerCSSPixel();
if (mState == WHEEL_SCROLL) {
scrollOffset = mAnimation->AsWheelScrollAnimation()->GetDestination();
} else if (mState == SMOOTH_SCROLL) {
scrollOffset = mAnimation->AsSmoothScrollAnimation()->GetDestination();
} else if (mState == KEYBOARD_SCROLL) {
scrollOffset = mAnimation->AsKeyboardScrollAnimation()->GetDestination();
} else {
scrollOffset = mFrameMetrics.GetScrollOffset();
}
scrollRect = mFrameMetrics.GetScrollableRect();
}
// Calculate the scroll destination based off of the scroll type and direction
CSSPoint scrollDestination = scrollOffset;
switch (aAction.mType) {
case KeyboardScrollAction::eScrollCharacter: {
int32_t scrollDistance = gfxPrefs::ToolkitHorizontalScrollDistance();
if (aAction.mForward) {
scrollDestination.x += scrollDistance * lineScrollSize.width;
} else {
scrollDestination.x -= scrollDistance * lineScrollSize.width;
}
break;
}
case KeyboardScrollAction::eScrollLine: {
int32_t scrollDistance = gfxPrefs::ToolkitVerticalScrollDistance();
if (aAction.mForward) {
scrollDestination.y += scrollDistance * lineScrollSize.height;
} else {
scrollDestination.y -= scrollDistance * lineScrollSize.height;
}
break;
}
case KeyboardScrollAction::eScrollPage: {
if (aAction.mForward) {
scrollDestination.y += pageScrollSize.height;
} else {
scrollDestination.y -= pageScrollSize.height;
}
break;
}
case KeyboardScrollAction::eScrollComplete: {
if (aAction.mForward) {
scrollDestination.y = scrollRect.YMost();
} else {
scrollDestination.y = scrollRect.y;
}
break;
}
case KeyboardScrollAction::eSentinel:
MOZ_ASSERT_UNREACHABLE("unexpected keyboard delta type");
}
return scrollDestination;
}
// Return whether or not the underlying layer can be scrolled on either axis.
bool
AsyncPanZoomController::CanScroll(const InputData& aEvent) const
@ -1822,6 +1977,8 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
startPosition = mAnimation->AsWheelScrollAnimation()->GetDestination();
} else if (mState == SMOOTH_SCROLL) {
startPosition = mAnimation->AsSmoothScrollAnimation()->GetDestination();
} else if (mState == KEYBOARD_SCROLL) {
startPosition = mAnimation->AsKeyboardScrollAnimation()->GetDestination();
}
if (MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition)) {
// If we're scroll snapping, use a smooth scroll animation to get
@ -1845,12 +2002,13 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
nsPoint deltaInAppUnits =
CSSPoint::ToAppUnits(delta / mFrameMetrics.GetZoom());
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to
// appunits/second
// appunits/second. We perform a cast to ParentLayerPoints/ms without a
// conversion so that the scroll duration isn't affected by zoom
nsPoint velocity =
CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), mY.GetVelocity())) * 1000.0f;
WheelScrollAnimation* animation = mAnimation->AsWheelScrollAnimation();
animation->Update(aEvent.mTimeStamp, deltaInAppUnits, nsSize(velocity.x, velocity.y));
animation->UpdateDelta(aEvent.mTimeStamp, deltaInAppUnits, nsSize(velocity.x, velocity.y));
break;
}
@ -2608,7 +2766,8 @@ void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination) {
SetState(SMOOTH_SCROLL);
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to
// appunits/second
// appunits/second. We perform a cast to ParentLayerPoints/ms without a
// conversion so that the scroll duration isn't affected by zoom
nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(),
mY.GetVelocity())) * 1000.0f;
nsPoint destination = CSSPoint::ToAppUnits(aDestination);

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

@ -61,6 +61,7 @@ class OverscrollEffectBase;
class WidgetOverscrollEffect;
class GenericOverscrollEffect;
class AndroidSpecificState;
struct KeyboardScrollAction;
// Base class for grouping platform-specific APZC state variables.
class PlatformSpecificStateBase {
@ -339,6 +340,13 @@ public:
*/
bool HasScrollgrab() const { return mScrollMetadata.GetHasScrollgrab(); }
/**
* Returns whether this APZC has scroll snap points.
*/
bool HasScrollSnapping() const {
return mScrollMetadata.GetSnapInfo().HasScrollSnapping();
}
/**
* Returns whether this APZC has room to be panned (in any direction).
*/
@ -482,6 +490,13 @@ protected:
ParentLayerPoint GetScrollWheelDelta(const ScrollWheelInput& aEvent) const;
/**
* Helper methods for handling keyboard events.
*/
nsEventStatus OnKeyboard(const KeyboardInput& aEvent);
CSSPoint GetKeyboardDestination(const KeyboardScrollAction& aAction) const;
/**
* Helper methods for long press gestures.
*/
@ -839,7 +854,8 @@ protected:
the finger is lifted. */
SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by
CSSOM-View smooth scroll-behavior */
WHEEL_SCROLL /* Smooth scrolling to a destination for a wheel event. */
WHEEL_SCROLL, /* Smooth scrolling to a destination for a wheel event. */
KEYBOARD_SCROLL /* Smooth scrolling to a destination for a keyboard event. */
};
// This is in theory protected by |mMonitor|; that is, it should be held whenever
@ -936,7 +952,9 @@ private:
friend class GenericFlingAnimation;
friend class OverscrollAnimation;
friend class SmoothScrollAnimation;
friend class GenericScrollAnimation;
friend class WheelScrollAnimation;
friend class KeyboardScrollAnimation;
friend class GenericOverscrollEffect;
friend class WidgetOverscrollEffect;

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

@ -0,0 +1,147 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "mozilla/layers/FocusState.h"
namespace mozilla {
namespace layers {
FocusState::FocusState()
: mLastAPZProcessedEvent(1)
, mLastContentProcessedEvent(0)
, mFocusHasKeyEventListeners(false)
, mFocusLayersId(0)
, mFocusHorizontalTarget(FrameMetrics::NULL_SCROLL_ID)
, mFocusVerticalTarget(FrameMetrics::NULL_SCROLL_ID)
{
}
bool
FocusState::IsCurrent() const
{
MOZ_ASSERT(mLastContentProcessedEvent <= mLastAPZProcessedEvent);
return mLastContentProcessedEvent == mLastAPZProcessedEvent;
}
void
FocusState::ReceiveFocusChangingEvent()
{
mLastAPZProcessedEvent += 1;
}
void
FocusState::Update(uint64_t aRootLayerTreeId,
uint64_t aOriginatingLayersId,
const FocusTarget& aState)
{
// Update the focus tree with the latest target
mFocusTree[aOriginatingLayersId] = aState;
// Reset our internal state so we can recalculate it
mFocusHasKeyEventListeners = false;
mFocusLayersId = aRootLayerTreeId;
mFocusHorizontalTarget = FrameMetrics::NULL_SCROLL_ID;
mFocusVerticalTarget = FrameMetrics::NULL_SCROLL_ID;
// To update the focus state for the entire APZCTreeManager, we need
// to traverse the focus tree to find the current leaf which is the global
// focus target we can use for async keyboard scrolling
while (true) {
auto currentNode = mFocusTree.find(mFocusLayersId);
if (currentNode == mFocusTree.end()) {
return;
}
const FocusTarget& target = currentNode->second;
// Accumulate event listener flags on the path to the focus target
mFocusHasKeyEventListeners |= target.mFocusHasKeyEventListeners;
switch (target.mType) {
case FocusTarget::eRefLayer: {
// Guard against infinite loops
MOZ_ASSERT(mFocusLayersId != target.mData.mRefLayerId);
if (mFocusLayersId == target.mData.mRefLayerId) {
return;
}
// The focus target is in a child layer tree
mFocusLayersId = target.mData.mRefLayerId;
break;
}
case FocusTarget::eScrollLayer: {
// This is the global focus target
mFocusHorizontalTarget = target.mData.mScrollTargets.mHorizontal;
mFocusVerticalTarget = target.mData.mScrollTargets.mVertical;
// Mark what sequence number this target has so we can determine whether
// it is stale or not
mLastContentProcessedEvent = target.mSequenceNumber;
return;
}
case FocusTarget::eNone: {
// Mark what sequence number this target has for debugging purposes so
// we can always accurately report on whether we are stale or not
mLastContentProcessedEvent = target.mSequenceNumber;
return;
}
case FocusTarget::eSentinel: {
MOZ_ASSERT_UNREACHABLE("Invalid FocusTargetType");
}
}
}
}
std::unordered_set<uint64_t>
FocusState::GetFocusTargetLayerIds() const
{
std::unordered_set<uint64_t> layersIds;
layersIds.reserve(mFocusTree.size());
for (const auto& focusNode : mFocusTree) {
layersIds.insert(focusNode.first);
}
return layersIds;
}
void
FocusState::RemoveFocusTarget(uint64_t aLayersId)
{
mFocusTree.erase(aLayersId);
}
Maybe<ScrollableLayerGuid>
FocusState::GetHorizontalTarget() const
{
// There is not a scrollable layer to async scroll if
// 1. We aren't current
// 2. There are event listeners that could change the focus
// 3. The target has not been layerized
if (!IsCurrent() ||
mFocusHasKeyEventListeners ||
mFocusHorizontalTarget == FrameMetrics::NULL_SCROLL_ID) {
return Nothing();
}
return Some(ScrollableLayerGuid(mFocusLayersId, 0, mFocusHorizontalTarget));
}
Maybe<ScrollableLayerGuid>
FocusState::GetVerticalTarget() const
{
// There is not a scrollable layer to async scroll if:
// 1. We aren't current
// 2. There are event listeners that could change the focus
// 3. The target has not been layerized
if (!IsCurrent() ||
mFocusHasKeyEventListeners ||
mFocusVerticalTarget == FrameMetrics::NULL_SCROLL_ID) {
return Nothing();
}
return Some(ScrollableLayerGuid(mFocusLayersId, 0, mFocusVerticalTarget));
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,173 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_layers_FocusState_h
#define mozilla_layers_FocusState_h
#include <unordered_map> // for std::unordered_map
#include <unordered_set> // for std::unordered_set
#include "FrameMetrics.h" // for FrameMetrics::ViewID
#include "mozilla/layers/FocusTarget.h" // for FocusTarget
namespace mozilla {
namespace layers {
/**
* This class is used for tracking chrome and content focus targets and calculating
* global focus information from them for use by APZCTreeManager for async keyboard
* scrolling.
*
* # Calculating the element to scroll
*
* Chrome and content processes have independently focused elements. This makes it
* difficult to calculate the global focused element and its scrollable frame from
* the chrome or content side. So instead we send the local focus information from
* each process to here and then calculate the global focus information. This
* local information resides in a `focus target`.
*
* A focus target indicates that either:
* 1. The focused element is a remote browser along with its layer tree ID
* 2. The focused element is not scrollable
* 3. The focused element is scrollable along with the ViewID's of its
scrollable layers
*
* Using this information we can determine the global focus information by
* starting at the focus target of the root layer tree ID and following remote
* browsers until we reach a scrollable or non-scrollable focus target.
*
* # Determinism and sequence numbers
*
* The focused element in content can be changed within any javascript code. And
* javascript can run in response to an event or at any moment from `setTimeout`
* and others. This makes it impossible to always have the current focus
* information in APZ as it can be changed asynchronously at any moment. If we
* don't have the latest focus information, we may incorrectly scroll a target
* when we shouldn't.
*
* A tradeoff is designed here whereby we will maintain deterministic focus
* changes for user input, but not for other javascript code. The reasoning
* here is that `setTimeout` and others are already non-deterministic and so it
* might not be as breaking to web content.
*
* To maintain deterministic focus changes for a given stream of user inputs, we
* invalidate our focus state whenever we receive a user input that may trigger
* event listeners. We then attach a new sequence number to these events and
* dispatch them to content. Content will then include the latest sequence number
* it has processed to every focus update. Using this we can determine whether
* any potentially focus changing events have yet to be handled by content.
*
* Once we have received the latest focus sequence number from content, we know
* that all event listeners triggered by user inputs, and their resulting focus
* changes, have been processed and so we have a current target that we can use
* again.
*/
class FocusState final
{
public:
FocusState();
/**
* The sequence number of the last potentially focus changing event processed
* by APZ. This number starts at one and increases monotonically. This number
* will never be zero as that is used to catch uninitialized focus sequence
* numbers on input events.
*/
uint64_t LastAPZProcessedEvent() const { return mLastAPZProcessedEvent; }
/**
* Whether the current focus state is known to be current or else if an event
* has been processed that could change the focus but we have not received an
* update with a new confirmed target.
*/
bool IsCurrent() const;
/**
* Notify focus state of a potentially focus changing event. This will
* increment the current focus sequence number. The new value can be gotten
* from LastAPZProcessedEvent().
*/
void ReceiveFocusChangingEvent();
/**
* Update the internal focus tree and recalculate the global focus target for
* a focus target update received from chrome or content.
*
* @param aRootLayerTreeId the layer tree ID of the root layer for the
parent APZCTreeManager
* @param aOriginatingLayersId the layer tree ID that this focus target
belongs to
*/
void Update(uint64_t aRootLayerTreeId,
uint64_t aOriginatingLayersId,
const FocusTarget& aTarget);
/**
* Collects a set of the layer tree IDs that we have a focus target for.
*/
std::unordered_set<uint64_t> GetFocusTargetLayerIds() const;
/**
* Removes a focus target by its layer tree ID.
*/
void RemoveFocusTarget(uint64_t aLayersId);
/**
* Gets the scrollable layer that should be horizontally scrolled for a key
* event, if any. The returned ScrollableLayerGuid doesn't contain a presShellId,
* and so it should not be used in comparisons.
*
* No scrollable layer is returned if any of the following are true:
* 1. We don't have a current focus target
* 2. There are event listeners that could change the focus
* 3. The target has not been layerized
*/
Maybe<ScrollableLayerGuid> GetHorizontalTarget() const;
/**
* The same as GetHorizontalTarget() but for vertical scrolling.
*/
Maybe<ScrollableLayerGuid> GetVerticalTarget() const;
/**
* Gets whether it is safe to not increment the focus sequence number for an
* unmatched keyboard event.
*/
bool CanIgnoreKeyboardShortcutMisses() const
{
return IsCurrent() && !mFocusHasKeyEventListeners;
}
private:
// The set of focus targets received indexed by their layer tree ID
std::unordered_map<uint64_t, FocusTarget> mFocusTree;
// The focus sequence number of the last potentially focus changing event
// processed by APZ. This number starts at one and increases monotonically.
// We don't worry about wrap around here because at a pace of 100 increments/sec,
// it would take 5.85*10^9 years before we would wrap around. This number will
// never be zero as that is used to catch uninitialized focus sequence numbers
// on input events.
uint64_t mLastAPZProcessedEvent;
// The focus sequence number last received in a focus update.
uint64_t mLastContentProcessedEvent;
// A flag whether there is a key listener on the event target chain for the
// focused element
bool mFocusHasKeyEventListeners;
// The layer tree ID which contains the scrollable frame of the focused element
uint64_t mFocusLayersId;
// The scrollable layer corresponding to the scrollable frame that is used to
// scroll the focused element. This depends on the direction the user is
// scrolling.
FrameMetrics::ViewID mFocusHorizontalTarget;
FrameMetrics::ViewID mFocusVerticalTarget;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_FocusState_h

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

@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "mozilla/layers/FocusTarget.h"
#include "mozilla/dom/EventTarget.h" // for EventTarget
#include "mozilla/dom/TabParent.h" // for TabParent
#include "mozilla/EventDispatcher.h" // for EventDispatcher
#include "mozilla/layout/RenderFrameParent.h" // For RenderFrameParent
#include "nsIPresShell.h" // for nsIPresShell
#include "nsLayoutUtils.h" // for nsLayoutUtils
using namespace mozilla::dom;
using namespace mozilla::layout;
namespace mozilla {
namespace layers {
static already_AddRefed<nsIPresShell>
GetRetargetEventPresShell(nsIPresShell* aRootPresShell)
{
MOZ_ASSERT(aRootPresShell);
// Use the last focused window in this PresShell and its
// associated PresShell
nsCOMPtr<nsPIDOMWindowOuter> window =
aRootPresShell->GetFocusedDOMWindowInOurWindow();
if (!window) {
return nullptr;
}
nsCOMPtr<nsIDocument> retargetEventDoc = window->GetExtantDoc();
if (!retargetEventDoc) {
return nullptr;
}
nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
return presShell.forget();
}
static bool
HasListenersForKeyEvents(nsIContent* aContent)
{
if (!aContent) {
return false;
}
WidgetEvent event(true, eVoidEvent);
nsTArray<EventTarget*> targets;
nsresult rv = EventDispatcher::Dispatch(aContent, nullptr, &event, nullptr,
nullptr, nullptr, &targets);
NS_ENSURE_SUCCESS(rv, false);
for (size_t i = 0; i < targets.Length(); i++) {
if (targets[i]->HasUntrustedOrNonSystemGroupKeyEventListeners()) {
return true;
}
}
return false;
}
static bool
IsEditableNode(nsINode* aNode)
{
return aNode && aNode->IsEditable();
}
FocusTarget::FocusTarget()
: mSequenceNumber(0)
, mFocusHasKeyEventListeners(false)
, mType(FocusTarget::eNone)
{
}
FocusTarget::FocusTarget(nsIPresShell* aRootPresShell,
uint64_t aFocusSequenceNumber)
: mSequenceNumber(aFocusSequenceNumber)
, mFocusHasKeyEventListeners(false)
{
MOZ_ASSERT(aRootPresShell);
MOZ_ASSERT(NS_IsMainThread());
// Key events can be retargeted to a child PresShell when there is an iframe
nsCOMPtr<nsIPresShell> presShell = GetRetargetEventPresShell(aRootPresShell);
// Get the content that should be scrolled for this PresShell, which is
// the current focused element or the current DOM selection
nsCOMPtr<nsIContent> scrollTarget = presShell->GetContentForScrolling();
// Collect event listener information so we can track what is potentially focus
// changing
mFocusHasKeyEventListeners = HasListenersForKeyEvents(scrollTarget);
// Check if the scroll target is a remote browser
if (TabParent* browserParent = TabParent::GetFrom(scrollTarget)) {
RenderFrameParent* rfp = browserParent->GetRenderFrame();
// The globally focused element for scrolling is in a remote layer tree
if (rfp) {
mType = FocusTarget::eRefLayer;
mData.mRefLayerId = rfp->GetLayersId();
return;
}
mType = FocusTarget::eNone;
return;
}
// If the focus isn't on a remote browser then check for scrollable targets
if (IsEditableNode(scrollTarget) ||
IsEditableNode(presShell->GetDocument())) {
mType = FocusTarget::eNone;
return;
}
// Gather the scrollable frames that would be scrolled in each direction
// for this scroll target
nsIScrollableFrame* horizontal =
presShell->GetScrollableFrameToScrollForContent(scrollTarget.get(),
nsIPresShell::eHorizontal);
nsIScrollableFrame* vertical =
presShell->GetScrollableFrameToScrollForContent(scrollTarget.get(),
nsIPresShell::eVertical);
// We might have the globally focused element for scrolling. Gather a ViewID for
// the horizontal and vertical scroll targets of this element.
mType = FocusTarget::eScrollLayer;
mData.mScrollTargets.mHorizontal =
nsLayoutUtils::FindIDForScrollableFrame(horizontal);
mData.mScrollTargets.mVertical =
nsLayoutUtils::FindIDForScrollableFrame(vertical);
}
bool
FocusTarget::operator==(const FocusTarget& aRhs) const
{
if (mSequenceNumber != aRhs.mSequenceNumber ||
mFocusHasKeyEventListeners != aRhs.mFocusHasKeyEventListeners ||
mType != aRhs.mType) {
return false;
}
if (mType == FocusTarget::eRefLayer) {
return mData.mRefLayerId == aRhs.mData.mRefLayerId;
} else if (mType == FocusTarget::eScrollLayer) {
return mData.mScrollTargets.mHorizontal == aRhs.mData.mScrollTargets.mHorizontal &&
mData.mScrollTargets.mVertical == aRhs.mData.mScrollTargets.mVertical;
}
return true;
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_layers_FocusTarget_h
#define mozilla_layers_FocusTarget_h
#include <stdint.h> // for int32_t, uint32_t
#include "FrameMetrics.h" // for FrameMetrics::ViewID
class nsIPresShell;
namespace mozilla {
namespace layers {
/**
* This class is used for communicating information about the currently focused
* element of a document and the scrollable frames to use when keyboard scrolling
* it. It is created on the main thread at paint-time, but is then passed over
* IPC to the compositor/APZ code.
*/
class FocusTarget final
{
public:
struct ScrollTargets
{
FrameMetrics::ViewID mHorizontal;
FrameMetrics::ViewID mVertical;
};
enum FocusTargetType
{
eNone,
eRefLayer,
eScrollLayer,
// Used as an upper bound for ContiguousEnumSerializer
eSentinel,
};
union FocusTargetData
{
uint64_t mRefLayerId;
ScrollTargets mScrollTargets;
};
FocusTarget();
/**
* Construct a focus target for the specified top level PresShell
*/
FocusTarget(nsIPresShell* aRootPresShell,
uint64_t aFocusSequenceNumber);
bool operator==(const FocusTarget& aRhs) const;
public:
// The content sequence number recorded at the time of this class's creation
uint64_t mSequenceNumber;
// Whether there are keydown, keypress, or keyup event listeners
// in the event target chain of the focused element
bool mFocusHasKeyEventListeners;
FocusTargetType mType;
FocusTargetData mData;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_FocusTarget_h

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

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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/. */
#include "GenericScrollAnimation.h"
#include "AsyncPanZoomController.h"
#include "gfxPrefs.h"
#include "nsPoint.h"
namespace mozilla {
namespace layers {
GenericScrollAnimation::GenericScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition)
: AsyncScrollBase(aInitialPosition)
, mApzc(aApzc)
, mFinalDestination(aInitialPosition)
, mForceVerticalOverscroll(false)
{
}
void
GenericScrollAnimation::UpdateDelta(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity)
{
mFinalDestination += aDelta;
Update(aTime, aCurrentVelocity);
}
void
GenericScrollAnimation::UpdateDestination(TimeStamp aTime, nsPoint aDestination, const nsSize& aCurrentVelocity)
{
mFinalDestination = aDestination;
Update(aTime, aCurrentVelocity);
}
void
GenericScrollAnimation::Update(TimeStamp aTime, const nsSize& aCurrentVelocity)
{
if (mIsFirstIteration) {
InitializeHistory(aTime);
}
// Clamp the final destination to the scrollable area.
CSSPoint clamped = CSSPoint::FromAppUnits(mFinalDestination);
clamped.x = mApzc.mX.ClampOriginToScrollableRect(clamped.x);
clamped.y = mApzc.mY.ClampOriginToScrollableRect(clamped.y);
mFinalDestination = CSSPoint::ToAppUnits(clamped);
AsyncScrollBase::Update(aTime, mFinalDestination, aCurrentVelocity);
}
bool
GenericScrollAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta)
{
TimeStamp now = mApzc.GetFrameTime();
CSSToParentLayerScale2D zoom = aFrameMetrics.GetZoom();
// If the animation is finished, make sure the final position is correct by
// using one last displacement. Otherwise, compute the delta via the timing
// function as normal.
bool finished = IsFinished(now);
nsPoint sampledDest = finished
? mDestination
: PositionAt(now);
ParentLayerPoint displacement =
(CSSPoint::FromAppUnits(sampledDest) - aFrameMetrics.GetScrollOffset()) * zoom;
if (finished) {
mApzc.mX.SetVelocity(0);
mApzc.mY.SetVelocity(0);
} else if (!IsZero(displacement)) {
// Velocity is measured in ParentLayerCoords / Milliseconds
float xVelocity = displacement.x / aDelta.ToMilliseconds();
float yVelocity = displacement.y / aDelta.ToMilliseconds();
mApzc.mX.SetVelocity(xVelocity);
mApzc.mY.SetVelocity(yVelocity);
}
// Note: we ignore overscroll for generic animations.
ParentLayerPoint adjustedOffset, overscroll;
mApzc.mX.AdjustDisplacement(displacement.x, adjustedOffset.x, overscroll.x);
mApzc.mY.AdjustDisplacement(displacement.y, adjustedOffset.y, overscroll.y,
mForceVerticalOverscroll);
// If we expected to scroll, but there's no more scroll range on either axis,
// then end the animation early. Note that the initial displacement could be 0
// if the compositor ran very quickly (<1ms) after the animation was created.
// When that happens we want to make sure the animation continues.
if (!IsZero(displacement) && IsZero(adjustedOffset)) {
// Nothing more to do - end the animation.
return false;
}
aFrameMetrics.ScrollBy(adjustedOffset / zoom);
return !finished;
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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/. */
#ifndef mozilla_layers_GenericScrollAnimation_h_
#define mozilla_layers_GenericScrollAnimation_h_
#include "AsyncPanZoomAnimation.h"
#include "AsyncScrollBase.h"
namespace mozilla {
namespace layers {
class AsyncPanZoomController;
class GenericScrollAnimation
: public AsyncPanZoomAnimation,
public AsyncScrollBase
{
public:
GenericScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition);
bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) override;
void UpdateDelta(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity);
void UpdateDestination(TimeStamp aTime, nsPoint aDestination, const nsSize& aCurrentVelocity);
CSSPoint GetDestination() const {
return CSSPoint::FromAppUnits(mFinalDestination);
}
private:
void Update(TimeStamp aTime, const nsSize& aCurrentVelocity);
protected:
AsyncPanZoomController& mApzc;
nsPoint mFinalDestination;
bool mForceVerticalOverscroll;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_GenericScrollAnimation_h_

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

@ -870,5 +870,10 @@ TouchBlockState::GetActiveTouchCount() const
return mTouchCounter.GetActiveTouchCount();
}
KeyboardBlockState::KeyboardBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc)
: InputBlockState(aTargetApzc, true)
{
}
} // namespace layers
} // namespace mozilla

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

@ -27,6 +27,7 @@ class TouchBlockState;
class WheelBlockState;
class DragBlockState;
class PanGestureBlockState;
class KeyboardBlockState;
/**
* A base class that stores state common to various input blocks.
@ -68,6 +69,9 @@ public:
virtual PanGestureBlockState* AsPanGestureBlock() {
return nullptr;
}
virtual KeyboardBlockState* AsKeyboardBlock() {
return nullptr;
}
virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
TargetConfirmationState aState,
@ -486,6 +490,23 @@ private:
TouchCounter& mTouchCounter;
};
/**
* This class represents a set of keyboard inputs targeted at the same Apzc.
*/
class KeyboardBlockState : public InputBlockState
{
public:
explicit KeyboardBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc);
KeyboardBlockState* AsKeyboardBlock() override {
return this;
}
bool MustStayActive() override {
return false;
}
};
} // namespace layers
} // namespace mozilla

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

@ -56,6 +56,14 @@ InputQueue::ReceiveInputEvent(const RefPtr<AsyncPanZoomController>& aTarget,
return ReceiveMouseInput(aTarget, aTargetConfirmed, event, aOutInputBlockId);
}
case KEYBOARD_INPUT: {
// Every keyboard input must have a confirmed target
MOZ_ASSERT(aTarget && aTargetConfirmed);
const KeyboardInput& event = aEvent.AsKeyboardInput();
return ReceiveKeyboardInput(aTarget, event, aOutInputBlockId);
}
default:
// The return value for non-touch input is only used by tests, so just pass
// through the return value for now. This can be changed later if needed.
@ -268,6 +276,39 @@ InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarge
return nsEventStatus_eConsumeDoDefault;
}
nsEventStatus
InputQueue::ReceiveKeyboardInput(const RefPtr<AsyncPanZoomController>& aTarget,
const KeyboardInput& aEvent,
uint64_t* aOutInputBlockId) {
KeyboardBlockState* block = mActiveKeyboardBlock.get();
// If the block is targeting a different Apzc than this keyboard event then
// we'll create a new input block
if (block && block->GetTargetApzc() != aTarget) {
block = nullptr;
}
if (!block) {
block = new KeyboardBlockState(aTarget);
INPQ_LOG("started new keyboard block %p id %" PRIu64 " for target %p\n",
block, block->GetBlockId(), aTarget.get());
mActiveKeyboardBlock = block;
} else {
INPQ_LOG("received new event in block %p\n", block);
}
if (aOutInputBlockId) {
*aOutInputBlockId = block->GetBlockId();
}
mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(aEvent, *block));
ProcessQueue();
return nsEventStatus_eConsumeNoDefault;
}
static bool
CanScrollTargetHorizontally(const PanGestureInput& aInitialEvent,
PanGestureBlockState* aBlock)
@ -461,6 +502,13 @@ InputQueue::GetCurrentPanGestureBlock() const
return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get();
}
KeyboardBlockState*
InputQueue::GetCurrentKeyboardBlock() const
{
InputBlockState* block = GetCurrentBlock();
return block ? block->AsKeyboardBlock() : mActiveKeyboardBlock.get();
}
WheelBlockState*
InputQueue::GetActiveWheelTransaction() const
{

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

@ -30,6 +30,7 @@ class TouchBlockState;
class WheelBlockState;
class DragBlockState;
class PanGestureBlockState;
class KeyboardBlockState;
class AsyncDragMetrics;
class QueuedInput;
@ -106,6 +107,7 @@ public:
WheelBlockState* GetCurrentWheelBlock() const;
DragBlockState* GetCurrentDragBlock() const;
PanGestureBlockState* GetCurrentPanGestureBlock() const;
KeyboardBlockState* GetCurrentKeyboardBlock() const;
/**
* Returns true iff the pending block at the head of the queue is a touch
* block and is ready for handling.
@ -169,6 +171,9 @@ private:
bool aTargetConfirmed,
const PanGestureInput& aEvent,
uint64_t* aOutInputBlockId);
nsEventStatus ReceiveKeyboardInput(const RefPtr<AsyncPanZoomController>& aTarget,
const KeyboardInput& aEvent,
uint64_t* aOutInputBlockId);
/**
* Helper function that searches mQueuedInputs for the first block matching
@ -202,6 +207,7 @@ private:
RefPtr<WheelBlockState> mActiveWheelBlock;
RefPtr<DragBlockState> mActiveDragBlock;
RefPtr<PanGestureBlockState> mActivePanGestureBlock;
RefPtr<KeyboardBlockState> mActiveKeyboardBlock;
// The APZC to which the last event was delivered
RefPtr<AsyncPanZoomController> mLastActiveApzc;

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

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "mozilla/layers/KeyboardMap.h"
#include "mozilla/TextEvents.h" // for IgnoreModifierState, ShortcutKeyCandidate
namespace mozilla {
namespace layers {
KeyboardShortcut::KeyboardShortcut()
{
}
KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode,
uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask,
const KeyboardScrollAction& aAction)
: mAction(aAction)
, mKeyCode(aKeyCode)
, mCharCode(aCharCode)
, mModifiers(aModifiers)
, mModifiersMask(aModifiersMask)
, mEventType(aEventType)
, mDispatchToContent(false)
{
}
KeyboardShortcut::KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode,
uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask)
: mKeyCode(aKeyCode)
, mCharCode(aCharCode)
, mModifiers(aModifiers)
, mModifiersMask(aModifiersMask)
, mEventType(aEventType)
, mDispatchToContent(true)
{
}
bool
KeyboardShortcut::Matches(const KeyboardInput& aInput,
const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode) const
{
return mEventType == aInput.mType &&
MatchesKey(aInput, aOverrideCharCode) &&
MatchesModifiers(aInput, aIgnore);
}
bool
KeyboardShortcut::MatchesKey(const KeyboardInput& aInput,
uint32_t aOverrideCharCode) const
{
// Compare by the key code if we have one
if (!mCharCode) {
return mKeyCode == aInput.mKeyCode;
}
// We are comparing by char code
uint32_t charCode;
// If we are comparing against a shortcut candidate then we might
// have an override char code
if (aOverrideCharCode) {
charCode = aOverrideCharCode;
} else {
charCode = aInput.mCharCode;
}
// Both char codes must be in lowercase to compare correctly
if (IS_IN_BMP(charCode)) {
charCode = ToLowerCase(static_cast<char16_t>(charCode));
}
return mCharCode == charCode;
}
bool
KeyboardShortcut::MatchesModifiers(const KeyboardInput& aInput,
const IgnoreModifierState& aIgnore) const
{
Modifiers modifiersMask = mModifiersMask;
// If we are ignoring Shift or OS, then unset that part of the mask
if (aIgnore.mOS) {
modifiersMask &= ~MODIFIER_OS;
}
if (aIgnore.mShift) {
modifiersMask &= ~MODIFIER_SHIFT;
}
// Mask off the modifiers we are ignoring from the keyboard input
return (aInput.modifiers & modifiersMask) == mModifiers;
}
KeyboardMap::KeyboardMap(nsTArray<KeyboardShortcut>&& aShortcuts)
: mShortcuts(aShortcuts)
{
}
KeyboardMap::KeyboardMap()
{
}
Maybe<KeyboardShortcut>
KeyboardMap::FindMatch(const KeyboardInput& aEvent) const
{
// If there are no shortcut candidates, then just search with with the
// keyboard input
if (aEvent.mShortcutCandidates.IsEmpty()) {
return FindMatchInternal(aEvent, IgnoreModifierState());
}
// Otherwise do a search with each shortcut candidate in order
for (auto& key : aEvent.mShortcutCandidates) {
IgnoreModifierState ignoreModifierState;
ignoreModifierState.mShift = key.mIgnoreShift;
auto match = FindMatchInternal(aEvent, ignoreModifierState, key.mCharCode);
if (match) {
return match;
}
}
return Nothing();
}
Maybe<KeyboardShortcut>
KeyboardMap::FindMatchInternal(const KeyboardInput& aEvent,
const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode) const
{
for (auto& shortcut : mShortcuts) {
if (shortcut.Matches(aEvent, aIgnore, aOverrideCharCode)) {
return Some(shortcut);
}
}
#ifdef XP_WIN
// Windows native applications ignore Windows-Logo key state when checking
// shortcut keys even if the key is pressed. Therefore, if there is no
// shortcut key which exactly matches current modifier state, we should
// retry to look for a shortcut key without the Windows-Logo key press.
if (!aIgnore.mOS && (aEvent.modifiers & MODIFIER_OS)) {
IgnoreModifierState ignoreModifierState(aIgnore);
ignoreModifierState.mOS = true;
return FindMatchInternal(aEvent, ignoreModifierState, aOverrideCharCode);
}
#endif
return Nothing();
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_layers_KeyboardMap_h
#define mozilla_layers_KeyboardMap_h
#include <stdint.h> // for uint32_t
#include "InputData.h" // for KeyboardInput
#include "nsIScrollableFrame.h" // for nsIScrollableFrame::ScrollUnit
#include "nsTArray.h" // for nsTArray
#include "mozilla/Maybe.h" // for mozilla::Maybe
#include "KeyboardScrollAction.h" // for KeyboardScrollAction
namespace mozilla {
struct IgnoreModifierState;
namespace layers {
class KeyboardMap;
/**
* This class is an off main-thread <xul:handler> for scrolling commands.
*/
class KeyboardShortcut final
{
public:
KeyboardShortcut();
/**
* Create a keyboard shortcut that when matched can be handled by executing
* the specified keyboard action.
*/
KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode,
uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask,
const KeyboardScrollAction& aAction);
/**
* Create a keyboard shortcut that when matched should be handled by ignoring
* the keyboard event and dispatching it to content.
*/
KeyboardShortcut(KeyboardInput::KeyboardEventType aEventType,
uint32_t aKeyCode,
uint32_t aCharCode,
Modifiers aModifiers,
Modifiers aModifiersMask);
protected:
friend mozilla::layers::KeyboardMap;
bool Matches(const KeyboardInput& aInput,
const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode = 0) const;
private:
bool MatchesKey(const KeyboardInput& aInput,
uint32_t aOverrideCharCode) const;
bool MatchesModifiers(const KeyboardInput& aInput,
const IgnoreModifierState& aIgnore) const;
public:
// The action to perform when this shortcut is matched,
// and not flagged to be dispatched to content
KeyboardScrollAction mAction;
// Only one of mKeyCode or mCharCode may be non-zero
// whichever one is non-zero is the one to compare when matching
uint32_t mKeyCode;
uint32_t mCharCode;
// The modifiers that must be active for this shortcut
Modifiers mModifiers;
// The modifiers to compare when matching this shortcut
Modifiers mModifiersMask;
// The type of keyboard event to match against
KeyboardInput::KeyboardEventType mEventType;
// Whether events matched by this must be dispatched to content
bool mDispatchToContent;
};
/**
* A keyboard map is an off main-thread <xul:binding> for scrolling commands.
*/
class KeyboardMap final
{
public:
KeyboardMap();
explicit KeyboardMap(nsTArray<KeyboardShortcut>&& aShortcuts);
const nsTArray<KeyboardShortcut>& Shortcuts() const { return mShortcuts; }
/**
* Search through the internal list of shortcuts for a match for the input event
*/
Maybe<KeyboardShortcut> FindMatch(const KeyboardInput& aEvent) const;
private:
Maybe<KeyboardShortcut> FindMatchInternal(const KeyboardInput& aEvent,
const IgnoreModifierState& aIgnore,
uint32_t aOverrideCharCode = 0) const;
nsTArray<KeyboardShortcut> mShortcuts;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_KeyboardMap_h

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

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "mozilla/layers/KeyboardScrollAction.h"
namespace mozilla {
namespace layers {
/* static */ nsIScrollableFrame::ScrollUnit
KeyboardScrollAction::GetScrollUnit(KeyboardScrollAction::KeyboardScrollActionType aDeltaType)
{
switch (aDeltaType) {
case KeyboardScrollAction::eScrollCharacter:
return nsIScrollableFrame::LINES;
case KeyboardScrollAction::eScrollLine:
return nsIScrollableFrame::LINES;
case KeyboardScrollAction::eScrollPage:
return nsIScrollableFrame::PAGES;
case KeyboardScrollAction::eScrollComplete:
return nsIScrollableFrame::WHOLE;
case KeyboardScrollAction::eSentinel:
MOZ_ASSERT_UNREACHABLE("Invalid KeyboardScrollActionType.");
return nsIScrollableFrame::WHOLE;
}
// Silence an overzealous warning
return nsIScrollableFrame::WHOLE;
}
KeyboardScrollAction::KeyboardScrollAction()
: mType(KeyboardScrollAction::eScrollCharacter)
, mForward(false)
{
}
KeyboardScrollAction::KeyboardScrollAction(KeyboardScrollActionType aType, bool aForward)
: mType(aType)
, mForward(aForward)
{
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_layers_KeyboardScrollAction_h
#define mozilla_layers_KeyboardScrollAction_h
#include "nsIScrollableFrame.h" // for nsIScrollableFrame::ScrollUnit
namespace mozilla {
namespace layers {
/**
* This class represents a scrolling action to be performed on a scrollable layer.
*/
struct KeyboardScrollAction final
{
public:
enum KeyboardScrollActionType : uint8_t
{
eScrollCharacter,
eScrollLine,
eScrollPage,
eScrollComplete,
// Used as an upper bound for ContiguousEnumSerializer
eSentinel,
};
static nsIScrollableFrame::ScrollUnit
GetScrollUnit(KeyboardScrollActionType aDeltaType);
KeyboardScrollAction();
KeyboardScrollAction(KeyboardScrollActionType aType, bool aForward);
// The type of scroll to perform for this action
KeyboardScrollActionType mType;
// Whether to scroll forward or backward along the axis of this action type
bool mForward;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_KeyboardScrollAction_h

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

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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/. */
#include "KeyboardScrollAnimation.h"
#include "gfxPrefs.h"
namespace mozilla {
namespace layers {
KeyboardScrollAnimation::KeyboardScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
KeyboardScrollAction::KeyboardScrollActionType aType)
: GenericScrollAnimation(aApzc, aInitialPosition)
{
switch (aType) {
case KeyboardScrollAction::eScrollCharacter:
case KeyboardScrollAction::eScrollLine: {
mOriginMaxMS = clamped(gfxPrefs::LineSmoothScrollMaxDurationMs(), 0, 10000);
mOriginMinMS = clamped(gfxPrefs::LineSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
break;
}
case KeyboardScrollAction::eScrollPage: {
mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
break;
}
case KeyboardScrollAction::eScrollComplete: {
mOriginMaxMS = clamped(gfxPrefs::OtherSmoothScrollMaxDurationMs(), 0, 10000);
mOriginMinMS = clamped(gfxPrefs::OtherSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
break;
}
case KeyboardScrollAction::eSentinel: {
MOZ_ASSERT_UNREACHABLE("Invalid KeyboardScrollActionType.");
}
}
// The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
mIntervalRatio = std::max(1.0, mIntervalRatio);
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* 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/. */
#ifndef mozilla_layers_KeyboardScrollAnimation_h_
#define mozilla_layers_KeyboardScrollAnimation_h_
#include "GenericScrollAnimation.h"
#include "mozilla/layers/KeyboardMap.h"
namespace mozilla {
namespace layers {
class AsyncPanZoomController;
class KeyboardScrollAnimation
: public GenericScrollAnimation
{
public:
KeyboardScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
KeyboardScrollAction::KeyboardScrollActionType aType);
KeyboardScrollAnimation* AsKeyboardScrollAnimation() override {
return this;
}
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_KeyboardScrollAnimation_h_

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

@ -38,6 +38,12 @@ QueuedInput::QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aB
{
}
QueuedInput::QueuedInput(const KeyboardInput& aInput, KeyboardBlockState& aBlock)
: mInput(MakeUnique<KeyboardInput>(aInput))
, mBlock(&aBlock)
{
}
InputData*
QueuedInput::Input()
{

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

@ -17,6 +17,7 @@ class MultiTouchInput;
class ScrollWheelInput;
class MouseInput;
class PanGestureInput;
class KeyboardInput;
namespace layers {
@ -25,6 +26,7 @@ class TouchBlockState;
class WheelBlockState;
class DragBlockState;
class PanGestureBlockState;
class KeyboardBlockState;
/**
* This lightweight class holds a pointer to an input event that has not yet
@ -38,6 +40,7 @@ public:
QueuedInput(const ScrollWheelInput& aInput, WheelBlockState& aBlock);
QueuedInput(const MouseInput& aInput, DragBlockState& aBlock);
QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aBlock);
QueuedInput(const KeyboardInput& aInput, KeyboardBlockState& aBlock);
InputData* Input();
InputBlockState* Block();

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

@ -16,83 +16,11 @@ namespace layers {
WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
ScrollWheelInput::ScrollDeltaType aDeltaType)
: AsyncScrollBase(aInitialPosition)
, mApzc(aApzc)
, mFinalDestination(aInitialPosition)
, mDeltaType(aDeltaType)
: GenericScrollAnimation(aApzc, aInitialPosition)
{
}
mForceVerticalOverscroll = !mApzc.mScrollMetadata.AllowVerticalScrollWithWheel();
void
WheelScrollAnimation::Update(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity)
{
InitPreferences(aTime);
mFinalDestination += aDelta;
// Clamp the final destination to the scrollable area.
CSSPoint clamped = CSSPoint::FromAppUnits(mFinalDestination);
clamped.x = mApzc.mX.ClampOriginToScrollableRect(clamped.x);
clamped.y = mApzc.mY.ClampOriginToScrollableRect(clamped.y);
mFinalDestination = CSSPoint::ToAppUnits(clamped);
AsyncScrollBase::Update(aTime, mFinalDestination, aCurrentVelocity);
}
bool
WheelScrollAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta)
{
TimeStamp now = mApzc.GetFrameTime();
CSSToParentLayerScale2D zoom = aFrameMetrics.GetZoom();
// If the animation is finished, make sure the final position is correct by
// using one last displacement. Otherwise, compute the delta via the timing
// function as normal.
bool finished = IsFinished(now);
nsPoint sampledDest = finished
? mDestination
: PositionAt(now);
ParentLayerPoint displacement =
(CSSPoint::FromAppUnits(sampledDest) - aFrameMetrics.GetScrollOffset()) * zoom;
if (finished) {
mApzc.mX.SetVelocity(0);
mApzc.mY.SetVelocity(0);
} else if (!IsZero(displacement)) {
// Velocity is measured in ParentLayerCoords / Milliseconds
float xVelocity = displacement.x / aDelta.ToMilliseconds();
float yVelocity = displacement.y / aDelta.ToMilliseconds();
mApzc.mX.SetVelocity(xVelocity);
mApzc.mY.SetVelocity(yVelocity);
}
// Note: we ignore overscroll for wheel animations.
ParentLayerPoint adjustedOffset, overscroll;
mApzc.mX.AdjustDisplacement(displacement.x, adjustedOffset.x, overscroll.x);
mApzc.mY.AdjustDisplacement(displacement.y, adjustedOffset.y, overscroll.y,
!mApzc.mScrollMetadata.AllowVerticalScrollWithWheel());
// If we expected to scroll, but there's no more scroll range on either axis,
// then end the animation early. Note that the initial displacement could be 0
// if the compositor ran very quickly (<1ms) after the animation was created.
// When that happens we want to make sure the animation continues.
if (!IsZero(displacement) && IsZero(adjustedOffset)) {
// Nothing more to do - end the animation.
return false;
}
aFrameMetrics.ScrollBy(adjustedOffset / zoom);
return !finished;
}
void
WheelScrollAnimation::InitPreferences(TimeStamp aTime)
{
if (!mIsFirstIteration) {
return;
}
switch (mDeltaType) {
switch (aDeltaType) {
case ScrollWheelInput::SCROLLDELTA_PAGE:
mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
@ -112,8 +40,6 @@ WheelScrollAnimation::InitPreferences(TimeStamp aTime)
// The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
mIntervalRatio = std::max(1.0, mIntervalRatio);
InitializeHistory(aTime);
}
} // namespace layers

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

@ -7,8 +7,7 @@
#ifndef mozilla_layers_WheelScrollAnimation_h_
#define mozilla_layers_WheelScrollAnimation_h_
#include "AsyncPanZoomAnimation.h"
#include "AsyncScrollBase.h"
#include "GenericScrollAnimation.h"
#include "InputData.h"
namespace mozilla {
@ -17,32 +16,16 @@ namespace layers {
class AsyncPanZoomController;
class WheelScrollAnimation
: public AsyncPanZoomAnimation,
public AsyncScrollBase
: public GenericScrollAnimation
{
public:
WheelScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition,
ScrollWheelInput::ScrollDeltaType aDeltaType);
bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) override;
void Update(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity);
WheelScrollAnimation* AsWheelScrollAnimation() override {
return this;
}
CSSPoint GetDestination() const {
return CSSPoint::FromAppUnits(mFinalDestination);
}
private:
void InitPreferences(TimeStamp aTime);
private:
AsyncPanZoomController& mApzc;
nsPoint mFinalDestination;
ScrollWheelInput::ScrollDeltaType mDeltaType;
};
} // namespace layers

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

@ -51,6 +51,16 @@ enum class ScrollInputMethod {
// Autoscrolling
MainThreadAutoscrolling, // autoscrolling
// Async Keyboard
ApzScrollLine, // line scrolling
// (generally triggered by up/down arrow keys)
ApzScrollCharacter, // character scrolling
// (generally triggered by left/right arrow keys)
ApzScrollPage, // page scrolling
// (generally triggered by PageUp/PageDown keys)
ApzCompleteScroll, // scrolling to the end of the scroll range
// (generally triggered by Home/End keys)
// New input methods can be added at the end, up to a maximum of 64.
// They should only be added at the end, to preserve the numerical values
// of the existing enumerators.

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

@ -17,6 +17,7 @@
#include "nsRect.h" // for mozilla::gfx::IntRect
#include "nsRegion.h" // for nsIntRegion
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/gfx/Helpers.h"
#include "nsDisplayList.h" // for nsDisplayItem
#include "nsCaret.h"

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

@ -811,6 +811,12 @@ ClientLayerManager::SetIsFirstPaint()
mForwarder->SetIsFirstPaint();
}
void
ClientLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget)
{
mForwarder->SetFocusTarget(aFocusTarget);
}
void
ClientLayerManager::ClearCachedResources(Layer* aSubtree)
{

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

@ -14,6 +14,7 @@
#include "mozilla/WidgetUtils.h" // for ScreenRotation
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/FocusTarget.h" // for FocusTarget
#include "mozilla/layers/LayersTypes.h" // for BufferMode, LayersBackend, etc
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
#include "mozilla/layers/APZTestData.h" // for APZTestData
@ -133,6 +134,8 @@ public:
virtual void SetIsFirstPaint() override;
virtual void SetFocusTarget(const FocusTarget& aFocusTarget) override;
/**
* Pass through call to the forwarder for nsPresContext's
* CollectPluginGeometryUpdates. Passes widget configuration information

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

@ -120,7 +120,7 @@ protected:
uint32_t GetPaintFlags();
void UpdateContentClient(PaintState& aState);
bool UpdatePaintRegion(PaintState& aState);
void PaintOffMainThread(DrawTargetCapture* aCapture);
void PaintOffMainThread(gfx::DrawTargetCapture* aCapture);
already_AddRefed<gfx::DrawTargetCapture> CapturePaintedContent();
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;

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

@ -8,6 +8,7 @@
#include "mozilla/EnumeratedArray.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
#include "nsISupportsImpl.h"
#include <string>

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

@ -119,6 +119,20 @@ APZCTreeManagerChild::ReceiveInputEvent(
event = processedEvent;
return res;
}
case KEYBOARD_INPUT: {
KeyboardInput& event = aEvent.AsKeyboardInput();
KeyboardInput processedEvent;
nsEventStatus res;
SendReceiveKeyboardInputEvent(event,
&res,
&processedEvent,
aOutTargetGuid,
aOutInputBlockId);
event = processedEvent;
return res;
}
default: {
MOZ_ASSERT_UNREACHABLE("Invalid InputData type.");
return nsEventStatus_eConsumeNoDefault;
@ -126,6 +140,12 @@ APZCTreeManagerChild::ReceiveInputEvent(
}
}
void
APZCTreeManagerChild::SetKeyboardMap(const KeyboardMap& aKeyboardMap)
{
SendSetKeyboardMap(aKeyboardMap);
}
void
APZCTreeManagerChild::ZoomToRect(
const ScrollableLayerGuid& aGuid,
@ -207,11 +227,15 @@ APZCTreeManagerChild::UpdateWheelTransaction(
SendUpdateWheelTransaction(aRefPoint, aEventMessage);
}
void APZCTreeManagerChild::TransformEventRefPoint(
void APZCTreeManagerChild::ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid)
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber)
{
SendTransformEventRefPoint(*aRefPoint, aRefPoint, aOutTargetGuid);
SendProcessUnhandledEvent(*aRefPoint,
aRefPoint,
aOutTargetGuid,
aOutFocusSequenceNumber);
}
mozilla::ipc::IPCResult

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

@ -30,6 +30,9 @@ public:
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override;
void
SetKeyboardMap(const KeyboardMap& aKeyboardMap) override;
void
ZoomToRect(
const ScrollableLayerGuid& aGuid,
@ -74,9 +77,10 @@ public:
ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY) override;
void
TransformEventRefPoint(
ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) override;
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) override;
void
UpdateWheelTransaction(

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

@ -144,6 +144,33 @@ APZCTreeManagerParent::RecvReceiveScrollWheelInputEvent(
return IPC_OK();
}
mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvReceiveKeyboardInputEvent(
const KeyboardInput& aEvent,
nsEventStatus* aOutStatus,
KeyboardInput* aOutEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId)
{
KeyboardInput event = aEvent;
*aOutStatus = mTreeManager->ReceiveInputEvent(
event,
aOutTargetGuid,
aOutInputBlockId);
*aOutEvent = event;
return IPC_OK();
}
mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvSetKeyboardMap(const KeyboardMap& aKeyboardMap)
{
mTreeManager->SetKeyboardMap(aKeyboardMap);
return IPC_OK();
}
mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvZoomToRect(
const ScrollableLayerGuid& aGuid,
@ -299,13 +326,14 @@ APZCTreeManagerParent::RecvUpdateWheelTransaction(
}
mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvTransformEventRefPoint(
APZCTreeManagerParent::RecvProcessUnhandledEvent(
const LayoutDeviceIntPoint& aRefPoint,
LayoutDeviceIntPoint* aOutRefPoint,
ScrollableLayerGuid* aOutTargetGuid)
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber)
{
LayoutDeviceIntPoint refPoint = aRefPoint;
mTreeManager->TransformEventRefPoint(&refPoint, aOutTargetGuid);
mTreeManager->ProcessUnhandledEvent(&refPoint, aOutTargetGuid, aOutFocusSequenceNumber);
*aOutRefPoint = refPoint;
return IPC_OK();

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

@ -78,6 +78,17 @@ public:
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override;
mozilla::ipc::IPCResult
RecvReceiveKeyboardInputEvent(
const KeyboardInput& aEvent,
nsEventStatus* aOutStatus,
KeyboardInput* aOutEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override;
mozilla::ipc::IPCResult
RecvSetKeyboardMap(const KeyboardMap& aKeyboardMap) override;
mozilla::ipc::IPCResult
RecvZoomToRect(
const ScrollableLayerGuid& aGuid,
@ -129,10 +140,11 @@ public:
const EventMessage& aEventMessage) override;
mozilla::ipc::IPCResult
RecvTransformEventRefPoint(
RecvProcessUnhandledEvent(
const LayoutDeviceIntPoint& aRefPoint,
LayoutDeviceIntPoint* aOutRefPoint,
ScrollableLayerGuid* aOutTargetGuid) override;
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) override;
void
ActorDestroy(ActorDestroyReason aWhy) override { }

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

@ -568,12 +568,13 @@ CompositorBridgeChild::RecvReleaseSharedCompositorFrameMetrics(
const ViewID& aId,
const uint32_t& aAPZCId)
{
SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
if (auto entry = mFrameMetricsTable.Lookup(aId)) {
// The SharedFrameMetricsData may have been removed previously if
// a SharedFrameMetricsData with the same ViewID but later APZCId had
// been store and over wrote it.
if (data && (data->GetAPZCId() == aAPZCId)) {
mFrameMetricsTable.Remove(aId);
if (entry.Data()->GetAPZCId() == aAPZCId) {
entry.Remove();
}
}
return IPC_OK();
}
@ -885,24 +886,18 @@ CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient
void
CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
{
RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
if (!client) {
return;
}
if (aFwdTransactionId < client->GetLastFwdTransactionId()) {
if (auto entry = mTexturesWaitingRecycled.Lookup(aTextureId)) {
if (aFwdTransactionId < entry.Data()->GetLastFwdTransactionId()) {
// Released on host side, but client already requested newer use texture.
return;
}
mTexturesWaitingRecycled.Remove(aTextureId);
entry.Remove();
}
}
void
CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
{
RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
if (!client) {
return;
}
mTexturesWaitingRecycled.Remove(aTextureId);
}

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

@ -15,6 +15,7 @@
#include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
#include "mozilla/webrender/WebRenderTypes.h"
#include "nsClassHashtable.h" // for nsClassHashtable
#include "nsRefPtrHashtable.h"
#include "nsCOMPtr.h" // for nsCOMPtr
#include "nsHashKeys.h" // for nsUint64HashKey
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
@ -318,7 +319,7 @@ private:
* Hold TextureClients refs until end of their usages on host side.
* It defer calling of TextureClient recycle callback.
*/
nsDataHashtable<nsUint64HashKey, RefPtr<TextureClient> > mTexturesWaitingRecycled;
nsRefPtrHashtable<nsUint64HashKey, TextureClient> mTexturesWaitingRecycled;
MessageLoop* mMessageLoop;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше