зеркало из https://github.com/mozilla/gecko-dev.git
merge fx-team to mozilla-central a=merge
This commit is contained in:
Коммит
89dba842cb
|
@ -241,6 +241,7 @@ function setupPanelFrame(frame) {
|
|||
frame.setAttribute("flex", 1);
|
||||
frame.setAttribute("transparent", "transparent");
|
||||
frame.setAttribute("autocompleteenabled", true);
|
||||
frame.setAttribute("tooltip", "aHTMLTooltip");
|
||||
if (platform === "darwin") {
|
||||
frame.style.borderRadius = "6px";
|
||||
frame.style.padding = "1px";
|
||||
|
|
|
@ -274,9 +274,11 @@ ContentSearchUIController.prototype = {
|
|||
ctrlKey: aEvent.ctrlKey,
|
||||
metaKey: aEvent.metaKey,
|
||||
altKey: aEvent.altKey,
|
||||
button: aEvent.button,
|
||||
},
|
||||
};
|
||||
if ("button" in aEvent) {
|
||||
eventData.originalEvent.button = aEvent.button;
|
||||
}
|
||||
|
||||
if (this.suggestionAtIndex(this.selectedIndex)) {
|
||||
eventData.selection = {
|
||||
|
|
|
@ -223,6 +223,8 @@ var gSearchPane = {
|
|||
let newValue = !gEngineView._engineStore.engines[index].shown;
|
||||
gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
|
||||
newValue.toString());
|
||||
// Prevent page from scrolling on the space key.
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
else {
|
||||
let isMac = Services.appinfo.OS == "Darwin";
|
||||
|
|
|
@ -559,12 +559,16 @@ var gSyncPane = {
|
|||
replaceQueryString: true
|
||||
});
|
||||
});
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
openManageFirefoxAccount: function(event) {
|
||||
if (this.clickOrSpaceOrEnterPressed(event)) {
|
||||
this.manageFirefoxAccount();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -667,4 +671,3 @@ var gSyncPane = {
|
|||
textbox.value = value;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ support-files =
|
|||
[browser_bug795764_cachedisabled.js]
|
||||
[browser_bug1018066_resetScrollPosition.js]
|
||||
[browser_bug1020245_openPreferences_to_paneContent.js]
|
||||
[browser_bug1184989_prevent_scrolling_when_preferences_flipped.js]
|
||||
support-files =
|
||||
browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul
|
||||
[browser_change_app_handler.js]
|
||||
skip-if = os != "win" # This test tests the windows-specific app selection dialog, so can't run on non-Windows
|
||||
[browser_connection.js]
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
|
||||
add_task(function* () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
const tabURL = getRootDirectory(gTestPath) + "browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul";
|
||||
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: tabURL }, function* (browser) {
|
||||
let doc = browser.contentDocument;
|
||||
let container = doc.getElementById("container");
|
||||
|
||||
// Test button
|
||||
let button = doc.getElementById("button");
|
||||
button.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "button");
|
||||
|
||||
// Test checkbox
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
checkbox.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
ok(checkbox.checked, "Checkbox is checked");
|
||||
yield checkPageScrolling(container, "checkbox");
|
||||
|
||||
// Test listbox
|
||||
let listbox = doc.getElementById("listbox");
|
||||
let listitem = doc.getElementById("listitem");
|
||||
listbox.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
ok(listitem.selected, "Listitem is selected");
|
||||
yield checkPageScrolling(container, "listbox");
|
||||
|
||||
// Test radio
|
||||
let radiogroup = doc.getElementById("radiogroup");
|
||||
radiogroup.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "radio");
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:preferences#search" }, function* (browser) {
|
||||
let doc = browser.contentDocument;
|
||||
let container = doc.getElementsByClassName("main-content")[0];
|
||||
|
||||
// Test search
|
||||
let engineList = doc.getElementById("engineList");
|
||||
engineList.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
is(engineList.view.selection.currentIndex, 0, "Search engineList is selected");
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(container, "search engineList");
|
||||
});
|
||||
|
||||
// Test session restore
|
||||
const CRASH_URL = "about:mozilla";
|
||||
const CRASH_FAVICON = "chrome://branding/content/icon32.png";
|
||||
const CRASH_SHENTRY = {url: CRASH_URL};
|
||||
const CRASH_TAB = {entries: [CRASH_SHENTRY], image: CRASH_FAVICON};
|
||||
const CRASH_STATE = {windows: [{tabs: [CRASH_TAB]}]};
|
||||
|
||||
const TAB_URL = "about:sessionrestore";
|
||||
const TAB_FORMDATA = {url: TAB_URL, id: {sessionData: CRASH_STATE}};
|
||||
const TAB_SHENTRY = {url: TAB_URL};
|
||||
const TAB_STATE = {entries: [TAB_SHENTRY], formdata: TAB_FORMDATA};
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
// Fake a post-crash tab
|
||||
ss.setTabState(tab, JSON.stringify(TAB_STATE));
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
|
||||
// Make body scrollable
|
||||
doc.body.style.height = (doc.body.clientHeight + 100) + "px";
|
||||
|
||||
let tabList = doc.getElementById("tabList");
|
||||
tabList.focus();
|
||||
EventUtils.synthesizeKey(" ", {});
|
||||
yield checkPageScrolling(doc.documentElement, "session restore");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
|
||||
function checkPageScrolling(container, type) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
is(container.scrollTop, 0, "Page should not scroll when " + type + " flipped");
|
||||
resolve();
|
||||
}, 0);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
XUL Widget Test for Bug 1184989
|
||||
-->
|
||||
<page title="Bug 1184989 Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<vbox id="container" style="height: 200px; overflow: auto;">
|
||||
<vbox style="height: 500px;">
|
||||
<hbox>
|
||||
<button id="button" label="button" />
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<checkbox id="checkbox" label="checkbox" />
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 50px;">
|
||||
<listbox id="listbox">
|
||||
<listitem id="listitem" label="listitem" />
|
||||
<listitem label="listitem" />
|
||||
</listbox>
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<radiogroup id="radiogroup">
|
||||
<radio id="radio" label="radio" />
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
</page>
|
|
@ -205,6 +205,8 @@ function onListKeyDown(aEvent) {
|
|||
{
|
||||
case KeyEvent.DOM_VK_SPACE:
|
||||
toggleRowChecked(document.getElementById("tabList").currentIndex);
|
||||
// Prevent page from scrolling on the space key.
|
||||
aEvent.preventDefault();
|
||||
break;
|
||||
case KeyEvent.DOM_VK_RETURN:
|
||||
var ix = document.getElementById("tabList").currentIndex;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.5.413
|
||||
Current extension version is: 1.5.437
|
||||
|
|
|
@ -91,7 +91,8 @@ function initializeDefaultPreferences() {
|
|||
"disableFontFace": false,
|
||||
"disableTextLayer": false,
|
||||
"useOnlyCssZoom": false,
|
||||
"externalLinkTarget": 0
|
||||
"externalLinkTarget": 0,
|
||||
"renderInteractiveForms": false
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ var DEFAULT_PREFERENCES =
|
|||
"disableFontFace": false,
|
||||
"disableTextLayer": false,
|
||||
"useOnlyCssZoom": false,
|
||||
"externalLinkTarget": 0
|
||||
"externalLinkTarget": 0,
|
||||
"renderInteractiveForms": false
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
|
|||
// Use strict in our context only - users might not want it
|
||||
'use strict';
|
||||
|
||||
var pdfjsVersion = '1.5.413';
|
||||
var pdfjsBuild = '6bb95e3';
|
||||
var pdfjsVersion = '1.5.437';
|
||||
var pdfjsBuild = 'ca61ccc';
|
||||
|
||||
var pdfjsFilePath =
|
||||
typeof document !== 'undefined' && document.currentScript ?
|
||||
|
@ -1158,6 +1158,7 @@ function createPromiseCapability() {
|
|||
throw new Error('DOM Promise is not present');
|
||||
})();
|
||||
|
||||
|
||||
var StatTimer = (function StatTimerClosure() {
|
||||
function rpad(str, pad, length) {
|
||||
while (str.length < length) {
|
||||
|
@ -1938,6 +1939,8 @@ var getDefaultSetting = displayDOMUtils.getDefaultSetting;
|
|||
* @property {PageViewport} viewport
|
||||
* @property {IPDFLinkService} linkService
|
||||
* @property {DownloadManager} downloadManager
|
||||
* @property {string} imageResourcesPath
|
||||
* @property {boolean} renderInteractiveForms
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1962,6 +1965,12 @@ AnnotationElementFactory.prototype =
|
|||
return new TextAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.WIDGET:
|
||||
var fieldType = parameters.data.fieldType;
|
||||
|
||||
switch (fieldType) {
|
||||
case 'Tx':
|
||||
return new TextWidgetAnnotationElement(parameters);
|
||||
}
|
||||
return new WidgetAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.POPUP:
|
||||
|
@ -2002,6 +2011,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
|||
this.linkService = parameters.linkService;
|
||||
this.downloadManager = parameters.downloadManager;
|
||||
this.imageResourcesPath = parameters.imageResourcesPath;
|
||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||
|
||||
if (isRenderable) {
|
||||
this.container = this._createContainer();
|
||||
|
@ -2285,9 +2295,7 @@ var TextAnnotationElement = (function TextAnnotationElementClosure() {
|
|||
*/
|
||||
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
||||
function WidgetAnnotationElement(parameters) {
|
||||
var isRenderable = !parameters.data.hasAppearance &&
|
||||
!!parameters.data.fieldValue;
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
AnnotationElement.call(this, parameters, true);
|
||||
}
|
||||
|
||||
Util.inherit(WidgetAnnotationElement, AnnotationElement, {
|
||||
|
@ -2299,18 +2307,55 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
|||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render: function WidgetAnnotationElement_render() {
|
||||
var content = document.createElement('div');
|
||||
content.textContent = this.data.fieldValue;
|
||||
var textAlignment = this.data.textAlignment;
|
||||
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
|
||||
content.style.verticalAlign = 'middle';
|
||||
content.style.display = 'table-cell';
|
||||
// Show only the container for unsupported field types.
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
|
||||
var font = (this.data.fontRefName ?
|
||||
this.page.commonObjs.getData(this.data.fontRefName) : null);
|
||||
this._setTextStyle(content, font);
|
||||
return WidgetAnnotationElement;
|
||||
})();
|
||||
|
||||
this.container.appendChild(content);
|
||||
/**
|
||||
* @class
|
||||
* @alias TextWidgetAnnotationElement
|
||||
*/
|
||||
var TextWidgetAnnotationElement = (
|
||||
function TextWidgetAnnotationElementClosure() {
|
||||
function TextWidgetAnnotationElement(parameters) {
|
||||
WidgetAnnotationElement.call(this, parameters);
|
||||
}
|
||||
|
||||
Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, {
|
||||
/**
|
||||
* Render the text widget annotation's HTML element in the empty container.
|
||||
*
|
||||
* @public
|
||||
* @memberof TextWidgetAnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render: function TextWidgetAnnotationElement_render() {
|
||||
this.container.className = 'textWidgetAnnotation';
|
||||
|
||||
if (this.renderInteractiveForms) {
|
||||
var input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.value = this.data.fieldValue;
|
||||
|
||||
this.container.appendChild(input);
|
||||
} else {
|
||||
var content = document.createElement('div');
|
||||
content.textContent = this.data.fieldValue;
|
||||
var textAlignment = this.data.textAlignment;
|
||||
content.style.textAlign = ['left', 'center', 'right'][textAlignment];
|
||||
content.style.verticalAlign = 'middle';
|
||||
content.style.display = 'table-cell';
|
||||
|
||||
var font = (this.data.fontRefName ?
|
||||
this.page.commonObjs.getData(this.data.fontRefName) : null);
|
||||
this._setTextStyle(content, font);
|
||||
|
||||
this.container.appendChild(content);
|
||||
}
|
||||
return this.container;
|
||||
},
|
||||
|
||||
|
@ -2320,10 +2365,10 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
|||
* @private
|
||||
* @param {HTMLDivElement} element
|
||||
* @param {Object} font
|
||||
* @memberof WidgetAnnotationElement
|
||||
* @memberof TextWidgetAnnotationElement
|
||||
*/
|
||||
_setTextStyle:
|
||||
function WidgetAnnotationElement_setTextStyle(element, font) {
|
||||
function TextWidgetAnnotationElement_setTextStyle(element, font) {
|
||||
// TODO: This duplicates some of the logic in CanvasGraphics.setFont().
|
||||
var style = element.style;
|
||||
style.fontSize = this.data.fontSize + 'px';
|
||||
|
@ -2345,7 +2390,7 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
|||
}
|
||||
});
|
||||
|
||||
return WidgetAnnotationElement;
|
||||
return TextWidgetAnnotationElement;
|
||||
})();
|
||||
|
||||
/**
|
||||
|
@ -2737,6 +2782,7 @@ var FileAttachmentAnnotationElement = (
|
|||
* @property {PDFPage} page
|
||||
* @property {IPDFLinkService} linkService
|
||||
* @property {string} imageResourcesPath
|
||||
* @property {boolean} renderInteractiveForms
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -2769,7 +2815,8 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
|
|||
linkService: parameters.linkService,
|
||||
downloadManager: parameters.downloadManager,
|
||||
imageResourcesPath: parameters.imageResourcesPath ||
|
||||
getDefaultSetting('imageResourcesPath')
|
||||
getDefaultSetting('imageResourcesPath'),
|
||||
renderInteractiveForms: parameters.renderInteractiveForms || false,
|
||||
};
|
||||
var element = annotationElementFactory.create(properties);
|
||||
if (element.isRenderable) {
|
||||
|
@ -2830,6 +2877,8 @@ var getDefaultSetting = displayDOMUtils.getDefaultSetting;
|
|||
* initially be set to empty array.
|
||||
* @property {number} timeout - (optional) Delay in milliseconds before
|
||||
* rendering of the text runs occurs.
|
||||
* @property {boolean} enhanceTextSelection - (optional) Whether to turn on the
|
||||
* text selection enhancement.
|
||||
*/
|
||||
var renderTextLayer = (function renderTextLayerClosure() {
|
||||
var MAX_TEXT_DIVS_TO_RENDER = 100000;
|
||||
|
@ -2840,17 +2889,31 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
return !NonWhitespaceRegexp.test(str);
|
||||
}
|
||||
|
||||
function appendText(textDivs, viewport, geom, styles, bounds,
|
||||
enhanceTextSelection) {
|
||||
var style = styles[geom.fontName];
|
||||
function appendText(task, geom, styles) {
|
||||
// Initialize all used properties to keep the caches monomorphic.
|
||||
var textDiv = document.createElement('div');
|
||||
textDivs.push(textDiv);
|
||||
var textDivProperties = {
|
||||
angle: 0,
|
||||
canvasWidth: 0,
|
||||
isWhitespace: false,
|
||||
originalTransform: '',
|
||||
paddingBottom: 0,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
paddingTop: 0,
|
||||
scale: 1,
|
||||
};
|
||||
|
||||
task._textDivs.push(textDiv);
|
||||
if (isAllWhitespace(geom.str)) {
|
||||
textDiv.dataset.isWhitespace = true;
|
||||
textDivProperties.isWhitespace = true;
|
||||
task._textDivProperties.set(textDiv, textDivProperties);
|
||||
return;
|
||||
}
|
||||
var tx = Util.transform(viewport.transform, geom.transform);
|
||||
|
||||
var tx = Util.transform(task._viewport.transform, geom.transform);
|
||||
var angle = Math.atan2(tx[1], tx[0]);
|
||||
var style = styles[geom.fontName];
|
||||
if (style.vertical) {
|
||||
angle += Math.PI / 2;
|
||||
}
|
||||
|
@ -2879,32 +2942,34 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
textDiv.textContent = geom.str;
|
||||
// |fontName| is only used by the Font Inspector. This test will succeed
|
||||
// when e.g. the Font Inspector is off but the Stepper is on, but it's
|
||||
// not worth the effort to do a more accurate test.
|
||||
// not worth the effort to do a more accurate test. We only use `dataset`
|
||||
// here to make the font name available for the debugger.
|
||||
if (getDefaultSetting('pdfBug')) {
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
}
|
||||
// Storing into dataset will convert number into string.
|
||||
if (angle !== 0) {
|
||||
textDiv.dataset.angle = angle * (180 / Math.PI);
|
||||
textDivProperties.angle = angle * (180 / Math.PI);
|
||||
}
|
||||
// We don't bother scaling single-char text divs, because it has very
|
||||
// little effect on text highlighting. This makes scrolling on docs with
|
||||
// lots of such divs a lot faster.
|
||||
if (geom.str.length > 1) {
|
||||
if (style.vertical) {
|
||||
textDiv.dataset.canvasWidth = geom.height * viewport.scale;
|
||||
textDivProperties.canvasWidth = geom.height * task._viewport.scale;
|
||||
} else {
|
||||
textDiv.dataset.canvasWidth = geom.width * viewport.scale;
|
||||
textDivProperties.canvasWidth = geom.width * task._viewport.scale;
|
||||
}
|
||||
}
|
||||
if (enhanceTextSelection) {
|
||||
task._textDivProperties.set(textDiv, textDivProperties);
|
||||
|
||||
if (task._enhanceTextSelection) {
|
||||
var angleCos = 1, angleSin = 0;
|
||||
if (angle !== 0) {
|
||||
angleCos = Math.cos(angle);
|
||||
angleSin = Math.sin(angle);
|
||||
}
|
||||
var divWidth = (style.vertical ? geom.height : geom.width) *
|
||||
viewport.scale;
|
||||
task._viewport.scale;
|
||||
var divHeight = fontHeight;
|
||||
|
||||
var m, b;
|
||||
|
@ -2915,7 +2980,7 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
b = [left, top, left + divWidth, top + divHeight];
|
||||
}
|
||||
|
||||
bounds.push({
|
||||
task._bounds.push({
|
||||
left: b[0],
|
||||
top: b[1],
|
||||
right: b[2],
|
||||
|
@ -2952,7 +3017,8 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
var lastFontFamily;
|
||||
for (var i = 0; i < textDivsLength; i++) {
|
||||
var textDiv = textDivs[i];
|
||||
if (textDiv.dataset.isWhitespace !== undefined) {
|
||||
var textDivProperties = task._textDivProperties.get(textDiv);
|
||||
if (textDivProperties.isWhitespace) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2967,38 +3033,40 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
}
|
||||
|
||||
var width = ctx.measureText(textDiv.textContent).width;
|
||||
textDiv.dataset.originalWidth = width;
|
||||
textLayerFrag.appendChild(textDiv);
|
||||
var transform;
|
||||
if (textDiv.dataset.canvasWidth !== undefined && width > 0) {
|
||||
// Dataset values come of type string.
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
transform = 'scaleX(' + textScale + ')';
|
||||
} else {
|
||||
transform = '';
|
||||
}
|
||||
var rotation = textDiv.dataset.angle;
|
||||
if (rotation) {
|
||||
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
||||
}
|
||||
if (transform) {
|
||||
textDiv.dataset.originalTransform = transform;
|
||||
CustomStyle.setProp('transform' , textDiv, transform);
|
||||
}
|
||||
|
||||
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;
|
||||
CustomStyle.setProp('transform', textDiv, transform);
|
||||
}
|
||||
task._textDivProperties.set(textDiv, textDivProperties);
|
||||
}
|
||||
task._renderingDone = true;
|
||||
capability.resolve();
|
||||
}
|
||||
|
||||
function expand(bounds, viewport) {
|
||||
function expand(task) {
|
||||
var bounds = task._bounds;
|
||||
var viewport = task._viewport;
|
||||
|
||||
var expanded = expandBounds(viewport.width, viewport.height, bounds);
|
||||
for (var i = 0; i < expanded.length; i++) {
|
||||
var div = bounds[i].div;
|
||||
if (!div.dataset.angle) {
|
||||
div.dataset.paddingLeft = bounds[i].left - expanded[i].left;
|
||||
div.dataset.paddingTop = bounds[i].top - expanded[i].top;
|
||||
div.dataset.paddingRight = expanded[i].right - bounds[i].right;
|
||||
div.dataset.paddingBottom = expanded[i].bottom - bounds[i].bottom;
|
||||
var divProperties = task._textDivProperties.get(div);
|
||||
if (divProperties.angle === 0) {
|
||||
divProperties.paddingLeft = bounds[i].left - expanded[i].left;
|
||||
divProperties.paddingTop = bounds[i].top - expanded[i].top;
|
||||
divProperties.paddingRight = expanded[i].right - bounds[i].right;
|
||||
divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom;
|
||||
task._textDivProperties.set(div, divProperties);
|
||||
continue;
|
||||
}
|
||||
// Box is rotated -- trying to find padding so rotated div will not
|
||||
|
@ -3032,21 +3100,22 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
});
|
||||
var findPositiveMin = function (ts, offset, count) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var t = ts[offset++];
|
||||
if (t > 0) {
|
||||
result = result ? Math.min(t, result) : t;
|
||||
}
|
||||
for (var i = 0; i < count; i++) {
|
||||
var t = ts[offset++];
|
||||
if (t > 0) {
|
||||
result = result ? Math.min(t, result) : t;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// Not based on math, but to simplify calculations, using cos and sin
|
||||
// absolute values to not exceed the box (it can but insignificantly).
|
||||
var boxScale = 1 + Math.min(Math.abs(c), Math.abs(s));
|
||||
div.dataset.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale;
|
||||
div.dataset.paddingTop = findPositiveMin(ts, 48, 16) / boxScale;
|
||||
div.dataset.paddingRight = findPositiveMin(ts, 0, 16) / boxScale;
|
||||
div.dataset.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale;
|
||||
divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale;
|
||||
divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale;
|
||||
divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale;
|
||||
divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale;
|
||||
task._textDivProperties.set(div, divProperties);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3268,8 +3337,8 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
this._textContent = textContent;
|
||||
this._container = container;
|
||||
this._viewport = viewport;
|
||||
textDivs = textDivs || [];
|
||||
this._textDivs = textDivs;
|
||||
this._textDivs = textDivs || [];
|
||||
this._textDivProperties = new WeakMap();
|
||||
this._renderingDone = false;
|
||||
this._canceled = false;
|
||||
this._capability = createPromiseCapability();
|
||||
|
@ -3294,14 +3363,9 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
|
||||
_render: function TextLayer_render(timeout) {
|
||||
var textItems = this._textContent.items;
|
||||
var styles = this._textContent.styles;
|
||||
var textDivs = this._textDivs;
|
||||
var viewport = this._viewport;
|
||||
var enhanceTextSelection = this._enhanceTextSelection;
|
||||
|
||||
var textStyles = this._textContent.styles;
|
||||
for (var i = 0, len = textItems.length; i < len; i++) {
|
||||
appendText(textDivs, viewport, textItems[i], styles, this._bounds,
|
||||
enhanceTextSelection);
|
||||
appendText(this, textItems[i], textStyles);
|
||||
}
|
||||
|
||||
if (!timeout) { // Render right away
|
||||
|
@ -3320,59 +3384,53 @@ var renderTextLayer = (function renderTextLayerClosure() {
|
|||
return;
|
||||
}
|
||||
if (!this._expanded) {
|
||||
expand(this._bounds, this._viewport);
|
||||
expand(this);
|
||||
this._expanded = true;
|
||||
this._bounds.length = 0;
|
||||
}
|
||||
if (expandDivs) {
|
||||
for (var i = 0, ii = this._textDivs.length; i < ii; i++) {
|
||||
var div = this._textDivs[i];
|
||||
var transform;
|
||||
var width = div.dataset.originalWidth;
|
||||
if (div.dataset.canvasWidth !== undefined && width > 0) {
|
||||
// Dataset values come of type string.
|
||||
var textScale = div.dataset.canvasWidth / width;
|
||||
transform = 'scaleX(' + textScale + ')';
|
||||
} else {
|
||||
transform = '';
|
||||
|
||||
for (var i = 0, ii = this._textDivs.length; i < ii; i++) {
|
||||
var div = this._textDivs[i];
|
||||
var divProperties = this._textDivProperties.get(div);
|
||||
|
||||
if (expandDivs) {
|
||||
var transform = '';
|
||||
|
||||
if (divProperties.scale !== 1) {
|
||||
transform = 'scaleX(' + divProperties.scale + ')';
|
||||
}
|
||||
var rotation = div.dataset.angle;
|
||||
if (rotation) {
|
||||
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
||||
if (divProperties.angle !== 0) {
|
||||
transform = 'rotate(' + divProperties.angle + 'deg) ' + transform;
|
||||
}
|
||||
if (div.dataset.paddingLeft) {
|
||||
if (divProperties.paddingLeft !== 0) {
|
||||
div.style.paddingLeft =
|
||||
(div.dataset.paddingLeft / textScale) + 'px';
|
||||
(divProperties.paddingLeft / divProperties.scale) + 'px';
|
||||
transform += ' translateX(' +
|
||||
(-div.dataset.paddingLeft / textScale) + 'px)';
|
||||
(-divProperties.paddingLeft / divProperties.scale) + 'px)';
|
||||
}
|
||||
if (div.dataset.paddingTop) {
|
||||
div.style.paddingTop = div.dataset.paddingTop + 'px';
|
||||
transform += ' translateY(' + (-div.dataset.paddingTop) + 'px)';
|
||||
if (divProperties.paddingTop !== 0) {
|
||||
div.style.paddingTop = divProperties.paddingTop + 'px';
|
||||
transform += ' translateY(' + (-divProperties.paddingTop) + 'px)';
|
||||
}
|
||||
if (div.dataset.paddingRight) {
|
||||
if (divProperties.paddingRight !== 0) {
|
||||
div.style.paddingRight =
|
||||
div.dataset.paddingRight / textScale + 'px';
|
||||
(divProperties.paddingRight / divProperties.scale) + 'px';
|
||||
}
|
||||
if (div.dataset.paddingBottom) {
|
||||
div.style.paddingBottom = div.dataset.paddingBottom + 'px';
|
||||
if (divProperties.paddingBottom !== 0) {
|
||||
div.style.paddingBottom = divProperties.paddingBottom + 'px';
|
||||
}
|
||||
if (transform) {
|
||||
CustomStyle.setProp('transform' , div, transform);
|
||||
if (transform !== '') {
|
||||
CustomStyle.setProp('transform', div, transform);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0, ii = this._textDivs.length; i < ii; i++) {
|
||||
div = this._textDivs[i];
|
||||
} else {
|
||||
div.style.padding = 0;
|
||||
transform = div.dataset.originalTransform || '';
|
||||
CustomStyle.setProp('transform', div, transform);
|
||||
CustomStyle.setProp('transform', div,
|
||||
divProperties.originalTransform);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts rendering of the text layer.
|
||||
*
|
||||
|
@ -6594,6 +6652,7 @@ var error = sharedUtil.error;
|
|||
var deprecated = sharedUtil.deprecated;
|
||||
var getVerbosityLevel = sharedUtil.getVerbosityLevel;
|
||||
var info = sharedUtil.info;
|
||||
var isInt = sharedUtil.isInt;
|
||||
var isArrayBuffer = sharedUtil.isArrayBuffer;
|
||||
var isSameOrigin = sharedUtil.isSameOrigin;
|
||||
var loadJpegStream = sharedUtil.loadJpegStream;
|
||||
|
@ -8115,7 +8174,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||
|
||||
messageHandler.on('JpegDecode', function(data) {
|
||||
if (this.destroyed) {
|
||||
return Promise.reject('Worker was terminated');
|
||||
return Promise.reject(new Error('Worker was destroyed'));
|
||||
}
|
||||
|
||||
var imageUrl = data[0];
|
||||
|
@ -8165,8 +8224,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||
},
|
||||
|
||||
getPage: function WorkerTransport_getPage(pageNumber, capability) {
|
||||
if (pageNumber <= 0 || pageNumber > this.numPages ||
|
||||
(pageNumber|0) !== pageNumber) {
|
||||
if (!isInt(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) {
|
||||
return Promise.reject(new Error('Invalid page request'));
|
||||
}
|
||||
|
||||
|
@ -8189,12 +8247,11 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||
},
|
||||
|
||||
getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
|
||||
return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref }).
|
||||
then(function (pageIndex) {
|
||||
return pageIndex;
|
||||
}, function (reason) {
|
||||
return Promise.reject(new Error(reason));
|
||||
});
|
||||
return this.messageHandler.sendWithPromise('GetPageIndex', {
|
||||
ref: ref,
|
||||
}).catch(function (reason) {
|
||||
return Promise.reject(new Error(reason));
|
||||
});
|
||||
},
|
||||
|
||||
getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) {
|
||||
|
@ -8792,6 +8849,13 @@ exports._UnsupportedManager = _UnsupportedManager;
|
|||
PDFJS.isEvalSupported = (PDFJS.isEvalSupported === undefined ?
|
||||
true : PDFJS.isEvalSupported);
|
||||
|
||||
/**
|
||||
* Renders interactive form elements.
|
||||
* @var {boolean}
|
||||
*/
|
||||
PDFJS.renderInteractiveForms = (PDFJS.renderInteractiveForms === undefined ?
|
||||
false : PDFJS.renderInteractiveForms);
|
||||
|
||||
|
||||
PDFJS.getDocument = displayAPI.getDocument;
|
||||
PDFJS.PDFDataRangeTransport = displayAPI.PDFDataRangeTransport;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -101,6 +101,26 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.annotationLayer .textWidgetAnnotation input {
|
||||
background-color: rgba(0, 54, 255, 0.13);
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
font-size: 9px;
|
||||
height: 100%;
|
||||
padding: 0 3px;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.annotationLayer .textWidgetAnnotation input:hover {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.annotationLayer .textWidgetAnnotation input:focus {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.annotationLayer .popupWrapper {
|
||||
position: absolute;
|
||||
width: 20em;
|
||||
|
|
|
@ -951,7 +951,8 @@ exports.PDFRenderingQueue = PDFRenderingQueue;
|
|||
"disableFontFace": false,
|
||||
"disableTextLayer": false,
|
||||
"useOnlyCssZoom": false,
|
||||
"externalLinkTarget": 0
|
||||
"externalLinkTarget": 0,
|
||||
"renderInteractiveForms": false
|
||||
}
|
||||
|
||||
);
|
||||
|
@ -5037,7 +5038,7 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms
|
|||
* @property {IPDFTextLayerFactory} textLayerFactory
|
||||
* @property {IPDFAnnotationLayerFactory} annotationLayerFactory
|
||||
* @property {boolean} enhanceTextSelection - Turns on the text selection
|
||||
* enhancement. The default is `false`.
|
||||
* enhancement. The default is `false`.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -5793,7 +5794,7 @@ exports.PDFThumbnailViewer = PDFThumbnailViewer;
|
|||
* @property {PageViewport} viewport - The viewport of the text layer.
|
||||
* @property {PDFFindController} findController
|
||||
* @property {boolean} enhanceTextSelection - Option to turn on improved
|
||||
* text selection.
|
||||
* text selection.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -6190,7 +6191,8 @@ var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
|
|||
annotations: annotations,
|
||||
page: self.pdfPage,
|
||||
linkService: self.linkService,
|
||||
downloadManager: self.downloadManager
|
||||
downloadManager: self.downloadManager,
|
||||
renderInteractiveForms: pdfjsLib.PDFJS.renderInteractiveForms,
|
||||
};
|
||||
|
||||
if (self.div) {
|
||||
|
@ -7403,6 +7405,9 @@ var PDFViewerApplication = {
|
|||
}
|
||||
PDFJS.externalLinkTarget = value;
|
||||
}),
|
||||
Preferences.get('renderInteractiveForms').then(function resolved(value) {
|
||||
PDFJS.renderInteractiveForms = value;
|
||||
}),
|
||||
// TODO move more preferences and other async stuff here
|
||||
]).catch(function (reason) { });
|
||||
|
||||
|
|
|
@ -977,10 +977,14 @@ toolbaritem[cui-areatype="menu-panel"] > :-moz-any(@nestedButtons@) > .toolbarbu
|
|||
animation-duration: 250ms;
|
||||
}
|
||||
|
||||
#urlbar-zoom-button:hover:active {
|
||||
#urlbar-zoom-button:hover {
|
||||
background-color: hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button:hover:active {
|
||||
background-color: hsla(0,0%,0%,.15);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button > .toolbarbutton-text {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
|
|
@ -1689,10 +1689,15 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
animation-name: urlbar-zoom-reset-pulse;
|
||||
animation-duration: 250ms;
|
||||
}
|
||||
#urlbar-zoom-button:hover:active {
|
||||
|
||||
#urlbar-zoom-button:hover {
|
||||
background-color: hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button:hover:active {
|
||||
background-color: hsla(0,0%,0%,.15);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button > .toolbarbutton-text {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
|
|
@ -1422,10 +1422,14 @@ html|*.urlbar-input:-moz-lwtheme::placeholder,
|
|||
animation-duration: 250ms;
|
||||
}
|
||||
|
||||
#urlbar-zoom-button:hover:active {
|
||||
#urlbar-zoom-button:hover {
|
||||
background-color: hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button:hover:active {
|
||||
background-color: hsla(0,0%,0%,.15);
|
||||
}
|
||||
|
||||
#urlbar-zoom-button > .toolbarbutton-text {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,20 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="resource://devtools/client/debugger/new/styles.css" />
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css" />
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css" />
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="chrome://devtools/content/sourceeditor/codemirror/mozilla.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mount"></div>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://devtools/content/shared/theme-switching.js"></script>
|
||||
<script type="text/javascript">
|
||||
const { BrowserLoader } = Components.utils.import("resource://devtools/client/shared/browser-loader.js", {});
|
||||
const { require: devtoolsRequire } = BrowserLoader({
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
|
||||
// For UnrestrictedDoubleOrKeyframeAnimationOptions
|
||||
#include "mozilla/dom/AnimationEffectTiming.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
|
||||
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
#include "mozilla/dom/CSSPseudoElement.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "nsCSSParser.h" // For nsCSSParser
|
||||
#include "nsIDocument.h"
|
||||
|
|
|
@ -137,6 +137,23 @@ AnonymousContent::GetCanvasContext(const nsAString& aElementId,
|
|||
return context.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Animation>
|
||||
AnonymousContent::SetAnimationForElement(JSContext* aContext,
|
||||
const nsAString& aElementId,
|
||||
JS::Handle<JSObject*> aKeyframes,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Element* element = GetElementById(aElementId);
|
||||
|
||||
if (!element) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return element->Animate(aContext, aKeyframes, aOptions, aRv);
|
||||
}
|
||||
|
||||
Element*
|
||||
AnonymousContent::GetElementById(const nsAString& aElementId)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
class Element;
|
||||
class UnrestrictedDoubleOrAnonymousKeyframeAnimationOptions;
|
||||
|
||||
class AnonymousContent final
|
||||
{
|
||||
|
@ -57,6 +58,12 @@ public:
|
|||
const nsAString& aContextId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Animation> SetAnimationForElement(JSContext* aContext,
|
||||
const nsAString& aElementId,
|
||||
JS::Handle<JSObject*> aKeyframes,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError);
|
||||
|
||||
private:
|
||||
~AnonymousContent();
|
||||
nsCOMPtr<Element> mContentNode;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
|
||||
#include "mozilla/AnimationComparator.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
|
|
|
@ -45,7 +45,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1020244
|
|||
|
||||
let members = ["getTextContentForElement", "setTextContentForElement",
|
||||
"getAttributeForElement", "setAttributeForElement",
|
||||
"removeAttributeForElement", "getCanvasContext"];
|
||||
"removeAttributeForElement", "getCanvasContext",
|
||||
"setAnimationForElement"];
|
||||
for (let member of members) {
|
||||
ok(member in anonymousContent, "AnonymousContent object defines " + member);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1020244
|
|||
is(anonymousContent.getAttributeForElement("test-element", "class"), null,
|
||||
"Class attribute for the test element was removed");
|
||||
|
||||
let anim = anonymousContent.setAnimationForElement("test-element", [
|
||||
{ transform: 'translateY(0px)' },
|
||||
{ transform: 'translateY(-300px)' }
|
||||
], 2000);
|
||||
is(anim.playState, "pending", "Animation should be running");
|
||||
anim.cancel();
|
||||
is(anim.playState, "idle", "Animation should have stopped immediately");
|
||||
|
||||
chromeDocument.removeAnonymousContent(anonymousContent);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -1505,29 +1505,25 @@ BrowserElementChild.prototype = {
|
|||
successRv: manifest
|
||||
});
|
||||
}),
|
||||
|
||||
_initFinder: function() {
|
||||
if (!this._finder) {
|
||||
try {
|
||||
this._findLimit = Services.prefs.getIntPref("accessibility.typeaheadfind.matchesCountLimit");
|
||||
} catch (e) {
|
||||
// Pref not available, assume 0, no match counting.
|
||||
this._findLimit = 0;
|
||||
}
|
||||
|
||||
let {Finder} = Components.utils.import("resource://gre/modules/Finder.jsm", {});
|
||||
this._finder = new Finder(docShell);
|
||||
this._finder.addResultListener({
|
||||
onMatchesCountResult: (data) => {
|
||||
sendAsyncMsg('findchange', {
|
||||
active: true,
|
||||
searchString: this._finder.searchString,
|
||||
searchLimit: this._findLimit,
|
||||
activeMatchOrdinal: data.current,
|
||||
numberOfMatches: data.total
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
let listener = {
|
||||
onMatchesCountResult: (data) => {
|
||||
sendAsyncMsg("findchange", {
|
||||
active: true,
|
||||
searchString: this._finder.searchString,
|
||||
searchLimit: this._finder.matchesCountLimit,
|
||||
activeMatchOrdinal: data.current,
|
||||
numberOfMatches: data.total
|
||||
});
|
||||
this._finder.removeResultListener(listener);
|
||||
}
|
||||
};
|
||||
this._finder.addResultListener(listener);
|
||||
},
|
||||
|
||||
_recvFindAll: function(data) {
|
||||
|
@ -1535,7 +1531,7 @@ BrowserElementChild.prototype = {
|
|||
let searchString = data.json.searchString;
|
||||
this._finder.caseSensitive = data.json.caseSensitive;
|
||||
this._finder.fastFind(searchString, false, false);
|
||||
this._finder.requestMatchesCount(searchString, this._findLimit, false);
|
||||
this._finder.requestMatchesCount(searchString, this._finder.matchesCountLimit, false);
|
||||
},
|
||||
|
||||
_recvFindNext: function(data) {
|
||||
|
@ -1543,8 +1539,9 @@ BrowserElementChild.prototype = {
|
|||
debug("findNext() called before findAll()");
|
||||
return;
|
||||
}
|
||||
this._initFinder();
|
||||
this._finder.findAgain(data.json.backward, false, false);
|
||||
this._finder.requestMatchesCount(this._finder.searchString, this._findLimit, false);
|
||||
this._finder.requestMatchesCount(this._finder.searchString, this._finder.matchesCountLimit, false);
|
||||
},
|
||||
|
||||
_recvClearMatch: function(data) {
|
||||
|
@ -1553,7 +1550,7 @@ BrowserElementChild.prototype = {
|
|||
return;
|
||||
}
|
||||
this._finder.removeSelection();
|
||||
sendAsyncMsg('findchange', {active: false});
|
||||
sendAsyncMsg("findchange", {active: false});
|
||||
},
|
||||
|
||||
_recvSetInputMethodActive: function(data) {
|
||||
|
|
|
@ -22,8 +22,7 @@ dictionary AnimationFilter {
|
|||
interface Animatable {
|
||||
[Func="nsDocument::IsElementAnimateEnabled", Throws]
|
||||
Animation animate(object? keyframes,
|
||||
optional (unrestricted double or KeyframeAnimationOptions)
|
||||
options);
|
||||
optional UnrestrictedDoubleOrKeyframeAnimationOptions options);
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
sequence<Animation> getAnimations(optional AnimationFilter filter);
|
||||
};
|
||||
|
|
|
@ -61,4 +61,10 @@ interface AnonymousContent {
|
|||
[Throws]
|
||||
nsISupports? getCanvasContext(DOMString elementId,
|
||||
DOMString contextId);
|
||||
|
||||
[Func="nsDocument::IsElementAnimateEnabled", Throws]
|
||||
Animation setAnimationForElement(DOMString elementId,
|
||||
object? keyframes,
|
||||
optional UnrestrictedDoubleOrKeyframeAnimationOptions
|
||||
options);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dev.w3.org/fxtf/web-animations/#the-animatable-interface
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
// This typedef is off in its own file, because of bug 995352.
|
||||
typedef (unrestricted double or KeyframeAnimationOptions) UnrestrictedDoubleOrKeyframeAnimationOptions;
|
|
@ -291,6 +291,7 @@ WEBIDL_FILES = [
|
|||
'KeyAlgorithm.webidl',
|
||||
'KeyboardEvent.webidl',
|
||||
'KeyEvent.webidl',
|
||||
'KeyframeAnimationOptions.webidl',
|
||||
'KeyframeEffect.webidl',
|
||||
'LegacyQueryInterface.webidl',
|
||||
'LinkStyle.webidl',
|
||||
|
|
|
@ -92,6 +92,8 @@ if (typeof(repr) == 'undefined') {
|
|||
ostring = (1 / o > 0) ? "+0" : "-0";
|
||||
} else if (typeof o === "string") {
|
||||
ostring = JSON.stringify(o);
|
||||
} else if (Array.isArray(o)) {
|
||||
ostring = "[" + o.map(val => repr(val)).join(", ") + "]";
|
||||
} else {
|
||||
ostring = (o + "");
|
||||
}
|
||||
|
@ -1378,38 +1380,22 @@ if (isPrimaryTestWindow) {
|
|||
|
||||
SimpleTest.DNE = {dne: 'Does not exist'};
|
||||
SimpleTest.LF = "\r\n";
|
||||
SimpleTest._isRef = function (object) {
|
||||
var type = typeof(object);
|
||||
return type == 'object' || type == 'function';
|
||||
};
|
||||
|
||||
|
||||
SimpleTest._deepCheck = function (e1, e2, stack, seen) {
|
||||
var ok = false;
|
||||
// Either they're both references or both not.
|
||||
var sameRef = !(!SimpleTest._isRef(e1) ^ !SimpleTest._isRef(e2));
|
||||
if (e1 == null && e2 == null) {
|
||||
if (Object.is(e1, e2)) {
|
||||
// Handles identical primitives and references.
|
||||
ok = true;
|
||||
} else if (e1 != null ^ e2 != null) {
|
||||
} else if (typeof e1 != "object" || typeof e2 != "object" || e1 === null || e2 === null) {
|
||||
// If either argument is a primitive or function, don't consider the arguments the same.
|
||||
ok = false;
|
||||
} else if (e1 == SimpleTest.DNE ^ e2 == SimpleTest.DNE) {
|
||||
} else if (e1 == SimpleTest.DNE || e2 == SimpleTest.DNE) {
|
||||
ok = false;
|
||||
} else if (sameRef && e1 == e2) {
|
||||
// Handles primitives and any variables that reference the same
|
||||
// object, including functions.
|
||||
ok = true;
|
||||
} else if (SimpleTest.isa(e1, 'Array') && SimpleTest.isa(e2, 'Array')) {
|
||||
ok = SimpleTest._eqArray(e1, e2, stack, seen);
|
||||
} else if (typeof e1 == "object" && typeof e2 == "object") {
|
||||
ok = SimpleTest._eqAssoc(e1, e2, stack, seen);
|
||||
} else if (typeof e1 == "number" && typeof e2 == "number"
|
||||
&& isNaN(e1) && isNaN(e2)) {
|
||||
ok = true;
|
||||
} else {
|
||||
// If we get here, they're not the same (function references must
|
||||
// always simply reference the same function).
|
||||
stack.push({ vals: [e1, e2] });
|
||||
ok = false;
|
||||
ok = SimpleTest._eqAssoc(e1, e2, stack, seen);
|
||||
}
|
||||
return ok;
|
||||
};
|
||||
|
@ -1437,11 +1423,11 @@ SimpleTest._eqArray = function (a1, a2, stack, seen) {
|
|||
var ok = true;
|
||||
// Only examines enumerable attributes. Only works for numeric arrays!
|
||||
// Associative arrays return 0. So call _eqAssoc() for them, instead.
|
||||
var max = a1.length > a2.length ? a1.length : a2.length;
|
||||
var max = Math.max(a1.length, a2.length);
|
||||
if (max == 0) return SimpleTest._eqAssoc(a1, a2, stack, seen);
|
||||
for (var i = 0; i < max; i++) {
|
||||
var e1 = i > a1.length - 1 ? SimpleTest.DNE : a1[i];
|
||||
var e2 = i > a2.length - 1 ? SimpleTest.DNE : a2[i];
|
||||
var e1 = i < a1.length ? a1[i] : SimpleTest.DNE;
|
||||
var e2 = i < a2.length ? a2[i] : SimpleTest.DNE;
|
||||
stack.push({ type: 'Array', idx: i, vals: [e1, e2] });
|
||||
ok = SimpleTest._deepCheck(e1, e2, stack, seen);
|
||||
if (ok) {
|
||||
|
@ -1482,8 +1468,8 @@ SimpleTest._eqAssoc = function (o1, o2, stack, seen) {
|
|||
var o2Size = 0; for (var i in o2) o2Size++;
|
||||
var bigger = o1Size > o2Size ? o1 : o2;
|
||||
for (var i in bigger) {
|
||||
var e1 = o1[i] == undefined ? SimpleTest.DNE : o1[i];
|
||||
var e2 = o2[i] == undefined ? SimpleTest.DNE : o2[i];
|
||||
var e1 = i in o1 ? o1[i] : SimpleTest.DNE;
|
||||
var e2 = i in o2 ? o2[i] : SimpleTest.DNE;
|
||||
stack.push({ type: 'Object', idx: i, vals: [e1, e2] });
|
||||
ok = SimpleTest._deepCheck(e1, e2, stack, seen)
|
||||
if (ok) {
|
||||
|
@ -1502,7 +1488,7 @@ SimpleTest._formatStack = function (stack) {
|
|||
var type = entry['type'];
|
||||
var idx = entry['idx'];
|
||||
if (idx != null) {
|
||||
if (/^\d+$/.test(idx)) {
|
||||
if (type == 'Array') {
|
||||
// Numeric array index.
|
||||
variable += '[' + idx + ']';
|
||||
} else {
|
||||
|
@ -1522,39 +1508,26 @@ SimpleTest._formatStack = function (stack) {
|
|||
var out = "Structures begin differing at:" + SimpleTest.LF;
|
||||
for (var i = 0; i < vals.length; i++) {
|
||||
var val = vals[i];
|
||||
if (val == null) {
|
||||
val = 'undefined';
|
||||
if (val === SimpleTest.DNE) {
|
||||
val = "Does not exist";
|
||||
} else {
|
||||
val == SimpleTest.DNE ? "Does not exist" : "'" + val + "'";
|
||||
val = repr(val);
|
||||
}
|
||||
out += vars[i] + ' = ' + val + SimpleTest.LF;
|
||||
}
|
||||
|
||||
out += vars[0] + ' = ' + vals[0] + SimpleTest.LF;
|
||||
out += vars[1] + ' = ' + vals[1] + SimpleTest.LF;
|
||||
|
||||
return ' ' + out;
|
||||
};
|
||||
|
||||
|
||||
SimpleTest.isDeeply = function (it, as, name) {
|
||||
var ok;
|
||||
// ^ is the XOR operator.
|
||||
if (SimpleTest._isRef(it) ^ SimpleTest._isRef(as)) {
|
||||
// One's a reference, one isn't.
|
||||
ok = false;
|
||||
} else if (!SimpleTest._isRef(it) && !SimpleTest._isRef(as)) {
|
||||
// Neither is an object.
|
||||
ok = SimpleTest.is(it, as, name);
|
||||
var stack = [{ vals: [it, as] }];
|
||||
var seen = [];
|
||||
if ( SimpleTest._deepCheck(it, as, stack, seen)) {
|
||||
SimpleTest.ok(true, name);
|
||||
} else {
|
||||
// We have two objects. Do a deep comparison.
|
||||
var stack = [], seen = [];
|
||||
if ( SimpleTest._deepCheck(it, as, stack, seen)) {
|
||||
ok = SimpleTest.ok(true, name);
|
||||
} else {
|
||||
ok = SimpleTest.ok(false, name, SimpleTest._formatStack(stack));
|
||||
}
|
||||
SimpleTest.ok(false, name, SimpleTest._formatStack(stack));
|
||||
}
|
||||
return ok;
|
||||
};
|
||||
|
||||
SimpleTest.typeOf = function (object) {
|
||||
|
|
|
@ -9,7 +9,7 @@ Custom pings can be submitted from JavaScript using:
|
|||
TelemetryController.submitExternalPing(type, payload, options)
|
||||
|
||||
- ``type`` - a ``string`` that is the type of the ping, limited to ``/^[a-z0-9][a-z0-9-]+[a-z0-9]$/i``.
|
||||
- ``payload`` - the actual payload data for the ping, should be a JSON style object.
|
||||
- ``payload`` - the actual payload data for the ping, has to be a JSON style object.
|
||||
- ``options`` - optional, an object containing additional options:
|
||||
- ``addClientId``- whether to add the client id to the ping, defaults to ``false``
|
||||
- ``addEnvironment`` - whether to add the environment data to the ping, defaults to ``false``
|
||||
|
@ -19,6 +19,21 @@ Custom pings can be submitted from JavaScript using:
|
|||
That ping will be archived locally for use with Shield and inspection in ``about:telemetry``.
|
||||
If the preferences allow upload of Telemetry pings, the ping will be uploaded at the next opportunity (this is subject to throttling, retry-on-failure, etc.).
|
||||
|
||||
Submission constraints
|
||||
----------------------
|
||||
|
||||
When submitting pings on shutdown, they should not be submitted after Telemetry shutdown.
|
||||
Pings should be submitted at the latest within:
|
||||
|
||||
- the `observer notification <https://developer.mozilla.org/de/docs/Observer_Notifications#Application_shutdown>`_ ``"profile-before-change"``
|
||||
- the :ref:`AsyncShutdown phase <AsyncShutdown_phases>` ``sendTelemetry``
|
||||
|
||||
There are other constraints that can lead to a ping submission getting dropped:
|
||||
|
||||
- invalid ping type strings
|
||||
- invalid payload types: E.g. strings instead of objects.
|
||||
- oversized payloads: We currently only drop pings >1MB, but targetting sizes of <=10KB is recommended.
|
||||
|
||||
Tools
|
||||
=====
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
Cu.import("resource://testing-common/ContentTask.jsm");
|
||||
ContentTask.setTestScope(window.opener.wrappedJSObject);
|
||||
|
||||
var gPrefsvc = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
|
||||
const SAMPLE_URL = "http://www.mozilla.org/";
|
||||
const SAMPLE_TEXT = "Some text in a text field.";
|
||||
const SEARCH_TEXT = "Text Test";
|
||||
const NOT_FOUND_TEXT = "This text is not on the page."
|
||||
const ITERATOR_TIMEOUT = gPrefsvc.getIntPref("findbar.iteratorTimeout") + 20;
|
||||
|
||||
var gFindBar = null;
|
||||
var gBrowser;
|
||||
|
@ -250,6 +253,8 @@
|
|||
}
|
||||
};
|
||||
gFindBar.browser.finder.addResultListener(listener);
|
||||
// Make sure we resolve _at least_ after five times the find iterator timeout.
|
||||
setTimeout(resolve, ITERATOR_TIMEOUT * 5);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -368,9 +373,7 @@
|
|||
ok(!matchCaseCheckbox.hidden, "match case box is hidden in manual mode");
|
||||
ok(matchCaseLabel.hidden, "match case label is visible in manual mode");
|
||||
|
||||
var prefsvc = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Components.interfaces.nsIPrefBranch);
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 2);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 2);
|
||||
|
||||
ok(matchCaseCheckbox.hidden,
|
||||
"match case box is visible in automatic mode");
|
||||
|
@ -388,7 +391,7 @@
|
|||
gFindBar.onFindAgainCommand();
|
||||
ok(matchCaseCheckbox.hidden && !matchCaseLabel.hidden,
|
||||
"bug 365551: case sensitivity UI is broken after find-again");
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
gFindBar.close();
|
||||
}
|
||||
|
||||
|
@ -519,6 +522,7 @@
|
|||
if (matchCase.checked) {
|
||||
promise = promiseFindResult();
|
||||
matchCase.click();
|
||||
yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT));
|
||||
yield promise;
|
||||
}
|
||||
|
||||
|
@ -553,15 +557,16 @@
|
|||
gFindBar._findField.select();
|
||||
gFindBar._findField.focus();
|
||||
|
||||
promise = promiseMatchesCountResult();
|
||||
yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT));
|
||||
yield enterStringIntoFindField(test.text, false);
|
||||
yield promise;
|
||||
yield promiseMatchesCountResult();
|
||||
let matches = foundMatches.value.match(regex);
|
||||
if (!test.total) {
|
||||
ok(!matches, "No message should be shown when 0 matches are expected");
|
||||
} else {
|
||||
assertMatches(test, matches);
|
||||
for (let i = 1; i < test.total; i++) {
|
||||
yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT));
|
||||
gFindBar.onFindAgainCommand();
|
||||
yield promiseMatchesCountResult();
|
||||
// test.current + 1, test.current + 2, ..., test.total, 1, ..., test.current
|
||||
|
@ -583,16 +588,14 @@
|
|||
yield enterStringIntoFindField(SEARCH_TEXT);
|
||||
gFindBar.clear();
|
||||
|
||||
let prefsvc = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
|
||||
yield enterStringIntoFindField("t");
|
||||
yield ContentTask.spawn(gBrowser, null, function* () {
|
||||
Assert.equal(content.getSelection().toString(), "T", "First T should be selected.");
|
||||
});
|
||||
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
|
||||
yield ContentTask.spawn(gBrowser, null, function* () {
|
||||
Assert.equal(content.getSelection().toString(), "t", "First t should be selected.");
|
||||
});
|
||||
|
@ -602,16 +605,14 @@
|
|||
// 1. Do a search that fails with case sensitivity but matches with no case sensitivity.
|
||||
// 2. Uncheck case sensitivity button to match the string.
|
||||
function* testFailedStringReset() {
|
||||
let prefsvc = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Components.interfaces.nsIPrefBranch);
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 1);
|
||||
|
||||
yield enterStringIntoFindField(SEARCH_TEXT.toUpperCase(), false);
|
||||
yield ContentTask.spawn(gBrowser, null, function* () {
|
||||
Assert.equal(content.getSelection().toString(), "", "Not found.");
|
||||
});
|
||||
|
||||
prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
gPrefsvc.setIntPref("accessibility.typeaheadfind.casesensitive", 0);
|
||||
yield ContentTask.spawn(gBrowser, { SEARCH_TEXT }, function* (args) {
|
||||
Assert.equal(content.getSelection().toString(), args.SEARCH_TEXT,
|
||||
"Search text should be selected.");
|
||||
|
|
|
@ -143,7 +143,13 @@
|
|||
and then they would see the incorrect value of checked. Additionally
|
||||
a command attribute would redirect the command events anyway.-->
|
||||
<handler event="click" button="0" action="this._handleClick();"/>
|
||||
<handler event="keypress" key=" " action="this._handleClick();"/>
|
||||
<handler event="keypress" key=" ">
|
||||
<![CDATA[
|
||||
this._handleClick();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
]]>
|
||||
</handler>
|
||||
|
||||
<handler event="keypress">
|
||||
<![CDATA[
|
||||
|
@ -246,7 +252,13 @@
|
|||
|
||||
<handlers>
|
||||
<handler event="keypress" keycode="VK_RETURN" action="this.open = true;"/>
|
||||
<handler event="keypress" key=" " action="this.open = true;"/>
|
||||
<handler event="keypress" key=" ">
|
||||
<![CDATA[
|
||||
this.open = true;
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
|
@ -337,8 +349,11 @@
|
|||
this.open = true;
|
||||
</handler>
|
||||
<handler event="keypress" key=" ">
|
||||
if (event.originalTarget == this)
|
||||
if (event.originalTarget == this) {
|
||||
this.open = true;
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<xul:label class="checkbox-label" xbl:inherits="xbl:text=label,accesskey,crop" flex="1"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
|
||||
<implementation implements="nsIDOMXULCheckboxElement">
|
||||
<method name="setChecked">
|
||||
<parameter name="aValue"/>
|
||||
|
@ -44,24 +44,26 @@
|
|||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<!-- public implementation -->
|
||||
<property name="checked" onset="return this.setChecked(val);"
|
||||
onget="return this.getAttribute('checked') == 'true';"/>
|
||||
</implementation>
|
||||
|
||||
|
||||
<handlers>
|
||||
<!-- While it would seem we could do this by handling oncommand, we need can't
|
||||
because any external oncommand handlers might get called before ours, and
|
||||
then they would see the incorrect value of checked. -->
|
||||
then they would see the incorrect value of checked. -->
|
||||
<handler event="click" button="0" action="if (!this.disabled) this.checked = !this.checked;"/>
|
||||
<handler event="keypress" key=" ">
|
||||
<![CDATA[
|
||||
this.checked = !this.checked;
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
</binding>
|
||||
|
||||
<binding id="checkbox-with-spacing"
|
||||
extends="chrome://global/content/bindings/checkbox.xml#checkbox">
|
||||
|
|
|
@ -344,6 +344,8 @@
|
|||
case "findbar.entireword":
|
||||
this._self._entireWord = prefsvc.getBoolPref(aPrefName);
|
||||
this._self._updateEntireWord();
|
||||
// Update the matches count.
|
||||
this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
|
||||
break;
|
||||
case "findbar.highlightAll":
|
||||
this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
|
||||
|
@ -499,11 +501,11 @@
|
|||
-->
|
||||
<method name="_updateMatchesCount">
|
||||
<body><![CDATA[
|
||||
if (this._matchesCountLimit == 0 || !this._dispatchFindEvent("matchescount"))
|
||||
if (!this._dispatchFindEvent("matchescount"))
|
||||
return;
|
||||
|
||||
this.browser.finder.requestMatchesCount(this._findField.value,
|
||||
this._matchesCountLimit, this._findMode == this.FIND_LINKS);
|
||||
this._findMode == this.FIND_LINKS);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -628,7 +630,6 @@
|
|||
this._updateCaseSensitivity();
|
||||
this._findFailedString = null;
|
||||
this._find();
|
||||
this._maybeHighlightAll();
|
||||
|
||||
this._dispatchFindEvent("casesensitivitychange");
|
||||
]]></body>
|
||||
|
@ -653,9 +654,6 @@
|
|||
statusLabel.hidden = !hideCheckbox;
|
||||
|
||||
this.browser.finder.entireWord = entireWord;
|
||||
|
||||
// Update the matches count
|
||||
this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -1020,8 +1018,6 @@
|
|||
}
|
||||
|
||||
this._enableFindButtons(val);
|
||||
this._maybeHighlightAll();
|
||||
|
||||
this._updateCaseSensitivity(val);
|
||||
this._updateEntireWord();
|
||||
|
||||
|
@ -1100,7 +1096,6 @@
|
|||
this._findField.removeAttribute("status");
|
||||
break;
|
||||
}
|
||||
this._updateMatchesCount(res);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
|
|
@ -822,11 +822,16 @@
|
|||
<handler event="keypress" key=" " phase="target">
|
||||
<![CDATA[
|
||||
if (this.currentItem) {
|
||||
if (this.currentItem.getAttribute("type") != "checkbox")
|
||||
if (this.currentItem.getAttribute("type") != "checkbox") {
|
||||
this.addItemToSelection(this.currentItem);
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
else if (!this.currentItem.disabled) {
|
||||
this.currentItem.checked = !this.currentItem.checked;
|
||||
this.currentItem.doCommand();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
]]>
|
||||
|
|
|
@ -370,8 +370,10 @@
|
|||
is done solely through the arrow keys and not the tab button. Tab
|
||||
takes you to the next widget in the tab order -->
|
||||
<handler event="keypress" key=" " phase="target">
|
||||
this.selectedItem = this.focusedItem;
|
||||
this.selectedItem.doCommand();
|
||||
this.selectedItem = this.focusedItem;
|
||||
this.selectedItem.doCommand();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
</handler>
|
||||
<handler event="keypress" keycode="VK_UP" phase="target">
|
||||
this.checkAdjacentElement(false);
|
||||
|
|
|
@ -26,6 +26,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "ClipboardHelper",
|
|||
"nsIClipboardHelper");
|
||||
|
||||
const kSelectionMaxLen = 150;
|
||||
const kMatchesCountLimitPref = "accessibility.typeaheadfind.matchesCountLimit";
|
||||
|
||||
function Finder(docShell) {
|
||||
this._fastFind = Cc["@mozilla.org/typeaheadfind;1"].createInstance(Ci.nsITypeAheadFind);
|
||||
|
@ -113,7 +114,9 @@ Finder.prototype = {
|
|||
})) {
|
||||
this.iterator.stop();
|
||||
}
|
||||
|
||||
this.highlighter.update(options);
|
||||
this.requestMatchesCount(options.searchString, options.linksOnly);
|
||||
|
||||
this._outlineLink(options.drawOutline);
|
||||
|
||||
|
@ -167,6 +170,14 @@ Finder.prototype = {
|
|||
return this._highlighter = new FinderHighlighter(this);
|
||||
},
|
||||
|
||||
get matchesCountLimit() {
|
||||
if (typeof this._matchesCountLimit == "number")
|
||||
return this._matchesCountLimit;
|
||||
|
||||
this._matchesCountLimit = Services.prefs.getIntPref(kMatchesCountLimitPref) || 0;
|
||||
return this._matchesCountLimit;
|
||||
},
|
||||
|
||||
_lastFindResult: null,
|
||||
|
||||
/**
|
||||
|
@ -321,6 +332,7 @@ Finder.prototype = {
|
|||
onFindbarClose: function() {
|
||||
this.enableSelection();
|
||||
this.highlighter.highlight(false);
|
||||
this.iterator.reset();
|
||||
BrowserUtils.trackToolbarVisibility(this._docShell, "findbar", false);
|
||||
},
|
||||
|
||||
|
@ -383,7 +395,7 @@ Finder.prototype = {
|
|||
_notifyMatchesCount: function(result = this._currentMatchesCountResult) {
|
||||
// The `_currentFound` property is only used for internal bookkeeping.
|
||||
delete result._currentFound;
|
||||
if (result.total == this._currentMatchLimit)
|
||||
if (result.total == this.matchesCountLimit)
|
||||
result.total = -1;
|
||||
|
||||
for (let l of this._listeners) {
|
||||
|
@ -395,9 +407,9 @@ Finder.prototype = {
|
|||
this._currentMatchesCountResult = null;
|
||||
},
|
||||
|
||||
requestMatchesCount: function(aWord, aMatchLimit, aLinksOnly) {
|
||||
requestMatchesCount: function(aWord, aLinksOnly) {
|
||||
if (this._lastFindResult == Ci.nsITypeAheadFind.FIND_NOTFOUND ||
|
||||
this.searchString == "" || !aWord) {
|
||||
this.searchString == "" || !aWord || !this.matchesCountLimit) {
|
||||
this._notifyMatchesCount({
|
||||
total: 0,
|
||||
current: 0
|
||||
|
@ -407,7 +419,6 @@ Finder.prototype = {
|
|||
|
||||
let window = this._getWindow();
|
||||
this._currentFoundRange = this._fastFind.getFoundRange();
|
||||
this._currentMatchLimit = aMatchLimit;
|
||||
|
||||
let params = {
|
||||
caseSensitive: this._fastFind.caseSensitive,
|
||||
|
@ -420,7 +431,7 @@ Finder.prototype = {
|
|||
|
||||
this.iterator.start(Object.assign(params, {
|
||||
finder: this,
|
||||
limit: aMatchLimit,
|
||||
limit: this.matchesCountLimit,
|
||||
listener: this,
|
||||
useCache: true,
|
||||
})).then(() => {
|
||||
|
@ -453,7 +464,7 @@ Finder.prototype = {
|
|||
onIteratorReset() {},
|
||||
|
||||
onIteratorRestart({ word, linksOnly }) {
|
||||
this.requestMatchesCount(word, this._currentMatchLimit, linksOnly);
|
||||
this.requestMatchesCount(word, linksOnly);
|
||||
},
|
||||
|
||||
onIteratorStart() {
|
||||
|
|
|
@ -20,7 +20,7 @@ XPCOMUtils.defineLazyGetter(this, "kDebug", () => {
|
|||
});
|
||||
|
||||
const kContentChangeThresholdPx = 5;
|
||||
const kModalHighlightRepaintFreqMs = 200;
|
||||
const kModalHighlightRepaintFreqMs = 100;
|
||||
const kHighlightAllPref = "findbar.highlightAll";
|
||||
const kModalHighlightPref = "findbar.modalHighlight";
|
||||
const kFontPropsCSS = ["color", "font-family", "font-kerning", "font-size",
|
||||
|
@ -30,96 +30,64 @@ const kFontPropsCamelCase = kFontPropsCSS.map(prop => {
|
|||
let parts = prop.split("-");
|
||||
return parts.shift() + parts.map(part => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
||||
});
|
||||
const kRGBRE = /^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/i
|
||||
// This uuid is used to prefix HTML element IDs and classNames in order to make
|
||||
// them unique and hard to clash with IDs and classNames content authors come up
|
||||
// with, since the stylesheet for modal highlighting is inserted as an agent-sheet
|
||||
// in the active HTML document.
|
||||
const kRGBRE = /^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/i;
|
||||
// This uuid is used to prefix HTML element IDs in order to make them unique and
|
||||
// hard to clash with IDs content authors come up with.
|
||||
const kModalIdPrefix = "cedee4d0-74c5-4f2d-ab43-4d37c0f9d463";
|
||||
const kModalOutlineId = kModalIdPrefix + "-findbar-modalHighlight-outline";
|
||||
const kModalStyle = `
|
||||
.findbar-modalHighlight-outline {
|
||||
position: absolute;
|
||||
background: #ffc535;
|
||||
box-shadow: 0 2px 0 0 rgba(0,0,0,.1);
|
||||
color: #000;
|
||||
display: -moz-box;
|
||||
margin: -2px 0 0 -2px !important;
|
||||
padding: 2px !important;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline.findbar-debug {
|
||||
z-index: 2147483647;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline[grow] {
|
||||
animation-name: findbar-modalHighlight-outlineAnim;
|
||||
}
|
||||
|
||||
@keyframes findbar-modalHighlight-outlineAnim {
|
||||
from {
|
||||
transform: scaleX(0) scaleY(0);
|
||||
}
|
||||
50% {
|
||||
transform: scaleX(1.5) scaleY(1.5);
|
||||
}
|
||||
to {
|
||||
transform: scaleX(0) scaleY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline[hidden] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline:not([disable-transitions]) {
|
||||
transition-property: opacity, transform, top, left;
|
||||
transition-duration: 50ms;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline-text {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
vertical-align: top !important;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outlineMask {
|
||||
background: #000;
|
||||
mix-blend-mode: multiply;
|
||||
opacity: .35;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outlineMask.findbar-debug {
|
||||
z-index: 2147483646;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outlineMask[brighttext] {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-rect {
|
||||
background: #fff;
|
||||
margin: -1px 0 0 -1px !important;
|
||||
padding: 0 1px 2px 1px !important;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outlineMask[brighttext] > .findbar-modalHighlight-rect {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.findbar-modalHighlight-outline,
|
||||
.findbar-modalHighlight-rect {
|
||||
border-radius: 3px;
|
||||
}`;
|
||||
const kModalStyles = {
|
||||
outlineNode: [
|
||||
["position", "absolute"],
|
||||
["background", "#ffc535"],
|
||||
["border-radius", "3px"],
|
||||
["box-shadow", "0 2px 0 0 rgba(0,0,0,.1)"],
|
||||
["color", "#000"],
|
||||
["display", "-moz-box"],
|
||||
["margin", "-2px 0 0 -2px !important"],
|
||||
["padding", "2px !important"],
|
||||
["pointer-events", "none"],
|
||||
["transition-property", "opacity, transform, top, left"],
|
||||
["transition-duration", "50ms"],
|
||||
["transition-timing-function", "linear"],
|
||||
["z-index", 2]
|
||||
],
|
||||
outlineNodeDebug: [ ["z-index", 2147483647] ],
|
||||
outlineText: [
|
||||
["margin", "0 !important"],
|
||||
["padding", "0 !important"],
|
||||
["vertical-align", "top !important"]
|
||||
],
|
||||
maskNode: [
|
||||
["background", "#000"],
|
||||
["mix-blend-mode", "multiply"],
|
||||
["opacity", ".35"],
|
||||
["pointer-events", "none"],
|
||||
["position", "absolute"],
|
||||
["z-index", 1]
|
||||
],
|
||||
maskNodeDebug: [
|
||||
["z-index", 2147483646],
|
||||
["top", 0],
|
||||
["left", 0]
|
||||
],
|
||||
maskNodeBrightText: [ ["background", "#fff"] ],
|
||||
maskRect: [
|
||||
["background", "#fff"],
|
||||
["border-radius", "3px"],
|
||||
["margin", "-1px 0 0 -1px !important"],
|
||||
["padding", "0 1px 2px 1px !important"],
|
||||
["position", "absolute"]
|
||||
],
|
||||
maskRectBrightText: [ "background", "#000" ]
|
||||
};
|
||||
const kModalOutlineAnim = {
|
||||
"keyframes": [
|
||||
{ transform: "scaleX(1) scaleY(1)" },
|
||||
{ transform: "scaleX(1.5) scaleY(1.5)", offset: .5, easing: "ease-in" },
|
||||
{ transform: "scaleX(1) scaleY(1)" }
|
||||
],
|
||||
duration: 50,
|
||||
};
|
||||
|
||||
function mockAnonymousContentNode(domNode) {
|
||||
return {
|
||||
|
@ -171,22 +139,6 @@ FinderHighlighter.prototype = {
|
|||
return this._iterator;
|
||||
},
|
||||
|
||||
get modalStyleSheet() {
|
||||
if (!this._modalStyleSheet) {
|
||||
this._modalStyleSheet = kModalStyle.replace(/findbar-/g,
|
||||
kModalIdPrefix + "-findbar-");
|
||||
}
|
||||
return this._modalStyleSheet;
|
||||
},
|
||||
|
||||
get modalStyleSheetURI() {
|
||||
if (!this._modalStyleSheetURI) {
|
||||
this._modalStyleSheetURI = "data:text/css;charset=utf-8," +
|
||||
encodeURIComponent(this.modalStyleSheet.replace(/[\n]+/g, " "));
|
||||
}
|
||||
return this._modalStyleSheetURI;
|
||||
},
|
||||
|
||||
/**
|
||||
* Each window is unique, globally, and the relation between an active
|
||||
* highlighting session and a window is 1:1.
|
||||
|
@ -195,8 +147,6 @@ FinderHighlighter.prototype = {
|
|||
* on page layout changes and user input
|
||||
* - {Map} frames Collection of frames that were encountered
|
||||
* when inspecting the found ranges
|
||||
* - {Boolean} installedSheet Whether the modal stylesheet was loaded
|
||||
* already
|
||||
* - {Map} modalHighlightRectsMap Collection of ranges and their corresponding
|
||||
* Rects
|
||||
*
|
||||
|
@ -208,7 +158,6 @@ FinderHighlighter.prototype = {
|
|||
gWindows.set(window, {
|
||||
dynamicRangesSet: new Set(),
|
||||
frames: new Map(),
|
||||
installedSheet: false,
|
||||
modalHighlightRectsMap: new Map()
|
||||
});
|
||||
}
|
||||
|
@ -401,8 +350,11 @@ FinderHighlighter.prototype = {
|
|||
}
|
||||
dict.lastWindowDimensions = null;
|
||||
|
||||
if (dict.modalHighlightOutline)
|
||||
dict.modalHighlightOutline.setAttributeForElement(kModalOutlineId, "hidden", "true");
|
||||
if (dict.modalHighlightOutline) {
|
||||
dict.modalHighlightOutline.setAttributeForElement(kModalOutlineId, "style",
|
||||
dict.modalHighlightOutline.getAttributeForElement(kModalOutlineId, "style") +
|
||||
"; opacity: 0");
|
||||
}
|
||||
|
||||
this._removeHighlightAllMask(window);
|
||||
this._removeModalHighlightListeners(window);
|
||||
|
@ -478,12 +430,14 @@ FinderHighlighter.prototype = {
|
|||
}
|
||||
|
||||
outlineNode = dict.modalHighlightOutline;
|
||||
try {
|
||||
outlineNode.removeAttributeForElement(kModalOutlineId, "grow");
|
||||
} catch (ex) {}
|
||||
window.requestAnimationFrame(() => {
|
||||
outlineNode.setAttributeForElement(kModalOutlineId, "grow", true);
|
||||
});
|
||||
if (dict.animation)
|
||||
dict.animation.finish();
|
||||
dict.animation = outlineNode.setAnimationForElement(kModalOutlineId,
|
||||
Cu.cloneInto(kModalOutlineAnim.keyframes, window), kModalOutlineAnim.duration);
|
||||
dict.animation.onfinish = () => dict.animation = null;
|
||||
|
||||
if (this._highlightAll && data.searchString)
|
||||
this.highlight(true, data.searchString, data.linksOnly);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -501,6 +455,8 @@ FinderHighlighter.prototype = {
|
|||
}
|
||||
|
||||
let dict = this.getForWindow(window.top);
|
||||
if (dict.animation)
|
||||
dict.animation.finish();
|
||||
dict.currentFoundRange = null;
|
||||
dict.dynamicRangesSet.clear();
|
||||
dict.frames.clear();
|
||||
|
@ -714,9 +670,28 @@ FinderHighlighter.prototype = {
|
|||
let idx = kFontPropsCamelCase.indexOf(prop);
|
||||
if (idx == -1)
|
||||
continue;
|
||||
style.push(`${kFontPropsCSS[idx]}: ${fontStyle[prop]};`);
|
||||
style.push(`${kFontPropsCSS[idx]}: ${fontStyle[prop]}`);
|
||||
}
|
||||
return style.join(" ");
|
||||
return style.join("; ");
|
||||
},
|
||||
|
||||
/**
|
||||
* Transform a style definition array as defined in `kModalStyles` into a CSS
|
||||
* string that can be used to set the 'style' property of a DOM node.
|
||||
*
|
||||
* @param {Array} stylePairs Two-dimensional array of style pairs
|
||||
* @param {...Array} [additionalStyles] Optional set of style pairs that will
|
||||
* augment or override the styles defined
|
||||
* by `stylePairs`
|
||||
* @return {String}
|
||||
*/
|
||||
_getStyleString(stylePairs, ...additionalStyles) {
|
||||
let baseStyle = new Map(stylePairs);
|
||||
for (let additionalStyle of additionalStyles) {
|
||||
for (let [prop, value] of additionalStyle)
|
||||
baseStyle.set(prop, value);
|
||||
}
|
||||
return [...baseStyle].map(([cssProp, cssVal]) => `${cssProp}: ${cssVal}`).join("; ");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -739,7 +714,7 @@ FinderHighlighter.prototype = {
|
|||
* is the case for 'fixed' and 'sticky' positioned elements and elements inside
|
||||
* (i)frames.
|
||||
*
|
||||
* @param {nsIDOMRange} range Range that be enclosed in a fixed container
|
||||
* @param {nsIDOMRange} range Range that be enclosed in a dynamic container
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_isInDynamicContainer(range) {
|
||||
|
@ -816,12 +791,12 @@ FinderHighlighter.prototype = {
|
|||
|
||||
/**
|
||||
* Re-read the rectangles of the ranges that we keep track of separately,
|
||||
* because they're enclosed by a position: fixed container DOM node.
|
||||
* because they're enclosed by a position: fixed container DOM node or (i)frame.
|
||||
*
|
||||
* @param {Object} dict Dictionary of properties belonging to the currently
|
||||
* active window
|
||||
*/
|
||||
_updateFixedRangesRects(dict) {
|
||||
_updateDynamicRangesRects(dict) {
|
||||
for (let range of dict.dynamicRangesSet)
|
||||
this._updateRangeRects(range, false, dict);
|
||||
// Reset the frame bounds cache.
|
||||
|
@ -851,7 +826,7 @@ FinderHighlighter.prototype = {
|
|||
|
||||
if (!fontStyle)
|
||||
fontStyle = this._getRangeFontStyle(range);
|
||||
// Text color in the outline is determined by our stylesheet.
|
||||
// Text color in the outline is determined by kModalStyles.
|
||||
delete fontStyle.color;
|
||||
|
||||
if (textContent.length)
|
||||
|
@ -859,16 +834,19 @@ FinderHighlighter.prototype = {
|
|||
// Correct the line-height to align the text in the middle of the box.
|
||||
fontStyle.lineHeight = rect.height + "px";
|
||||
outlineNode.setAttributeForElement(kModalOutlineId + "-text", "style",
|
||||
this._getStyleString(kModalStyles.outlineText) + "; " +
|
||||
this._getHTMLFontStyle(fontStyle));
|
||||
|
||||
if (typeof outlineNode.getAttributeForElement(kModalOutlineId, "hidden") == "string")
|
||||
outlineNode.removeAttributeForElement(kModalOutlineId, "hidden");
|
||||
|
||||
let window = range.startContainer.ownerDocument.defaultView;
|
||||
let { left, top } = this._getRootBounds(window);
|
||||
outlineNode.setAttributeForElement(kModalOutlineId, "style",
|
||||
`top: ${top + rect.top}px; left: ${left + rect.left}px;
|
||||
height: ${rect.height}px; width: ${rect.width}px;`);
|
||||
this._getStyleString(kModalStyles.outlineNode, [
|
||||
["top", top + rect.top + "px"],
|
||||
["left", left + rect.left + "px"],
|
||||
["height", rect.height + "px"],
|
||||
["width", rect.width + "px"]],
|
||||
kDebug ? kModalStyles.outlineNodeDebug : []
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -921,8 +899,6 @@ FinderHighlighter.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
this._maybeInstallStyleSheet(window);
|
||||
|
||||
// The outline needs to be sitting inside a container, otherwise the anonymous
|
||||
// content API won't find it by its ID later...
|
||||
let container = document.createElement("div");
|
||||
|
@ -930,11 +906,12 @@ FinderHighlighter.prototype = {
|
|||
// Create the main (yellow) highlight outline box.
|
||||
let outlineBox = document.createElement("div");
|
||||
outlineBox.setAttribute("id", kModalOutlineId);
|
||||
outlineBox.className = kModalOutlineId + (kDebug ? ` ${kModalIdPrefix}-findbar-debug` : "");
|
||||
outlineBox.setAttribute("style", this._getStyleString(kModalStyles.outlineNode,
|
||||
kDebug ? kModalStyles.outlineNodeDebug : []));
|
||||
let outlineBoxText = document.createElement("span");
|
||||
let attrValue = kModalOutlineId + "-text";
|
||||
outlineBoxText.setAttribute("id", attrValue);
|
||||
outlineBoxText.setAttribute("class", attrValue);
|
||||
outlineBoxText.setAttribute("style", this._getStyleString(kModalStyles.outlineText));
|
||||
outlineBox.appendChild(outlineBoxText);
|
||||
|
||||
container.appendChild(outlineBox);
|
||||
|
@ -963,25 +940,27 @@ FinderHighlighter.prototype = {
|
|||
let maskNode = document.createElement("div");
|
||||
|
||||
// Make sure the dimmed mask node takes the full width and height that's available.
|
||||
let {width, height} = this._getWindowDimensions(window);
|
||||
dict.lastWindowDimensions = { width, height };
|
||||
let {width, height} = dict.lastWindowDimensions = this._getWindowDimensions(window);
|
||||
maskNode.setAttribute("id", kMaskId);
|
||||
maskNode.setAttribute("class", kMaskId + (kDebug ? ` ${kModalIdPrefix}-findbar-debug` : ""));
|
||||
maskNode.setAttribute("style", `width: ${width}px; height: ${height}px;`);
|
||||
maskNode.setAttribute("style", this._getStyleString(kModalStyles.maskNode,
|
||||
[ ["width", width + "px"], ["height", height + "px"] ],
|
||||
dict.brightText ? kModalStyles.maskNodeBrightText : [],
|
||||
kDebug ? kModalStyles.maskNodeDebug : []));
|
||||
if (dict.brightText)
|
||||
maskNode.setAttribute("brighttext", "true");
|
||||
|
||||
if (paintContent || dict.modalHighlightAllMask) {
|
||||
this._updateRangeOutline(dict);
|
||||
this._updateFixedRangesRects(dict);
|
||||
this._updateDynamicRangesRects(dict);
|
||||
// Create a DOM node for each rectangle representing the ranges we found.
|
||||
let maskContent = [];
|
||||
const kRectClassName = kModalIdPrefix + "-findbar-modalHighlight-rect";
|
||||
const rectStyle = this._getStyleString(kModalStyles.maskRect,
|
||||
dict.brightText ? kModalStyles.maskRectBrightText : []);
|
||||
for (let [range, rects] of dict.modalHighlightRectsMap) {
|
||||
if (dict.updateAllRanges)
|
||||
rects = this._updateRangeRects(range);
|
||||
for (let rect of rects) {
|
||||
maskContent.push(`<div class="${kRectClassName}" style="top: ${rect.y}px;
|
||||
maskContent.push(`<div style="${rectStyle}; top: ${rect.y}px;
|
||||
left: ${rect.x}px; height: ${rect.height}px; width: ${rect.width}px;"></div>`);
|
||||
}
|
||||
}
|
||||
|
@ -1033,8 +1012,8 @@ FinderHighlighter.prototype = {
|
|||
* meantime. This happens when the DOM is updated
|
||||
* whilst the page is loaded.
|
||||
* {Boolean} scrollOnly TRUE when the page has scrolled in the meantime,
|
||||
* which means that the fixed positioned elements
|
||||
* need to be repainted.
|
||||
* which means that the dynamically positioned
|
||||
* elements need to be repainted.
|
||||
* {Boolean} updateAllRanges Whether to recalculate the rects of all ranges
|
||||
* that were found up until now.
|
||||
*/
|
||||
|
@ -1045,12 +1024,12 @@ FinderHighlighter.prototype = {
|
|||
|
||||
window = window.top;
|
||||
let dict = this.getForWindow(window);
|
||||
let repaintFixedNodes = (scrollOnly && !!dict.dynamicRangesSet.size);
|
||||
let repaintDynamicRanges = (scrollOnly && !!dict.dynamicRangesSet.size);
|
||||
|
||||
// When we request to repaint unconditionally, we mean to call
|
||||
// `_repaintHighlightAllMask()` right after the timeout.
|
||||
if (!dict.unconditionalRepaintRequested)
|
||||
dict.unconditionalRepaintRequested = !contentChanged || repaintFixedNodes;
|
||||
dict.unconditionalRepaintRequested = !contentChanged || repaintDynamicRanges;
|
||||
// Some events, like a resize, call for recalculation of all the rects of all ranges.
|
||||
if (!dict.updateAllRanges)
|
||||
dict.updateAllRanges = updateAllRanges;
|
||||
|
@ -1078,29 +1057,6 @@ FinderHighlighter.prototype = {
|
|||
}, kModalHighlightRepaintFreqMs);
|
||||
},
|
||||
|
||||
/**
|
||||
* The outline that shows/ highlights the current found range is styled and
|
||||
* animated using CSS. This style can be found in `kModalStyle`, but to have it
|
||||
* applied on any DOM node we insert using the AnonymousContent API we need to
|
||||
* inject an agent sheet into the document.
|
||||
*
|
||||
* @param {nsIDOMWindow} window
|
||||
*/
|
||||
_maybeInstallStyleSheet(window) {
|
||||
window = window.top;
|
||||
let dict = this.getForWindow(window);
|
||||
let document = window.document;
|
||||
if (dict.installedSheet == document)
|
||||
return;
|
||||
|
||||
let dwu = this._getDWU(window);
|
||||
let uri = this.modalStyleSheetURI;
|
||||
try {
|
||||
dwu.loadSheetUsingURIString(uri, dwu.AGENT_SHEET);
|
||||
} catch (e) {}
|
||||
dict.installedSheet = document;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add event listeners to the content which will cause the modal highlight
|
||||
* AnonymousContent to be re-painted or hidden.
|
||||
|
|
|
@ -200,10 +200,9 @@ RemoteFinder.prototype = {
|
|||
shiftKey: aEvent.shiftKey });
|
||||
},
|
||||
|
||||
requestMatchesCount: function (aSearchString, aMatchLimit, aLinksOnly) {
|
||||
requestMatchesCount: function (aSearchString, aLinksOnly) {
|
||||
this._browser.messageManager.sendAsyncMessage("Finder:MatchesCount",
|
||||
{ searchString: aSearchString,
|
||||
matchLimit: aMatchLimit,
|
||||
linksOnly: aLinksOnly });
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +321,7 @@ RemoteFinderListener.prototype = {
|
|||
break;
|
||||
|
||||
case "Finder:MatchesCount":
|
||||
this._finder.requestMatchesCount(data.searchString, data.matchLimit, data.linksOnly);
|
||||
this._finder.requestMatchesCount(data.searchString, data.linksOnly);
|
||||
break;
|
||||
|
||||
case "Finder:ModalHighlightChange":
|
||||
|
|
|
@ -5,6 +5,7 @@ AsyncShutdown
|
|||
==============
|
||||
|
||||
During shutdown of the process, subsystems are closed one after another. ``AsyncShutdown`` is a module dedicated to express shutdown-time dependencies between:
|
||||
|
||||
- services and their clients;
|
||||
- shutdown phases (e.g. profile-before-change) and their clients.
|
||||
|
||||
|
@ -14,11 +15,13 @@ Barriers: Expressing shutdown dependencies towards a service
|
|||
============================================================
|
||||
|
||||
Consider a service FooService. At some point during the shutdown of the process, this service needs to:
|
||||
|
||||
- inform its clients that it is about to shut down;
|
||||
- wait until the clients have completed their final operations based on FooService (often asynchronously);
|
||||
- only then shut itself down.
|
||||
|
||||
This may be expressed as an instance of ``AsyncShutdown.Barrier``. An instance of ``AsyncShutdown.Barrier`` provides:
|
||||
|
||||
- a capability ``client`` that may be published to clients, to let them register or unregister blockers;
|
||||
- methods for the owner of the barrier to let it consult the state of blockers and wait until all client-registered blockers have been resolved.
|
||||
|
||||
|
@ -33,6 +36,7 @@ mechanism helps ensure that we do not leave the process in a state in
|
|||
which it can neither proceed with shutdown nor be relaunched.
|
||||
|
||||
If the CrashReporter is enabled, this crash will report:
|
||||
|
||||
- the name of the barrier that failed;
|
||||
- for each blocker that has not been released yet:
|
||||
|
||||
|
@ -219,6 +223,7 @@ Phases: Expressing dependencies towards phases of shutdown
|
|||
==========================================================
|
||||
|
||||
The shutdown of a process takes place by phase, such as:
|
||||
|
||||
- ``profileBeforeChange`` (once this phase is complete, there is no guarantee that the process has access to a profile directory);
|
||||
- ``webWorkersShutdown`` (once this phase is complete, JavaScript does not have access to workers anymore);
|
||||
- ...
|
||||
|
|
|
@ -1864,6 +1864,17 @@ UpdateService.prototype = {
|
|||
observe: function AUS_observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "post-update-processing":
|
||||
if (readStatusFile(getUpdatesDir()) == STATE_SUCCEEDED) {
|
||||
// The active update needs to be copied to the first update in the
|
||||
// updates.xml early during startup to support post update actions
|
||||
// (bug 1301288).
|
||||
let um = Cc["@mozilla.org/updates/update-manager;1"].
|
||||
getService(Ci.nsIUpdateManager);
|
||||
um.activeUpdate.state = STATE_SUCCEEDED;
|
||||
um.saveUpdates();
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_POSTUPDATE, true);
|
||||
}
|
||||
|
||||
if (Services.appinfo.ID in APPID_TO_TOPIC) {
|
||||
// Delay post-update processing to ensure that possible update
|
||||
// dialogs are shown in front of the app window, if possible.
|
||||
|
@ -2076,7 +2087,6 @@ UpdateService.prototype = {
|
|||
|
||||
// Update the patch's metadata.
|
||||
um.activeUpdate = update;
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_POSTUPDATE, true);
|
||||
|
||||
// Done with this update. Clean it up.
|
||||
cleanupActiveUpdate();
|
||||
|
|
Загрузка…
Ссылка в новой задаче