merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-09-09 12:01:21 +02:00
Родитель fadd103e03 00b6191463
Коммит 89dba842cb
45 изменённых файлов: 1797 добавлений и 1487 удалений

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

@ -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();