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 # Generated from ./tools/rewriting/ThirdPartyPaths.txt
# awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt # awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
^browser/components/translation/cld2/.* ^browser/components/translation/cld2/.*
^build/stlport/.*
^db/sqlite3/src/.* ^db/sqlite3/src/.*
^dom/media/platforms/ffmpeg/libav.* ^dom/media/platforms/ffmpeg/libav.*
^extensions/spellcheck/hunspell/src/.* ^extensions/spellcheck/hunspell/src/.*
^gfx/2d/convolver.*
^gfx/2d/image_operations.*
^gfx/angle/.* ^gfx/angle/.*
^gfx/cairo/.* ^gfx/cairo/.*
^gfx/graphite2/.* ^gfx/graphite2/.*

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

@ -33,8 +33,7 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
MOZ_ASSERT(CheckDocTree()); MOZ_ASSERT(CheckDocTree());
if (aData.NewTree().IsEmpty()) { if (aData.NewTree().IsEmpty()) {
NS_ERROR("no children being added"); return IPC_FAIL(this, "No children being added");
return IPC_FAIL_NO_REASON(this);
} }
ProxyAccessible* parent = GetAccessible(aData.ID()); 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 // 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. // entry for the document itself, but it doesn't hurt to be explicit.
if (!aRootID) { if (!aRootID) {
NS_ERROR("trying to hide entire document?"); return IPC_FAIL(this, "Trying to hide entire document?");
return IPC_FAIL_NO_REASON(this);
} }
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID); ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
@ -398,8 +396,7 @@ DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
} }
if (aRole > roles::LAST_ROLE) { if (aRole > roles::LAST_ROLE) {
NS_ERROR("child sent bad role in RoleChangedEvent"); return IPC_FAIL(this, "Child sent bad role in RoleChangedEvent");
return IPC_FAIL_NO_REASON(this);
} }
mRole = static_cast<a11y::role>(aRole); 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. // the accessible description (help text) of this particular instance.
- (NSString*)help; - (NSString*)help;
// returns the orientation (vertical, horizontal, or undefined)
- (NSString*)orientation;
- (BOOL)isEnabled; - (BOOL)isEnabled;
// information about focus. // information about focus.

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

@ -323,6 +323,9 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
} }
if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) if ([attribute isEqualToString:NSAccessibilityHelpAttribute])
return [self help]; return [self help];
if ([attribute isEqualToString:NSAccessibilityOrientationAttribute])
return [self orientation];
if ([attribute isEqualToString:NSAccessibilityDOMIdentifierAttribute]) { if ([attribute isEqualToString:NSAccessibilityDOMIdentifierAttribute]) {
nsAutoString id; nsAutoString id;
if (accWrap) if (accWrap)
@ -1067,6 +1070,28 @@ struct RoleDescrComparator
NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 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. // objc-style description (from NSObject); not to be confused with the accessible description above.
- (NSString*)description - (NSString*)description
{ {

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

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

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

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

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

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

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

@ -40,6 +40,41 @@ add_task(async function clickSuggestion() {
await BrowserTestUtils.removeTab(tab); 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() { function getFirstSuggestion() {
let controller = gURLBar.popup.input.controller; let controller = gURLBar.popup.input.controller;
let matchCount = controller.matchCount; 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 && if (!this._deferredKeyEventQueue.length &&
(this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery)) { (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); let handled = this.mController.handleEnter(false, event);
this.handleEnterSearchString = null; this.handleEnterSearchString = null;
this.popup.overrideValue = null; this.popup.overrideValue = null;

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

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

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

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

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

@ -72,6 +72,11 @@
"optional": true, "optional": true,
"description": "One of 'image', 'video', or 'audio' if the context menu was activated on one of these types of elements." "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": { "linkUrl": {
"type": "string", "type": "string",
"optional": true, "optional": true,

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

@ -73,7 +73,7 @@ add_task(async function() {
type: "separator", 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++) { for (let i = 0; i < contexts.length; i++) {
let context = contexts[i]; let context = contexts[i];
let title = context; let title = context;
@ -183,6 +183,30 @@ add_task(async function() {
checkClickInfo(result); 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. // Test "editable" context and OnClick data property.
extensionMenuRoot = await openExtensionContextMenu("#edit-me"); 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"); equal(onVisited.url, expected.url, "onVisited received the expected url");
// Title will be blank until bug 1287928 lands // Title will be blank until bug 1287928 lands
// https://bugzilla.mozilla.org/show_bug.cgi?id=1287928 // 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.lastVisitTime, expected.time, "onVisited received the expected time");
equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount"); equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
} }

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

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

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

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

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

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

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

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

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

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

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

@ -19,12 +19,6 @@
# define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER} # define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER}
#endif #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 #ifdef _DEBUG
// From // From
// http://msdn.microsoft.com/en-us/library/aa985982%28VS.80%29.aspx // http://msdn.microsoft.com/en-us/library/aa985982%28VS.80%29.aspx

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

@ -895,19 +895,14 @@ StyleEditorUI.prototype = {
this._jumpToLocation.bind(this, location)); this._jumpToLocation.bind(this, location));
let cond = this._panelDoc.createElement("div"); let cond = this._panelDoc.createElement("div");
cond.textContent = rule.conditionText;
cond.className = "media-rule-condition"; cond.className = "media-rule-condition";
if (!rule.matches) { if (!rule.matches) {
cond.classList.add("media-condition-unmatched"); cond.classList.add("media-condition-unmatched");
} }
if (this._target.tab.tagName == "tab") { if (this._target.tab.tagName == "tab") {
const minMaxPattern = /(min\-|max\-)(width|height):\s\d+(px)/ig; this._setConditionContents(cond, rule.conditionText);
const replacement = } else {
"<a href='#' class='media-responsive-mode-toggle'>$&</a>"; cond.textContent = rule.conditionText;
cond.innerHTML = cond.textContent.replace(minMaxPattern, replacement);
cond.addEventListener("click",
this._onMediaConditionClick.bind(this));
} }
div.appendChild(cond); div.appendChild(cond);
@ -927,6 +922,43 @@ StyleEditorUI.prototype = {
}.bind(this)).catch(e => console.error(e)); }.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 * Called when a media condition is clicked
* If a responsive mode link is clicked, it will launch it. * If a responsive mode link is clicked, it will launch it.
@ -935,9 +967,6 @@ StyleEditorUI.prototype = {
* Event object * Event object
*/ */
_onMediaConditionClick: function (e) { _onMediaConditionClick: function (e) {
if (!e.target.matches(".media-responsive-mode-toggle")) {
return;
}
let conditionText = e.target.textContent; let conditionText = e.target.textContent;
let isWidthCond = conditionText.toLowerCase().indexOf("width") > -1; let isWidthCond = conditionText.toLowerCase().indexOf("width") > -1;
let mediaVal = parseInt(/\d+/.exec(conditionText), 10); let mediaVal = parseInt(/\d+/.exec(conditionText), 10);

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

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

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

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

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

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

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

@ -1879,6 +1879,16 @@ public:
*/ */
static void RunInMetastableState(already_AddRefed<nsIRunnable> aRunnable); 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. // Call EnterMicroTask when you're entering JS execution.
// Usually the best way to do this is to use nsAutoMicroTask. // Usually the best way to do this is to use nsAutoMicroTask.
static void EnterMicroTask(); static void EnterMicroTask();
@ -3227,6 +3237,8 @@ private:
*/ */
static bool sFragmentParsingActive; static bool sFragmentParsingActive;
static nsISerialEventTarget* sStableStateEventTarget;
static nsString* sShiftText; static nsString* sShiftText;
static nsString* sControlText; static nsString* sControlText;
static nsString* sMetaText; static nsString* sMetaText;

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

@ -36,11 +36,13 @@
#include "mozilla/BasicEvents.h" #include "mozilla/BasicEvents.h"
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
#include "mozilla/dom/Selection.h" #include "mozilla/dom/Selection.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsIClipboardDragDropHooks.h" #include "nsIClipboardDragDropHooks.h"
#include "nsIClipboardDragDropHookList.h" #include "nsIClipboardDragDropHookList.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::layers;
constexpr const char * sSelectAllString = "cmd_selectAll"; constexpr const char * sSelectAllString = "cmd_selectAll";
constexpr const char * sSelectNoneString = "cmd_selectNone"; constexpr const char * sSelectNoneString = "cmd_selectNone";
@ -271,33 +273,44 @@ IsCaretOnInWindow(nsPIDOMWindowOuter* aWindow, nsISelectionController* aSelCont)
static constexpr struct BrowseCommand { static constexpr struct BrowseCommand {
const char *reverse, *forward; const char *reverse, *forward;
KeyboardScrollAction::KeyboardScrollActionType scrollAction;
nsresult (NS_STDCALL nsISelectionController::*scroll)(bool); nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
nsresult (NS_STDCALL nsISelectionController::*move)(bool, bool); nsresult (NS_STDCALL nsISelectionController::*move)(bool, bool);
} browseCommands[] = { } browseCommands[] = {
{ sScrollTopString, sScrollBottomString, { sScrollTopString, sScrollBottomString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll }, &nsISelectionController::CompleteScroll },
{ sScrollPageUpString, sScrollPageDownString, { sScrollPageUpString, sScrollPageDownString,
KeyboardScrollAction::eScrollPage,
&nsISelectionController::ScrollPage }, &nsISelectionController::ScrollPage },
{ sScrollLineUpString, sScrollLineDownString, { sScrollLineUpString, sScrollLineDownString,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine }, &nsISelectionController::ScrollLine },
{ sScrollLeftString, sScrollRightString, { sScrollLeftString, sScrollRightString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter }, &nsISelectionController::ScrollCharacter },
{ sMoveTopString, sMoveBottomString, { sMoveTopString, sMoveBottomString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll, &nsISelectionController::CompleteScroll,
&nsISelectionController::CompleteMove }, &nsISelectionController::CompleteMove },
{ sMovePageUpString, sMovePageDownString, { sMovePageUpString, sMovePageDownString,
KeyboardScrollAction::eScrollPage,
&nsISelectionController::ScrollPage, &nsISelectionController::ScrollPage,
&nsISelectionController::PageMove }, &nsISelectionController::PageMove },
{ sLinePreviousString, sLineNextString, { sLinePreviousString, sLineNextString,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine, &nsISelectionController::ScrollLine,
&nsISelectionController::LineMove }, &nsISelectionController::LineMove },
{ sWordPreviousString, sWordNextString, { sWordPreviousString, sWordNextString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter, &nsISelectionController::ScrollCharacter,
&nsISelectionController::WordMove }, &nsISelectionController::WordMove },
{ sCharPreviousString, sCharNextString, { sCharPreviousString, sCharNextString,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter, &nsISelectionController::ScrollCharacter,
&nsISelectionController::CharacterMove }, &nsISelectionController::CharacterMove },
{ sBeginLineString, sEndLineString, { sBeginLineString, sEndLineString,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll, &nsISelectionController::CompleteScroll,
&nsISelectionController::IntraLineMove } &nsISelectionController::IntraLineMove }
}; };
@ -334,23 +347,32 @@ nsSelectMoveScrollCommand::DoCommand(const char *aCommandName, nsISupports *aCom
static const struct PhysicalBrowseCommand { static const struct PhysicalBrowseCommand {
const char *command; const char *command;
int16_t direction, amount; int16_t direction, amount;
KeyboardScrollAction::KeyboardScrollActionType scrollAction;
nsresult (NS_STDCALL nsISelectionController::*scroll)(bool); nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
} physicalBrowseCommands[] = { } physicalBrowseCommands[] = {
{ sMoveLeftString, nsISelectionController::MOVE_LEFT, 0, { sMoveLeftString, nsISelectionController::MOVE_LEFT, 0,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter }, &nsISelectionController::ScrollCharacter },
{ sMoveRightString, nsISelectionController::MOVE_RIGHT, 0, { sMoveRightString, nsISelectionController::MOVE_RIGHT, 0,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter }, &nsISelectionController::ScrollCharacter },
{ sMoveUpString, nsISelectionController::MOVE_UP, 0, { sMoveUpString, nsISelectionController::MOVE_UP, 0,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine }, &nsISelectionController::ScrollLine },
{ sMoveDownString, nsISelectionController::MOVE_DOWN, 0, { sMoveDownString, nsISelectionController::MOVE_DOWN, 0,
KeyboardScrollAction::eScrollLine,
&nsISelectionController::ScrollLine }, &nsISelectionController::ScrollLine },
{ sMoveLeft2String, nsISelectionController::MOVE_LEFT, 1, { sMoveLeft2String, nsISelectionController::MOVE_LEFT, 1,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter }, &nsISelectionController::ScrollCharacter },
{ sMoveRight2String, nsISelectionController::MOVE_RIGHT, 1, { sMoveRight2String, nsISelectionController::MOVE_RIGHT, 1,
KeyboardScrollAction::eScrollCharacter,
&nsISelectionController::ScrollCharacter }, &nsISelectionController::ScrollCharacter },
{ sMoveUp2String, nsISelectionController::MOVE_UP, 1, { sMoveUp2String, nsISelectionController::MOVE_UP, 1,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll }, &nsISelectionController::CompleteScroll },
{ sMoveDown2String, nsISelectionController::MOVE_DOWN, 1, { sMoveDown2String, nsISelectionController::MOVE_DOWN, 1,
KeyboardScrollAction::eScrollComplete,
&nsISelectionController::CompleteScroll }, &nsISelectionController::CompleteScroll },
}; };
@ -1262,3 +1284,36 @@ nsWindowCommandRegistration::RegisterWindowCommands(
return rv; 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" #include "nscore.h"
namespace mozilla {
namespace layers {
struct KeyboardScrollAction;
} // namespace layers
} // namespace mozilla
class nsIControllerCommandTable; class nsIControllerCommandTable;
class nsWindowCommandRegistration class nsWindowCommandRegistration
@ -17,6 +23,22 @@ public:
static nsresult RegisterWindowCommands(nsIControllerCommandTable *ccm); 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 // XXX find a better home for these
#define NS_WINDOWCONTROLLER_CID \ #define NS_WINDOWCONTROLLER_CID \

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

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

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

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

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

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

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

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

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

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

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

@ -130,8 +130,6 @@ skip-if = (os == 'mac' && os_version == '10.6')
# application crashed [@ mozilla::gl::GLContext::AfterGLCall] # application crashed [@ mozilla::gl::GLContext::AfterGLCall]
skip-if = (os == 'android') || (os == 'win') 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] [generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win') fail-if = (os == 'mac') || (os == 'win')
[generated/test_conformance__extensions__oes-texture-half-float.html] [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 bool
EventListenerManager::HasApzAwareListeners() EventListenerManager::HasApzAwareListeners()
{ {

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

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

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

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

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

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

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

@ -99,6 +99,10 @@ public:
// Called from AsyncEventDispatcher to notify it is running. // Called from AsyncEventDispatcher to notify it is running.
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {} 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; virtual bool IsApzAware() const;
protected: protected:

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

@ -859,6 +859,17 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
uint32_t maxTouchPoints = 0; uint32_t maxTouchPoints = 0;
DimensionInfo dimensionInfo; 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) { if (aIframeMoz) {
MOZ_ASSERT(aTabOpener); MOZ_ASSERT(aTabOpener);
nsAutoCString url; nsAutoCString url;
@ -871,10 +882,11 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
url.SetIsVoid(true); 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), newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame, NS_ConvertUTF8toUTF16(url),
name, NS_ConvertUTF8toUTF16(features), name, NS_ConvertUTF8toUTF16(features));
aWindowIsNew, &textureFactoryIdentifier,
&layersId, &compositorOptions, &maxTouchPoints);
} else { } else {
nsAutoCString baseURIString; nsAutoCString baseURIString;
float fullZoom; float fullZoom;
@ -883,30 +895,98 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
return rv; return rv;
} }
if (!SendCreateWindow(aTabOpener, newChild, renderFrame, windowCreated =
SendCreateWindow(aTabOpener, newChild, renderFrame,
aChromeFlags, aCalledFromJS, aPositionSpecified, aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, aSizeSpecified,
features, features,
baseURIString, baseURIString,
fullZoom, fullZoom);
&rv,
aWindowIsNew,
&frameScripts,
&urlToLoad,
&textureFactoryIdentifier,
&layersId,
&compositorOptions,
&maxTouchPoints,
&dimensionInfo)) {
PRenderFrameChild::Send__delete__(renderFrame);
return NS_ERROR_NOT_AVAILABLE;
} }
// 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)) { if (NS_FAILED(rv)) {
PRenderFrameChild::Send__delete__(renderFrame); PRenderFrameChild::Send__delete__(renderFrame);
return rv; return rv;
} }
}
if (!*aWindowIsNew) { if (!*aWindowIsNew) {
PRenderFrameChild::Send__delete__(renderFrame); PRenderFrameChild::Send__delete__(renderFrame);
return NS_ERROR_ABORT; return NS_ERROR_ABORT;

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

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

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

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

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

@ -22,6 +22,8 @@ using CSSRect from "Units.h";
using CSSSize from "Units.h"; using CSSSize from "Units.h";
using mozilla::LayoutDeviceIntPoint from "Units.h"; using mozilla::LayoutDeviceIntPoint from "Units.h";
using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.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 mozilla {
namespace dom { namespace dom {
@ -96,5 +98,27 @@ struct DimensionInfo
LayoutDeviceIntPoint chromeDisp; 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 dom
} // namespace mozilla } // namespace mozilla

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

@ -149,11 +149,6 @@ parent:
async PPaymentRequest(); 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 * 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. * 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. * @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) nsString aURL, nsString aName, nsString aFeatures)
returns (bool windowOpened, returns (CreatedWindowInfo window);
TextureFactoryIdentifier textureFactoryIdentifier,
uint64_t layersId,
CompositorOptions compositorOptions,
uint32_t maxTouchPoints);
/** /**
* Tells the containing widget whether the given input block results in a * Tells the containing widget whether the given input block results in a
@ -898,6 +889,12 @@ child:
*/ */
async SetOriginAttributes(OriginAttributes aOriginAttributes); 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! * FIXME: write protocol!

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

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

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

@ -407,6 +407,11 @@ TabChild::TabChild(nsIContentChild* aManager,
#if defined(ACCESSIBILITY) #if defined(ACCESSIBILITY)
, mTopLevelDocAccessibleChild(nullptr) , mTopLevelDocAccessibleChild(nullptr)
#endif #endif
, mPendingDocShellIsActive(false)
, mPendingDocShellPreserveLayers(false)
, mPendingDocShellReceivedMessage(false)
, mPendingDocShellBlockers(0)
, mWidgetNativeData(0)
{ {
nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this))); // for capture by the lambda nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this))); // for capture by the lambda
mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId, mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
@ -2362,20 +2367,26 @@ TabChild::RecvDestroy()
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult void
TabChild::RecvSetDocShellIsActive(const bool& aIsActive, TabChild::AddPendingDocShellBlocker()
const bool& aPreserveLayers,
const uint64_t& aLayerObserverEpoch)
{ {
// Since SetDocShellIsActive requests come in from both the hang monitor mPendingDocShellBlockers++;
// 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;
void
TabChild::RemovePendingDocShellBlocker()
{
mPendingDocShellBlockers--;
if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
mPendingDocShellReceivedMessage = false;
InternalSetDocShellIsActive(mPendingDocShellIsActive,
mPendingDocShellPreserveLayers);
}
}
void
TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
{
auto clearForcePaint = MakeScopeExit([&] { auto clearForcePaint = MakeScopeExit([&] {
// We might force a paint, or we might already have painted and this is a // 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 // 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 // We send the current layer observer epoch to the compositor so that
// TabParent knows whether a layer update notification corresponds to the // TabParent knows whether a layer update notification corresponds to the
// latest SetDocShellIsActive request that was made. // latest SetDocShellIsActive request that was made.
mPuppetWidget->GetLayerManager()->SetLayerObserverEpoch(aLayerObserverEpoch); mPuppetWidget->GetLayerManager()->SetLayerObserverEpoch(mLayerObserverEpoch);
} }
// docshell is consider prerendered only if not active yet // 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 // notification to fire in the parent (so that it knows that the child has
// updated its epoch). ForcePaintNoOp does that. // updated its epoch). ForcePaintNoOp does that.
if (IPCOpen()) { if (IPCOpen()) {
Unused << SendForcePaintNoOp(aLayerObserverEpoch); Unused << SendForcePaintNoOp(mLayerObserverEpoch);
return IPC_OK(); return;
} }
} }
@ -2457,7 +2468,33 @@ TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
} else if (!aPreserveLayers) { } else if (!aPreserveLayers) {
MakeHidden(); 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(); return IPC_OK();
} }
@ -3175,6 +3212,13 @@ TabChild::RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes)
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
TabChild::RecvSetWidgetNativeData(const WindowsHandle& aWidgetNativeData)
{
mWidgetNativeData = aWidgetNativeData;
return IPC_OK();
}
mozilla::plugins::PPluginWidgetChild* mozilla::plugins::PPluginWidgetChild*
TabChild::AllocPPluginWidgetChild() TabChild::AllocPPluginWidgetChild()
{ {

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -12,6 +12,7 @@
#include "nsXBLPrototypeBinding.h" #include "nsXBLPrototypeBinding.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
#include "nsGlobalWindowCommands.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIAtom.h" #include "nsIAtom.h"
#include "nsIDOMKeyEvent.h" #include "nsIDOMKeyEvent.h"
@ -46,13 +47,16 @@
#include "mozilla/BasicEvents.h" #include "mozilla/BasicEvents.h"
#include "mozilla/JSEventHandler.h" #include "mozilla/JSEventHandler.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/EventHandlerBinding.h" #include "mozilla/dom/EventHandlerBinding.h"
#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ScriptSettings.h"
#include "mozilla/layers/KeyboardMap.h"
#include "xpcpublic.h" #include "xpcpublic.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::layers;
uint32_t nsXBLPrototypeHandler::gRefCnt = 0; uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
@ -136,6 +140,66 @@ nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLPrototypeHandler, this, mNextHandler); 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> already_AddRefed<nsIContent>
nsXBLPrototypeHandler::GetHandlerElement() nsXBLPrototypeHandler::GetHandlerElement()
{ {
@ -539,6 +603,54 @@ nsXBLPrototypeHandler::DispatchXULKeyCommand(nsIDOMEvent* aEvent)
return NS_OK; 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> already_AddRefed<nsIAtom>
nsXBLPrototypeHandler::GetEventName() nsXBLPrototypeHandler::GetEventName()
{ {

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

@ -7,6 +7,7 @@
#ifndef nsXBLPrototypeHandler_h__ #ifndef nsXBLPrototypeHandler_h__
#define nsXBLPrototypeHandler_h__ #define nsXBLPrototypeHandler_h__
#include "mozilla/EventForwards.h"
#include "nsIAtom.h" #include "nsIAtom.h"
#include "nsString.h" #include "nsString.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -27,10 +28,18 @@ class nsIObjectOutputStream;
class nsXBLPrototypeBinding; class nsXBLPrototypeBinding;
namespace mozilla { namespace mozilla {
struct IgnoreModifierState;
namespace dom { namespace dom {
class AutoJSAPI; class AutoJSAPI;
class EventTarget; class EventTarget;
} // namespace dom } // namespace dom
namespace layers {
class KeyboardShortcut;
} // namespace layers
} // namespace mozilla } // namespace mozilla
#define NS_HANDLER_TYPE_XBL_JS (1 << 0) #define NS_HANDLER_TYPE_XBL_JS (1 << 0)
@ -46,29 +55,11 @@ class EventTarget;
#define NS_PHASE_TARGET 2 #define NS_PHASE_TARGET 2
#define NS_PHASE_BUBBLING 3 #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 class nsXBLPrototypeHandler
{ {
typedef mozilla::dom::IgnoreModifierState IgnoreModifierState; typedef mozilla::IgnoreModifierState IgnoreModifierState;
typedef mozilla::layers::KeyboardShortcut KeyboardShortcut;
typedef mozilla::Modifiers Modifiers;
public: public:
// This constructor is used by XBL handlers (both the JS and command shorthand variety) // This constructor is used by XBL handlers (both the JS and command shorthand variety)
@ -90,6 +81,17 @@ public:
~nsXBLPrototypeHandler(); ~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 bool EventTypeEquals(nsIAtom* aEventType) const
{ {
return mEventName == aEventType; return mEventName == aEventType;
@ -186,6 +188,10 @@ protected:
nsresult DispatchXULKeyCommand(nsIDOMEvent* aEvent); nsresult DispatchXULKeyCommand(nsIDOMEvent* aEvent);
nsresult EnsureEventHandler(mozilla::dom::AutoJSAPI& jsapi, nsIAtom* aName, nsresult EnsureEventHandler(mozilla::dom::AutoJSAPI& jsapi, nsIAtom* aName,
JS::MutableHandle<JSObject*> aHandler); JS::MutableHandle<JSObject*> aHandler);
Modifiers GetModifiers() const;
Modifiers GetModifiersMask() const;
static int32_t KeyToMask(int32_t key); static int32_t KeyToMask(int32_t key);
static int32_t AccelKeyMask(); static int32_t AccelKeyMask();

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

@ -25,17 +25,21 @@
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "mozilla/EventListenerManager.h" #include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h" #include "mozilla/EventStateManager.h"
#include "mozilla/Move.h"
#include "nsISelectionController.h" #include "nsISelectionController.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" #include "mozilla/dom/Event.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsIHTMLEditor.h" #include "nsIHTMLEditor.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::layers;
class nsXBLSpecialDocInfo : public nsIObserver class nsXBLSpecialDocInfo : public nsIObserver
{ {
@ -146,9 +150,18 @@ nsXBLSpecialDocInfo::GetAllHandlers(const char* aType,
} }
// Init statics // Init statics
nsXBLSpecialDocInfo* nsXBLWindowKeyHandler::sXBLSpecialDocInfo = nullptr; static StaticRefPtr<nsXBLSpecialDocInfo> sXBLSpecialDocInfo;
uint32_t nsXBLWindowKeyHandler::sRefCnt = 0; uint32_t nsXBLWindowKeyHandler::sRefCnt = 0;
/* static */ void
nsXBLWindowKeyHandler::EnsureSpecialDocInfo()
{
if (!sXBLSpecialDocInfo) {
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
}
sXBLSpecialDocInfo->LoadDocInfo();
}
nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement, nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement,
EventTarget* aTarget) EventTarget* aTarget)
: mTarget(aTarget), : mTarget(aTarget),
@ -167,7 +180,7 @@ nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
--sRefCnt; --sRefCnt;
if (!sRefCnt) { if (!sRefCnt) {
NS_IF_RELEASE(sXBLSpecialDocInfo); sXBLSpecialDocInfo = nullptr;
} }
} }
@ -228,11 +241,7 @@ nsXBLWindowKeyHandler::EnsureHandlers()
nsCOMPtr<nsIContent> content(do_QueryInterface(el)); nsCOMPtr<nsIContent> content(do_QueryInterface(el));
BuildHandlerChain(content, &mHandler); BuildHandlerChain(content, &mHandler);
} else { // We are an XBL file of handlers. } else { // We are an XBL file of handlers.
if (!sXBLSpecialDocInfo) { EnsureSpecialDocInfo();
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
NS_ADDREF(sXBLSpecialDocInfo);
}
sXBLSpecialDocInfo->LoadDocInfo();
// Now determine which handlers we should be using. // Now determine which handlers we should be using.
if (IsHTMLEditableFieldFocused()) { if (IsHTMLEditableFieldFocused()) {
@ -397,6 +406,41 @@ nsXBLWindowKeyHandler::RemoveKeyboardEventListenersFrom(
TrustedEventsAtSystemGroupBubble()); 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* nsIAtom*
nsXBLWindowKeyHandler::ConvertEventToDOMEventType( nsXBLWindowKeyHandler::ConvertEventToDOMEventType(
const WidgetKeyboardEvent& aWidgetKeyboardEvent) const const WidgetKeyboardEvent& aWidgetKeyboardEvent) const

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

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

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

@ -197,6 +197,18 @@ struct TextureFactoryIdentifier
, mUsingAdvancedLayers(false) , mUsingAdvancedLayers(false)
, mSyncHandle(aSyncHandle) , 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; 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. // The scroll frame's scroll-snap-type.
// One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}. // One of NS_STYLE_SCROLL_SNAP_{NONE, MANDATORY, PROXIMITY}.
uint8_t mScrollSnapTypeX; uint8_t mScrollSnapTypeX;

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

@ -2102,6 +2102,15 @@ Layer::RemoveUserData(void* aKey)
return d; 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 void
PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{ {

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

@ -97,6 +97,7 @@ class ReadbackLayer;
class ReadbackProcessor; class ReadbackProcessor;
class RefLayer; class RefLayer;
class HostLayer; class HostLayer;
class FocusTarget;
class KnowsCompositor; class KnowsCompositor;
class ShadowableLayer; class ShadowableLayer;
class ShadowLayerForwarder; class ShadowLayerForwarder;
@ -599,6 +600,11 @@ public:
*/ */
virtual void SetIsFirstPaint() {} 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 * Make sure that the previous transaction has been entirely
* completed. * completed.
@ -844,6 +850,11 @@ public:
*/ */
LayerManager* Manager() { return mManager; } LayerManager* Manager() { return mManager; }
/**
* This should only be called when changing layer managers from HostLayers.
*/
void SetManager(LayerManager* aManager, HostLayer* aSelf);
enum { enum {
/** /**
* If this is set, the caller is promising that by the end of this * 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/EventStateManager.h" // for WheelPrefs
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc #include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc
#include "mozilla/MouseEvents.h" // for WidgetMouseEvent #include "mozilla/MouseEvents.h" // for WidgetMouseEvent
#include "mozilla/TextEvents.h" // for WidgetKeyboardEvent
#include "mozilla/TouchEvents.h" // for WidgetTouchEvent #include "mozilla/TouchEvents.h" // for WidgetTouchEvent
namespace mozilla { namespace mozilla {
@ -69,11 +70,12 @@ IAPZCTreeManager::ReceiveInputEvent(
mouseEvent.mRefPoint.x = input.mOrigin.x; mouseEvent.mRefPoint.x = input.mOrigin.x;
mouseEvent.mRefPoint.y = input.mOrigin.y; mouseEvent.mRefPoint.y = input.mOrigin.y;
mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
mouseEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
return status; return status;
} }
TransformEventRefPoint(&mouseEvent.mRefPoint, aOutTargetGuid); ProcessUnhandledEvent(&mouseEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
} }
case eTouchEventClass: { case eTouchEventClass: {
@ -92,6 +94,7 @@ IAPZCTreeManager::ReceiveInputEvent(
touchInput.mTouches[i].ToNewDOMTouch(); touchInput.mTouches[i].ToNewDOMTouch();
} }
touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ; touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
touchEvent.mFocusSequenceNumber = touchInput.mFocusSequenceNumber;
return result; return result;
} }
@ -133,18 +136,30 @@ IAPZCTreeManager::ReceiveInputEvent(
wheelEvent.mRefPoint.x = input.mOrigin.x; wheelEvent.mRefPoint.x = input.mOrigin.x;
wheelEvent.mRefPoint.y = input.mOrigin.y; wheelEvent.mRefPoint.y = input.mOrigin.y;
wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
return status; return status;
} }
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage); UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid); ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore; 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: { default: {
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage); UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid); ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid, &aEvent.mFocusSequenceNumber);
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
} }

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

@ -21,6 +21,8 @@ class InputData;
namespace layers { namespace layers {
class KeyboardMap;
enum AllowedTouchBehavior { enum AllowedTouchBehavior {
NONE = 0, NONE = 0,
VERTICAL_PAN = 1 << 0, VERTICAL_PAN = 1 << 0,
@ -104,6 +106,11 @@ public:
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId); 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 * 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 * 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) // Methods to help process WidgetInputEvents (or manage conversion to/from InputData)
virtual void TransformEventRefPoint( virtual void ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint, LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) = 0; ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) = 0;
virtual void UpdateWheelTransaction( virtual void UpdateWheelTransaction(
LayoutDeviceIntPoint aRefPoint, LayoutDeviceIntPoint aRefPoint,

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

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stack> #include <stack>
#include <unordered_set>
#include "APZCTreeManager.h" #include "APZCTreeManager.h"
#include "AsyncPanZoomController.h" #include "AsyncPanZoomController.h"
#include "Compositor.h" // for Compositor #include "Compositor.h" // for Compositor
@ -21,6 +22,7 @@
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
#include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics #include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
#include "mozilla/layers/FocusState.h" // for FocusState
#include "mozilla/layers/LayerMetricsWrapper.h" #include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/WebRenderScrollDataWrapper.h" #include "mozilla/layers/WebRenderScrollDataWrapper.h"
#include "mozilla/MouseEvents.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 // This is initialized with all nodes in the old tree, and nodes are removed
// from it as we reuse them in the new tree. // from it as we reuse them in the new tree.
nsTArray<RefPtr<HitTestingTreeNode>> mNodesToDestroy; 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 // 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 // to facilitate re-using the same APZC for different layers that scroll
@ -158,6 +165,35 @@ APZCTreeManager::CheckerboardFlushObserver::Observe(nsISupports* aSubject,
return NS_OK; 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 /*static*/ const ScreenMargin
APZCTreeManager::CalculatePendingDisplayPort( APZCTreeManager::CalculatePendingDisplayPort(
@ -263,6 +299,7 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
{ {
state.mNodesToDestroy.AppendElement(aNode); state.mNodesToDestroy.AppendElement(aNode);
}); });
state.mLayersIdsToDestroy = mFocusState.GetFocusTargetLayerIds();
mRootNode = nullptr; mRootNode = nullptr;
if (aRoot) { if (aRoot) {
@ -273,6 +310,8 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
uint64_t layersId = aRootLayerTreeId; uint64_t layersId = aRootLayerTreeId;
ancestorTransforms.push(Matrix4x4()); ancestorTransforms.push(Matrix4x4());
state.mLayersIdsToDestroy.erase(aRootLayerTreeId);
mApzcTreeLog << "[start]\n"; mApzcTreeLog << "[start]\n";
mTreeLock.AssertCurrentThreadOwns(); mTreeLock.AssertCurrentThreadOwns();
@ -310,7 +349,15 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
MOZ_ASSERT(!node->GetFirstChild()); MOZ_ASSERT(!node->GetFirstChild());
parent = node; parent = node;
next = nullptr; 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)); indents.push(gfx::TreeAutoIndent(mApzcTreeLog));
}, },
[&](ScrollNode aLayerMetrics) [&](ScrollNode aLayerMetrics)
@ -335,6 +382,11 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
state.mNodesToDestroy[i]->Destroy(); 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 #if ENABLE_APZCTM_LOGGING
// Make the hit-test tree line up with the layer dump // Make the hit-test tree line up with the layer dump
printf_stderr("APZCTreeManager (%p)\n", this); printf_stderr("APZCTreeManager (%p)\n", this);
@ -342,6 +394,20 @@ APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
#endif #endif
} }
void
APZCTreeManager::UpdateFocusState(uint64_t aRootLayerTreeId,
uint64_t aOriginatingLayersId,
const FocusTarget& aFocusTarget)
{
if (!gfxPrefs::APZKeyboardEnabled()) {
return;
}
mFocusState.Update(aRootLayerTreeId,
aOriginatingLayersId,
aFocusTarget);
}
void void
APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId, APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
Layer* aRoot, Layer* aRoot,
@ -868,6 +934,9 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
{ {
APZThreadUtils::AssertOnControllerThread(); APZThreadUtils::AssertOnControllerThread();
// Use a RAII class for updating the focus sequence number of this event
AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
MOZ_ASSERT(mToolbarAnimator); MOZ_ASSERT(mToolbarAnimator);
ScreenPoint scrollOffset; ScreenPoint scrollOffset;
@ -1035,7 +1104,6 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
FlushRepaintsToClearScreenToGeckoTransform(); FlushRepaintsToClearScreenToGeckoTransform();
ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput(); ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
wheelInput.mHandledByAPZ = WillHandleInput(wheelInput); wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
if (!wheelInput.mHandledByAPZ) { if (!wheelInput.mHandledByAPZ) {
return result; return result;
@ -1176,6 +1244,91 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
apzc->GetGuid(aOutTargetGuid); apzc->GetGuid(aOutTargetGuid);
tapInput.mPoint = *untransformedPoint; 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; break;
} case SENTINEL_INPUT: { } case SENTINEL_INPUT: {
MOZ_ASSERT_UNREACHABLE("Invalid InputType."); MOZ_ASSERT_UNREACHABLE("Invalid InputType.");
@ -1404,8 +1557,9 @@ APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
} }
void void
APZCTreeManager::TransformEventRefPoint(LayoutDeviceIntPoint* aRefPoint, APZCTreeManager::ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber)
{ {
// Transform the aRefPoint. // Transform the aRefPoint.
// If the event hits an overscrolled APZC, instruct the caller to ignore it. // 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); ViewAs<LayoutDevicePixel>(*untransformedRefPoint, LDIsScreen);
} }
} }
// Update the focus sequence number and attach it to the event
mFocusState.ReceiveFocusChangingEvent();
*aOutFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
} }
void void
@ -1437,6 +1595,12 @@ APZCTreeManager::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
} }
} }
void
APZCTreeManager::SetKeyboardMap(const KeyboardMap& aKeyboardMap)
{
mKeyboardMap = aKeyboardMap;
}
void void
APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid, APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
const CSSRect& aRect, const CSSRect& aRect,

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

@ -14,6 +14,8 @@
#include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/layers/TouchCounter.h"// for TouchCounter #include "mozilla/layers/TouchCounter.h"// for TouchCounter
#include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager #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/Mutex.h" // for Mutex
#include "mozilla/RefPtr.h" // for RefPtr #include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for mozilla::TimeStamp #include "mozilla/TimeStamp.h" // for mozilla::TimeStamp
@ -40,6 +42,7 @@ class APZCTreeManagerParent;
class CompositorBridgeParent; class CompositorBridgeParent;
class OverscrollHandoffChain; class OverscrollHandoffChain;
struct OverscrollHandoffState; struct OverscrollHandoffState;
class FocusTarget;
struct FlingHandoffState; struct FlingHandoffState;
struct ScrollableLayerGuidHash; struct ScrollableLayerGuidHash;
class LayerMetricsWrapper; class LayerMetricsWrapper;
@ -111,6 +114,19 @@ public:
*/ */
static void InitializeGlobalState(); 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. * 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 * Preserve nodes and APZC instances where possible, but retire those whose
@ -211,6 +227,11 @@ public:
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override; 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 * 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 * 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) // Methods to help process WidgetInputEvents (or manage conversion to/from InputData)
void TransformEventRefPoint( void ProcessUnhandledEvent(
LayoutDeviceIntPoint* aRefPoint, LayoutDeviceIntPoint* aRefPoint,
ScrollableLayerGuid* aOutTargetGuid) override; ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) override;
void UpdateWheelTransaction( void UpdateWheelTransaction(
LayoutDeviceIntPoint aRefPoint, LayoutDeviceIntPoint aRefPoint,
@ -550,6 +572,14 @@ private:
/* Holds the zoom constraints for scrollable layers, as determined by the /* Holds the zoom constraints for scrollable layers, as determined by the
* the main-thread gecko code. */ * the main-thread gecko code. */
std::unordered_map<ScrollableLayerGuid, ZoomConstraints, ScrollableLayerGuidHash> mZoomConstraints; 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 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 * 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 * touch events delivered to the same initial APZC. This will only ever be touched on the

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

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

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

@ -77,6 +77,7 @@
#include "SharedMemoryBasic.h" // for SharedMemoryBasic #include "SharedMemoryBasic.h" // for SharedMemoryBasic
#include "ScrollSnap.h" // for ScrollSnapUtils #include "ScrollSnap.h" // for ScrollSnapUtils
#include "WheelScrollAnimation.h" #include "WheelScrollAnimation.h"
#include "KeyboardScrollAnimation.h"
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
#include "AndroidAPZ.h" #include "AndroidAPZ.h"
#include "mozilla/layers/AndroidDynamicToolbarAnimator.h" #include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
@ -1005,6 +1006,11 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
rv = HandleGestureEvent(tapInput); rv = HandleGestureEvent(tapInput);
break; break;
} }
case KEYBOARD_INPUT: {
KeyboardInput keyInput = aEvent.AsKeyboardInput();
rv = OnKeyboard(keyInput);
break;
}
case SENTINEL_INPUT: { case SENTINEL_INPUT: {
MOZ_ASSERT_UNREACHABLE("Invalid value"); MOZ_ASSERT_UNREACHABLE("Invalid value");
break; break;
@ -1067,6 +1073,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
case SMOOTH_SCROLL: case SMOOTH_SCROLL:
case OVERSCROLL_ANIMATION: case OVERSCROLL_ANIMATION:
case WHEEL_SCROLL: case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case PAN_MOMENTUM: case PAN_MOMENTUM:
MOZ_ASSERT(GetCurrentTouchBlock()); MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll); GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
@ -1142,6 +1149,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
case WHEEL_SCROLL: case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case OVERSCROLL_ANIMATION: case OVERSCROLL_ANIMATION:
// Should not receive a touch-move in the OVERSCROLL_ANIMATION state // Should not receive a touch-move in the OVERSCROLL_ANIMATION state
// as touch blocks that begin in an overscrolled state cancel the // as touch blocks that begin in an overscrolled state cancel the
@ -1222,6 +1230,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
case WHEEL_SCROLL: case WHEEL_SCROLL:
case KEYBOARD_SCROLL:
case OVERSCROLL_ANIMATION: case OVERSCROLL_ANIMATION:
// Should not receive a touch-end in the OVERSCROLL_ANIMATION state // Should not receive a touch-end in the OVERSCROLL_ANIMATION state
// as touch blocks that begin in an overscrolled state cancel the // as touch blocks that begin in an overscrolled state cancel the
@ -1656,6 +1665,152 @@ AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent) cons
return delta; 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. // Return whether or not the underlying layer can be scrolled on either axis.
bool bool
AsyncPanZoomController::CanScroll(const InputData& aEvent) const AsyncPanZoomController::CanScroll(const InputData& aEvent) const
@ -1822,6 +1977,8 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
startPosition = mAnimation->AsWheelScrollAnimation()->GetDestination(); startPosition = mAnimation->AsWheelScrollAnimation()->GetDestination();
} else if (mState == SMOOTH_SCROLL) { } else if (mState == SMOOTH_SCROLL) {
startPosition = mAnimation->AsSmoothScrollAnimation()->GetDestination(); startPosition = mAnimation->AsSmoothScrollAnimation()->GetDestination();
} else if (mState == KEYBOARD_SCROLL) {
startPosition = mAnimation->AsKeyboardScrollAnimation()->GetDestination();
} }
if (MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition)) { if (MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition)) {
// If we're scroll snapping, use a smooth scroll animation to get // If we're scroll snapping, use a smooth scroll animation to get
@ -1845,12 +2002,13 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
nsPoint deltaInAppUnits = nsPoint deltaInAppUnits =
CSSPoint::ToAppUnits(delta / mFrameMetrics.GetZoom()); CSSPoint::ToAppUnits(delta / mFrameMetrics.GetZoom());
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to // 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 = nsPoint velocity =
CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), mY.GetVelocity())) * 1000.0f; CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(), mY.GetVelocity())) * 1000.0f;
WheelScrollAnimation* animation = mAnimation->AsWheelScrollAnimation(); 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; break;
} }
@ -2608,7 +2766,8 @@ void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination) {
SetState(SMOOTH_SCROLL); SetState(SMOOTH_SCROLL);
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()); nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to // 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(), nsPoint initialVelocity = CSSPoint::ToAppUnits(CSSPoint(mX.GetVelocity(),
mY.GetVelocity())) * 1000.0f; mY.GetVelocity())) * 1000.0f;
nsPoint destination = CSSPoint::ToAppUnits(aDestination); nsPoint destination = CSSPoint::ToAppUnits(aDestination);

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

@ -61,6 +61,7 @@ class OverscrollEffectBase;
class WidgetOverscrollEffect; class WidgetOverscrollEffect;
class GenericOverscrollEffect; class GenericOverscrollEffect;
class AndroidSpecificState; class AndroidSpecificState;
struct KeyboardScrollAction;
// Base class for grouping platform-specific APZC state variables. // Base class for grouping platform-specific APZC state variables.
class PlatformSpecificStateBase { class PlatformSpecificStateBase {
@ -339,6 +340,13 @@ public:
*/ */
bool HasScrollgrab() const { return mScrollMetadata.GetHasScrollgrab(); } 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). * Returns whether this APZC has room to be panned (in any direction).
*/ */
@ -482,6 +490,13 @@ protected:
ParentLayerPoint GetScrollWheelDelta(const ScrollWheelInput& aEvent) const; 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. * Helper methods for long press gestures.
*/ */
@ -839,7 +854,8 @@ protected:
the finger is lifted. */ the finger is lifted. */
SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by
CSSOM-View smooth scroll-behavior */ 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 // This is in theory protected by |mMonitor|; that is, it should be held whenever
@ -936,7 +952,9 @@ private:
friend class GenericFlingAnimation; friend class GenericFlingAnimation;
friend class OverscrollAnimation; friend class OverscrollAnimation;
friend class SmoothScrollAnimation; friend class SmoothScrollAnimation;
friend class GenericScrollAnimation;
friend class WheelScrollAnimation; friend class WheelScrollAnimation;
friend class KeyboardScrollAnimation;
friend class GenericOverscrollEffect; friend class GenericOverscrollEffect;
friend class WidgetOverscrollEffect; 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(); return mTouchCounter.GetActiveTouchCount();
} }
KeyboardBlockState::KeyboardBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc)
: InputBlockState(aTargetApzc, true)
{
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

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

@ -27,6 +27,7 @@ class TouchBlockState;
class WheelBlockState; class WheelBlockState;
class DragBlockState; class DragBlockState;
class PanGestureBlockState; class PanGestureBlockState;
class KeyboardBlockState;
/** /**
* A base class that stores state common to various input blocks. * A base class that stores state common to various input blocks.
@ -68,6 +69,9 @@ public:
virtual PanGestureBlockState* AsPanGestureBlock() { virtual PanGestureBlockState* AsPanGestureBlock() {
return nullptr; return nullptr;
} }
virtual KeyboardBlockState* AsKeyboardBlock() {
return nullptr;
}
virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc, virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
TargetConfirmationState aState, TargetConfirmationState aState,
@ -486,6 +490,23 @@ private:
TouchCounter& mTouchCounter; 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 layers
} // namespace mozilla } // namespace mozilla

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

@ -56,6 +56,14 @@ InputQueue::ReceiveInputEvent(const RefPtr<AsyncPanZoomController>& aTarget,
return ReceiveMouseInput(aTarget, aTargetConfirmed, event, aOutInputBlockId); 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: default:
// The return value for non-touch input is only used by tests, so just pass // 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. // 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; 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 static bool
CanScrollTargetHorizontally(const PanGestureInput& aInitialEvent, CanScrollTargetHorizontally(const PanGestureInput& aInitialEvent,
PanGestureBlockState* aBlock) PanGestureBlockState* aBlock)
@ -461,6 +502,13 @@ InputQueue::GetCurrentPanGestureBlock() const
return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get(); return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get();
} }
KeyboardBlockState*
InputQueue::GetCurrentKeyboardBlock() const
{
InputBlockState* block = GetCurrentBlock();
return block ? block->AsKeyboardBlock() : mActiveKeyboardBlock.get();
}
WheelBlockState* WheelBlockState*
InputQueue::GetActiveWheelTransaction() const InputQueue::GetActiveWheelTransaction() const
{ {

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

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

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

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

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

@ -16,83 +16,11 @@ namespace layers {
WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc, WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc,
const nsPoint& aInitialPosition, const nsPoint& aInitialPosition,
ScrollWheelInput::ScrollDeltaType aDeltaType) ScrollWheelInput::ScrollDeltaType aDeltaType)
: AsyncScrollBase(aInitialPosition) : GenericScrollAnimation(aApzc, aInitialPosition)
, mApzc(aApzc)
, mFinalDestination(aInitialPosition)
, mDeltaType(aDeltaType)
{ {
} mForceVerticalOverscroll = !mApzc.mScrollMetadata.AllowVerticalScrollWithWheel();
void switch (aDeltaType) {
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) {
case ScrollWheelInput::SCROLLDELTA_PAGE: case ScrollWheelInput::SCROLLDELTA_PAGE:
mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000); mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mOriginMaxMS); 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 // The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0; mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
mIntervalRatio = std::max(1.0, mIntervalRatio); mIntervalRatio = std::max(1.0, mIntervalRatio);
InitializeHistory(aTime);
} }
} // namespace layers } // namespace layers

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

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

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

@ -51,6 +51,16 @@ enum class ScrollInputMethod {
// Autoscrolling // Autoscrolling
MainThreadAutoscrolling, // 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. // 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 // They should only be added at the end, to preserve the numerical values
// of the existing enumerators. // of the existing enumerators.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -144,6 +144,33 @@ APZCTreeManagerParent::RecvReceiveScrollWheelInputEvent(
return IPC_OK(); 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 mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvZoomToRect( APZCTreeManagerParent::RecvZoomToRect(
const ScrollableLayerGuid& aGuid, const ScrollableLayerGuid& aGuid,
@ -299,13 +326,14 @@ APZCTreeManagerParent::RecvUpdateWheelTransaction(
} }
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
APZCTreeManagerParent::RecvTransformEventRefPoint( APZCTreeManagerParent::RecvProcessUnhandledEvent(
const LayoutDeviceIntPoint& aRefPoint, const LayoutDeviceIntPoint& aRefPoint,
LayoutDeviceIntPoint* aOutRefPoint, LayoutDeviceIntPoint* aOutRefPoint,
ScrollableLayerGuid* aOutTargetGuid) ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber)
{ {
LayoutDeviceIntPoint refPoint = aRefPoint; LayoutDeviceIntPoint refPoint = aRefPoint;
mTreeManager->TransformEventRefPoint(&refPoint, aOutTargetGuid); mTreeManager->ProcessUnhandledEvent(&refPoint, aOutTargetGuid, aOutFocusSequenceNumber);
*aOutRefPoint = refPoint; *aOutRefPoint = refPoint;
return IPC_OK(); return IPC_OK();

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

@ -78,6 +78,17 @@ public:
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId) override; 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 mozilla::ipc::IPCResult
RecvZoomToRect( RecvZoomToRect(
const ScrollableLayerGuid& aGuid, const ScrollableLayerGuid& aGuid,
@ -129,10 +140,11 @@ public:
const EventMessage& aEventMessage) override; const EventMessage& aEventMessage) override;
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
RecvTransformEventRefPoint( RecvProcessUnhandledEvent(
const LayoutDeviceIntPoint& aRefPoint, const LayoutDeviceIntPoint& aRefPoint,
LayoutDeviceIntPoint* aOutRefPoint, LayoutDeviceIntPoint* aOutRefPoint,
ScrollableLayerGuid* aOutTargetGuid) override; ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutFocusSequenceNumber) override;
void void
ActorDestroy(ActorDestroyReason aWhy) override { } ActorDestroy(ActorDestroyReason aWhy) override { }

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

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

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

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

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