Backed out 6 changesets (bug 384458) for frequent browser_FinderHighlighter.js failures

Backed out changeset ded915ec401f (bug 384458)
Backed out changeset 63ec66da50fa (bug 384458)
Backed out changeset ae71396d3be0 (bug 384458)
Backed out changeset 3b025cbfbe3c (bug 384458)
Backed out changeset 091c5465acf7 (bug 384458)
Backed out changeset 5eabde153def (bug 384458)
This commit is contained in:
Wes Kocher 2016-06-08 14:53:57 -07:00
Родитель 346739a504
Коммит 0adc8ded6e
18 изменённых файлов: 481 добавлений и 1519 удалений

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

@ -614,8 +614,6 @@ pref("accessibility.typeaheadfind", false);
pref("accessibility.typeaheadfind.timeout", 5000);
pref("accessibility.typeaheadfind.linksonly", false);
pref("accessibility.typeaheadfind.flashBar", 1);
pref("findbar.highlightAll", true);
pref("findbar.modalHighlight", true);
// Tracks when accessibility is loaded into the previous session.
pref("accessibility.loadedInLastSession", false);

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

@ -37,7 +37,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'foo',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 1,
numberOfMatches: 5,
}), `test ${testCount++}`);
@ -48,7 +48,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'foo',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 2,
numberOfMatches: 5,
}), `test ${testCount++}`);
@ -59,7 +59,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'foo',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 1,
numberOfMatches: 5,
}), `test ${testCount++}`);
@ -70,7 +70,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'xxx',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 0,
numberOfMatches: 0,
}), `test ${testCount++}`);
@ -81,7 +81,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'bar',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 1,
numberOfMatches: 4,
}), `test ${testCount++}`);
@ -92,7 +92,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'bar',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 2,
numberOfMatches: 4,
}), `test ${testCount++}`);
@ -103,7 +103,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'bar',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 3,
numberOfMatches: 4,
}), `test ${testCount++}`);
@ -114,7 +114,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'bar',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 4,
numberOfMatches: 4,
}), `test ${testCount++}`);
@ -125,7 +125,7 @@ function runTest() {
msg_name: "findchange",
active: true,
searchString: 'bar',
searchLimit: 1000,
searchLimit: 100,
activeMatchOrdinal: 1,
numberOfMatches: 4,
}), `test ${testCount++}`);

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

@ -856,10 +856,8 @@ pref("accessibility.typeaheadfind.prefillwithselection", false);
#else
pref("accessibility.typeaheadfind.prefillwithselection", true);
#endif
pref("accessibility.typeaheadfind.matchesCountTimeout", 100);
pref("accessibility.typeaheadfind.matchesCountLimit", 1000);
pref("findbar.highlightAll", false);
pref("findbar.modalHighlight", false);
pref("accessibility.typeaheadfind.matchesCountTimeout", 250);
pref("accessibility.typeaheadfind.matchesCountLimit", 100);
// use Mac OS X Appearance panel text smoothing setting when rendering text, disabled by default
pref("gfx.use_text_smoothing_setting", false);

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

@ -23,8 +23,6 @@ user_pref("browser.shell.checkDefaultBrowser", false);
user_pref("shell.checkDefaultClient", false);
user_pref("browser.warnOnQuit", false);
user_pref("accessibility.typeaheadfind.autostart", false);
user_pref("findbar.highlightAll", false);
user_pref("findbar.modalHighlight", false);
user_pref("javascript.options.showInConsole", true);
user_pref("devtools.browsertoolbox.panel", "jsdebugger");
user_pref("devtools.debugger.remote-port", 6023);

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

@ -11,7 +11,6 @@ support-files =
[browser_autoscroll_disabled.js]
[browser_bug295977_autoscroll_overflow.js]
[browser_bug451286.js]
skip-if = !e10s
[browser_bug594509.js]
[browser_bug982298.js]
[browser_bug1198465.js]

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

@ -20,7 +20,6 @@ add_task(function*() {
yield openFindBarAndWait();
gFindBar._findField.value = SEARCH_TEXT;
yield findAgainAndWait();
var matchCase = gFindBar.getElement("find-case-sensitive");
if (matchCase.checked)
matchCase.doCommand();
@ -119,21 +118,6 @@ function toggleHighlightAndWait(shouldHighlight) {
});
}
function findAgainAndWait() {
return new Promise(resolve => {
let listener = {
onFindResult() {
gFindBar.browser.finder.removeResultListener(listener);
resolve();
},
onHighlightFinished() {},
onMatchesCountResult() {}
};
gFindBar.browser.finder.addResultListener(listener);
gFindBar.onFindAgainCommand();
});
}
function* openFindBarAndWait() {
let awaitTransitionEnd = BrowserTestUtils.waitForEvent(gFindBar, "transitionend");
gFindBar.open();

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

@ -64,7 +64,7 @@
// Make sure the findfield is correctly focused on open
var searchStr = "text inside an input element";
yield promiseEnterStringIntoFindField(searchStr);
yield* enterStringIntoFindField(searchStr);
is(document.commandDispatcher.focusedElement,
gFindBar._findField.inputField, "Find field isn't focused");
@ -72,6 +72,12 @@
// when the find bar is closed.
gFindBar.close();
gFindBar.onFindAgainCommand(false);
// For remote browsers, the content document DOM tree is not accessible, thus
// the focused element should fall back to the browser element.
if (gBrowser.hasAttribute("remote")) {
is(document.commandDispatcher.focusedElement, gBrowser,
"Browser element isn't focused");
}
yield ContentTask.spawn(gBrowser, null, function* () {
Assert.equal(content.document.activeElement,
content.document.getElementById("input"), "Input Element isn't focused");
@ -87,30 +93,23 @@
"Focus was stolen from a chrome element");
}
function promiseFindResult(str = null) {
return new Promise(resolve => {
function* enterStringIntoFindField(aString) {
for (let i = 0; i < aString.length; i++) {
let event = document.createEvent("KeyEvents");
let promise = new Promise(resolve => {
let listener = {
onFindResult: function({ searchString }) {
if (str !== null && str != searchString) {
return;
}
onFindResult: function() {
gFindBar.browser.finder.removeResultListener(listener);
resolve();
}
};
gFindBar.browser.finder.addResultListener(listener);
});
}
function promiseEnterStringIntoFindField(str) {
let promise = promiseFindResult(str);
for (let i = 0; i < str.length; i++) {
let event = document.createEvent("KeyEvents");
event.initKeyEvent("keypress", true, true, null, false, false,
false, false, 0, str.charCodeAt(i));
false, false, 0, aString.charCodeAt(i));
gFindBar._findField.inputField.dispatchEvent(event);
yield promise;
}
return promise;
}
]]></script>
<textbox id="textbox"/>

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

@ -436,6 +436,7 @@
</property>
<field name="_lastSearchString">null</field>
<field name="_lastSearchHighlight">false</field>
<property name="webProgress"
readonly="true"

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

@ -124,6 +124,7 @@
</property>
<field name="_lastSearchString">null</field>
<field name="_lastSearchHighlight">false</field>
<property name="editortype"
onget="return this.getAttribute('editortype');"

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

@ -290,22 +290,12 @@
this._browser.finder.addResultListener(this);
this._findField.value = this._browser._lastSearchString;
this.toggleHighlight(this.browser._lastSearchHighlight);
}
return val;
]]></setter>
</property>
<field name="__prefsvc">null</field>
<property name="_prefsvc">
<getter><![CDATA[
if (!this.__prefsvc) {
this.__prefsvc = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
}
return this.__prefsvc;
]]></getter>
</property>
<field name="_observer"><![CDATA[({
_self: this,
@ -322,7 +312,8 @@
if (aTopic != "nsPref:changed")
return;
let prefsvc = this._self._prefsvc;
let prefsvc =
aSubject.QueryInterface(Components.interfaces.nsIPrefBranch);
switch (aPrefName) {
case "accessibility.typeaheadfind":
@ -334,14 +325,6 @@
case "accessibility.typeaheadfind.casesensitive":
this._self._setCaseSensitivity(prefsvc.getIntPref(aPrefName));
break;
case "findbar.highlightAll":
this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
break;
case "findbar.modalHighlight":
this._self._useModalHighlight = prefsvc.getBoolPref(aPrefName);
if (this._self.browser.finder)
this._self.browser.finder.onModalHighlightChange(this._self._useModalHighlight);
break;
}
}
})]]></field>
@ -357,7 +340,9 @@
this._foundURL = null;
let prefsvc = this._prefsvc;
let prefsvc =
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
this._quickFindTimeoutLength =
prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
@ -367,7 +352,6 @@
prefsvc.getIntPref("accessibility.typeaheadfind.matchesCountTimeout");
this._matchesCountLimit =
prefsvc.getIntPref("accessibility.typeaheadfind.matchesCountLimit");
this._useModalHighlight = prefsvc.getBoolPref("findbar.modalHighlight");
prefsvc.addObserver("accessibility.typeaheadfind",
this._observer, false);
@ -375,8 +359,6 @@
this._observer, false);
prefsvc.addObserver("accessibility.typeaheadfind.casesensitive",
this._observer, false);
prefsvc.addObserver("findbar.highlightAll", this._observer, false);
prefsvc.addObserver("findbar.modalHighlight", this._observer, false);
this._findAsYouType =
prefsvc.getBoolPref("accessibility.typeaheadfind");
@ -384,7 +366,6 @@
prefsvc.getBoolPref("accessibility.typeaheadfind.linksonly");
this._typeAheadCaseSensitive =
prefsvc.getIntPref("accessibility.typeaheadfind.casesensitive");
this._highlightAll = prefsvc.getBoolPref("findbar.highlightAll");
// Convenience
this.nsITypeAheadFind = Components.interfaces.nsITypeAheadFind;
@ -412,20 +393,17 @@
return;
this._destroyed = true;
if (this.browser.finder)
this.browser.finder.destroy();
this.browser = null;
let prefsvc = this._prefsvc;
let prefsvc =
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
prefsvc.removeObserver("accessibility.typeaheadfind",
this._observer);
prefsvc.removeObserver("accessibility.typeaheadfind.linksonly",
this._observer);
prefsvc.removeObserver("accessibility.typeaheadfind.casesensitive",
this._observer);
prefsvc.removeObserver("findbar.highlightAll", this._observer);
prefsvc.removeObserver("findbar.modalHighlight", this._observer);
// Clear all timers that might still be running.
this._cancelTimers();
@ -513,30 +491,19 @@
- Turns highlight on or off.
- @param aHighlight (boolean)
- Whether to turn the highlight on or off
- @param aFromPrefObserver (boolean)
- Whether the callee is the pref observer, which means we should
- not set the same pref again.
-->
<method name="toggleHighlight">
<parameter name="aHighlight"/>
<parameter name="aFromPrefObserver"/>
<body><![CDATA[
if (aHighlight === this._highlightAll) {
if (!this._dispatchFindEvent("highlightallchange"))
return;
}
this._highlightAll = aHighlight;
if (!this._dispatchFindEvent("highlightallchange")) {
return;
}
this._setHighlightAll(aHighlight, aFromPrefObserver);
let word = this._findField.value;
// Bug 429723. Don't attempt to highlight ""
if (aHighlight && !word)
return;
this.browser._lastSearchHighlight = aHighlight;
this.browser.finder.highlight(aHighlight, word);
// Update the matches count
@ -544,30 +511,6 @@
]]></body>
</method>
<!--
- Updates the highlight-all mode of the findbar and its UI.
- @param aHighlight (boolean)
- Whether to turn the highlight on or off.
- @param aFromPrefObserver (boolean)
- Whether the callee is the pref observer, which means we should
- not set the same pref again.
-->
<method name="_setHighlightAll">
<parameter name="aHighlight"/>
<parameter name="aFromPrefObserver"/>
<body><![CDATA[
if (typeof aHighlight != "boolean") {
aHighlight = this._highlightAll;
}
if (aHighlight !== this._highlightAll && !aFromPrefObserver) {
this._prefsvc.setBoolPref("findbar.highlightAll", aHighlight);
}
this._highlightAll = aHighlight;
let checkbox = this.getElement("highlight");
checkbox.checked = this._highlightAll;
]]></body>
</method>
<!--
- Updates the case-sensitivity mode of the findbar and its UI.
- @param [optional] aString
@ -699,7 +642,8 @@
this.setAttribute("noanim", true);
this.hidden = true;
this.browser.finder.onFindbarClose();
this.browser.finder.focusContent();
this.browser.finder.enableSelection();
this._cancelTimers();
@ -910,7 +854,6 @@
this.getElement("find-previous").hidden = showMinimalUI;
foundMatches.hidden = showMinimalUI || !foundMatches.value;
this._updateCaseSensitivity();
this._setHighlightAll();
if (showMinimalUI)
this._findField.classList.add("minimal");
@ -1065,7 +1008,7 @@
event.initCustomEvent("find" + aType, true, true, {
query: this._findField.value,
caseSensitive: !!this._typeAheadCaseSensitive,
highlightAll: this._highlightAll,
highlightAll: this.getElement("highlight").checked,
findPrevious: aFindPrevious
});
return this.dispatchEvent(event);
@ -1084,7 +1027,9 @@
<method name="startFind">
<parameter name="aMode"/>
<body><![CDATA[
let prefsvc = this._prefsvc;
let prefsvc =
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
let userWantsPrefill = true;
this.open(aMode);
@ -1162,16 +1107,10 @@
this._findFailedString = null;
// Ensure the stored SearchString is in sync with what we want to find
if (this._findField.value != this._browser.finder.searchString) {
if (this._findField.value != this._browser.finder.searchString)
this._find(this._findField.value);
} else {
else
this._findAgain(aFindPrevious);
if (this._useModalHighlight) {
this.open();
this._findField.select();
this._findField.focus();
}
}
return undefined;
]]></body>
@ -1192,7 +1131,9 @@
<method name="_onFindFieldFocus">
<body><![CDATA[
let prefsvc = this._prefsvc;
let prefsvc =
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
const kPref = "accessibility.typeaheadfind.prefillwithselection";
if (this.prefillWithSelection && prefsvc.getBoolPref(kPref))
return;
@ -1276,13 +1217,6 @@
]]></body>
</method>
<method name="onHighlightFinished">
<parameter name="result"/>
<body><![CDATA[
// Noop.
]]></body>
</method>
<method name="onCurrentSelection">
<parameter name="aSelectionString" />
<parameter name="aIsInitialSelection" />

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

@ -22,6 +22,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "ClipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
const kHighlightIterationSizeMax = 100;
const kSelectionMaxLen = 150;
function Finder(docShell) {
@ -32,7 +33,6 @@ function Finder(docShell) {
this._listeners = [];
this._previousLink = null;
this._searchString = null;
this._highlighter = null;
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress)
@ -40,19 +40,6 @@ function Finder(docShell) {
}
Finder.prototype = {
destroy: function() {
if (this._highlighter) {
this._highlighter.clear();
this._highlighter.hide();
}
this.listeners = [];
this._docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress)
.removeProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
this._listeners = [];
this._fastFind = this._docShell = this._previousLink = this._highlighter = null;
},
addResultListener: function (aListener) {
if (this._listeners.indexOf(aListener) === -1)
this._listeners.push(aListener);
@ -62,15 +49,12 @@ Finder.prototype = {
this._listeners = this._listeners.filter(l => l != aListener);
},
_notify: function (options) {
if (typeof options.storeResult != "boolean")
options.storeResult = true;
if (options.storeResult) {
this._searchString = options.searchString;
this.clipboardSearchString = options.searchString
_notify: function (aSearchString, aResult, aFindBackwards, aDrawOutline, aStoreResult = true) {
if (aStoreResult) {
this._searchString = aSearchString;
this.clipboardSearchString = aSearchString
}
this._outlineLink(options.drawOutline);
this._outlineLink(aDrawOutline);
let foundLink = this._fastFind.foundLink;
let linkURL = null;
@ -83,15 +67,18 @@ Finder.prototype = {
linkURL = TextToSubURIService.unEscapeURIForUI(docCharset, foundLink.href);
}
options.linkURL = linkURL;
options.rect = this._getResultRect();
options.searchString = this._searchString;
this.highlighter.update(options);
let data = {
result: aResult,
findBackwards: aFindBackwards,
linkURL: linkURL,
rect: this._getResultRect(),
searchString: this._searchString,
storeResult: aStoreResult
};
for (let l of this._listeners) {
try {
l.onFindResult(options);
l.onFindResult(data);
} catch (ex) {}
}
},
@ -121,14 +108,6 @@ Finder.prototype = {
this._fastFind.caseSensitive = aSensitive;
},
get highlighter() {
if (this._highlighter)
return this._highlighter;
const {FinderHighlighter} = Cu.import("resource://gre/modules/FinderHighlighter.jsm", {});
return this._highlighter = new FinderHighlighter(this);
},
_lastFindResult: null,
/**
@ -141,13 +120,7 @@ Finder.prototype = {
fastFind: function (aSearchString, aLinksOnly, aDrawOutline) {
this._lastFindResult = this._fastFind.find(aSearchString, aLinksOnly);
let searchString = this._fastFind.searchString;
this._notify({
searchString,
result: this._lastFindResult,
findBackwards: false,
findAgain: false,
drawOutline: aDrawOutline
});
this._notify(searchString, this._lastFindResult, false, aDrawOutline);
},
/**
@ -162,13 +135,7 @@ Finder.prototype = {
findAgain: function (aFindBackwards, aLinksOnly, aDrawOutline) {
this._lastFindResult = this._fastFind.findAgain(aFindBackwards, aLinksOnly);
let searchString = this._fastFind.searchString;
this._notify({
searchString,
result: this._lastFindResult,
findBackwards: aFindBackwards,
fidnAgain: true,
drawOutline: aDrawOutline
});
this._notify(searchString, this._lastFindResult, aFindBackwards, aDrawOutline);
},
/**
@ -186,22 +153,25 @@ Finder.prototype = {
return searchString;
},
highlight: Task.async(function* (aHighlight, aWord) {
this.highlighter.maybeAbort();
_notifyHighlightFinished: function(aHighlight) {
for (let l of this._listeners) {
try {
l.onHighlightFinished(aHighlight);
} catch (ex) {}
}
},
let found = yield this.highlighter.highlight(aHighlight, aWord, null);
this.highlighter.notifyFinished(aHighlight);
highlight: Task.async(function* (aHighlight, aWord) {
if (this._abortHighlight) {
this._abortHighlight();
}
let found = yield this._highlight(aHighlight, aWord, null);
this._notifyHighlightFinished(aHighlight);
if (aHighlight) {
let result = found ? Ci.nsITypeAheadFind.FIND_FOUND
: Ci.nsITypeAheadFind.FIND_NOTFOUND;
this._notify({
searchString: aWord,
result,
findBackwards: false,
findAgain: false,
drawOutline: false,
storeResult: false
});
this._notify(aWord, result, false, false, false);
}
}),
@ -260,7 +230,6 @@ Finder.prototype = {
removeSelection: function() {
this._fastFind.collapseSelection();
this.enableSelection();
this.highlighter.clear();
},
focusContent: function() {
@ -292,17 +261,6 @@ Finder.prototype = {
} catch (e) {}
},
onFindbarClose: function() {
this.focusContent();
this.enableSelection();
this.highlighter.hide();
},
onModalHighlightChange(useModalHighlight) {
if (this._highlighter)
this._highlighter.onModalHighlightChange(useModalHighlight);
},
keyPress: function (aEvent) {
let controller = this._getSelectionController(this._getWindow());
@ -476,6 +434,28 @@ Finder.prototype = {
}
},
_highlightIterator: Task.async(function* (aWord, aWindow, aOnFind) {
let count = 0;
for (let range of this._findIterator(aWord, aWindow)) {
aOnFind(range);
if (++count >= kHighlightIterationSizeMax) {
count = 0;
yield this._highlightSleep(0);
}
}
}),
_abortHighlight: null,
_highlightSleep: function(delay) {
return new Promise((resolve, reject) => {
this._abortHighlight = () => {
this._abortHighlight = null;
reject();
};
this._getWindow().setTimeout(resolve, delay);
});
},
/**
* Helper method for `_countMatchesInWindow` that recursively collects all
* visible (i)frames inside a window.
@ -618,6 +598,84 @@ Finder.prototype = {
}
},
_highlight: Task.async(function* (aHighlight, aWord, aWindow) {
let win = aWindow || this._getWindow();
let found = false;
for (let i = 0; win.frames && i < win.frames.length; i++) {
if (yield this._highlight(aHighlight, aWord, win.frames[i]))
found = true;
}
let controller = this._getSelectionController(win);
let doc = win.document;
if (!controller || !doc || !doc.documentElement) {
// Without the selection controller,
// we are unable to (un)highlight any matches
return found;
}
if (aHighlight) {
yield this._highlightIterator(aWord, win, aRange => {
this._highlightRange(aRange, controller);
found = true;
});
} else {
// First, attempt to remove highlighting from main document
let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
sel.removeAllRanges();
// Next, check our editor cache, for editors belonging to this
// document
if (this._editors) {
for (let x = this._editors.length - 1; x >= 0; --x) {
if (this._editors[x].document == doc) {
sel = this._editors[x].selectionController
.getSelection(Ci.nsISelectionController.SELECTION_FIND);
sel.removeAllRanges();
// We don't need to listen to this editor any more
this._unhookListenersAtIndex(x);
}
}
}
// Removing the highlighting always succeeds, so return true.
found = true;
}
return found;
}),
_highlightRange: function(aRange, aController) {
let node = aRange.startContainer;
let controller = aController;
let editableNode = this._getEditableNode(node);
if (editableNode)
controller = editableNode.editor.selectionController;
let findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
findSelection.addRange(aRange);
if (editableNode) {
// Highlighting added, so cache this editor, and hook up listeners
// to ensure we deal properly with edits within the highlighting
if (!this._editors) {
this._editors = [];
this._stateListeners = [];
}
let existingIndex = this._editors.indexOf(editableNode.editor);
if (existingIndex == -1) {
let x = this._editors.length;
this._editors[x] = editableNode.editor;
this._stateListeners[x] = this._createStateListener();
this._editors[x].addEditActionListener(this);
this._editors[x].addDocumentStateListener(this._stateListeners[x]);
}
}
},
_getSelectionController: function(aWindow) {
// display: none iframes don't have a selection controller, see bug 493658
try {
@ -640,6 +698,129 @@ Finder.prototype = {
return controller;
},
/*
* For a given node returns its editable parent or null if there is none.
* It's enough to check if aNode is a text node and its parent's parent is
* instance of nsIDOMNSEditableElement.
*
* @param aNode the node we want to check
* @returns the first node in the parent chain that is editable,
* null if there is no such node
*/
_getEditableNode: function (aNode) {
if (aNode.nodeType === aNode.TEXT_NODE && aNode.parentNode && aNode.parentNode.parentNode &&
aNode.parentNode.parentNode instanceof Ci.nsIDOMNSEditableElement) {
return aNode.parentNode.parentNode;
}
return null;
},
/*
* Helper method to unhook listeners, remove cached editors
* and keep the relevant arrays in sync
*
* @param aIndex the index into the array of editors/state listeners
* we wish to remove
*/
_unhookListenersAtIndex: function (aIndex) {
this._editors[aIndex].removeEditActionListener(this);
this._editors[aIndex]
.removeDocumentStateListener(this._stateListeners[aIndex]);
this._editors.splice(aIndex, 1);
this._stateListeners.splice(aIndex, 1);
if (!this._editors.length) {
delete this._editors;
delete this._stateListeners;
}
},
/*
* Remove ourselves as an nsIEditActionListener and
* nsIDocumentStateListener from a given cached editor
*
* @param aEditor the editor we no longer wish to listen to
*/
_removeEditorListeners: function (aEditor) {
// aEditor is an editor that we listen to, so therefore must be
// cached. Find the index of this editor
let idx = this._editors.indexOf(aEditor);
if (idx == -1)
return;
// Now unhook ourselves, and remove our cached copy
this._unhookListenersAtIndex(idx);
},
/*
* nsIEditActionListener logic follows
*
* We implement this interface to allow us to catch the case where
* the findbar found a match in a HTML <input> or <textarea>. If the
* user adjusts the text in some way, it will no longer match, so we
* want to remove the highlight, rather than have it expand/contract
* when letters are added or removed.
*/
/*
* Helper method used to check whether a selection intersects with
* some highlighting
*
* @param aSelectionRange the range from the selection to check
* @param aFindRange the highlighted range to check against
* @returns true if they intersect, false otherwise
*/
_checkOverlap: function (aSelectionRange, aFindRange) {
// The ranges overlap if one of the following is true:
// 1) At least one of the endpoints of the deleted selection
// is in the find selection
// 2) At least one of the endpoints of the find selection
// is in the deleted selection
if (aFindRange.isPointInRange(aSelectionRange.startContainer,
aSelectionRange.startOffset))
return true;
if (aFindRange.isPointInRange(aSelectionRange.endContainer,
aSelectionRange.endOffset))
return true;
if (aSelectionRange.isPointInRange(aFindRange.startContainer,
aFindRange.startOffset))
return true;
if (aSelectionRange.isPointInRange(aFindRange.endContainer,
aFindRange.endOffset))
return true;
return false;
},
/*
* Helper method to determine if an edit occurred within a highlight
*
* @param aSelection the selection we wish to check
* @param aNode the node we want to check is contained in aSelection
* @param aOffset the offset into aNode that we want to check
* @returns the range containing (aNode, aOffset) or null if no ranges
* in the selection contain it
*/
_findRange: function (aSelection, aNode, aOffset) {
let rangeCount = aSelection.rangeCount;
let rangeidx = 0;
let foundContainingRange = false;
let range = null;
// Check to see if this node is inside one of the selection's ranges
while (!foundContainingRange && rangeidx < rangeCount) {
range = aSelection.getRangeAt(rangeidx);
if (range.isPointInRange(aNode, aOffset)) {
foundContainingRange = true;
break;
}
rangeidx++;
}
if (foundContainingRange)
return range;
return null;
},
/**
* Determines whether a range is inside a link.
* @param aRange
@ -684,7 +865,176 @@ Finder.prototype = {
// Avoid leaking if we change the page.
this._previousLink = null;
this.highlighter.onLocationChange();
},
// Start of nsIEditActionListener implementations
WillDeleteText: function (aTextNode, aOffset, aLength) {
let editor = this._getEditableNode(aTextNode).editor;
let controller = editor.selectionController;
let fSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
let range = this._findRange(fSelection, aTextNode, aOffset);
if (range) {
// Don't remove the highlighting if the deleted text is at the
// end of the range
if (aTextNode != range.endContainer ||
aOffset != range.endOffset) {
// Text within the highlight is being removed - the text can
// no longer be a match, so remove the highlighting
fSelection.removeRange(range);
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
}
}
},
DidInsertText: function (aTextNode, aOffset, aString) {
let editor = this._getEditableNode(aTextNode).editor;
let controller = editor.selectionController;
let fSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
let range = this._findRange(fSelection, aTextNode, aOffset);
if (range) {
// If the text was inserted before the highlight
// adjust the highlight's bounds accordingly
if (aTextNode == range.startContainer &&
aOffset == range.startOffset) {
range.setStart(range.startContainer,
range.startOffset+aString.length);
} else if (aTextNode != range.endContainer ||
aOffset != range.endOffset) {
// The edit occurred within the highlight - any addition of text
// will result in the text no longer being a match,
// so remove the highlighting
fSelection.removeRange(range);
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
}
}
},
WillDeleteSelection: function (aSelection) {
let editor = this._getEditableNode(aSelection.getRangeAt(0)
.startContainer).editor;
let controller = editor.selectionController;
let fSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
let selectionIndex = 0;
let findSelectionIndex = 0;
let shouldDelete = {};
let numberOfDeletedSelections = 0;
let numberOfMatches = fSelection.rangeCount;
// We need to test if any ranges in the deleted selection (aSelection)
// are in any of the ranges of the find selection
// Usually both selections will only contain one range, however
// either may contain more than one.
for (let fIndex = 0; fIndex < numberOfMatches; fIndex++) {
shouldDelete[fIndex] = false;
let fRange = fSelection.getRangeAt(fIndex);
for (let index = 0; index < aSelection.rangeCount; index++) {
if (shouldDelete[fIndex])
continue;
let selRange = aSelection.getRangeAt(index);
let doesOverlap = this._checkOverlap(selRange, fRange);
if (doesOverlap) {
shouldDelete[fIndex] = true;
numberOfDeletedSelections++;
}
}
}
// OK, so now we know what matches (if any) are in the selection
// that is being deleted. Time to remove them.
if (numberOfDeletedSelections == 0)
return;
for (let i = numberOfMatches - 1; i >= 0; i--) {
if (shouldDelete[i])
fSelection.removeRange(fSelection.getRangeAt(i));
}
// Remove listeners if no more highlights left
if (fSelection.rangeCount == 0)
this._removeEditorListeners(editor);
},
/*
* nsIDocumentStateListener logic follows
*
* When attaching nsIEditActionListeners, there are no guarantees
* as to whether the findbar or the documents in the browser will get
* destructed first. This leads to the potential to either leak, or to
* hold on to a reference an editable element's editor for too long,
* preventing it from being destructed.
*
* However, when an editor's owning node is being destroyed, the editor
* sends out a DocumentWillBeDestroyed notification. We can use this to
* clean up our references to the object, to allow it to be destroyed in a
* timely fashion.
*/
/*
* Unhook ourselves when one of our state listeners has been called.
* This can happen in 4 cases:
* 1) The document the editor belongs to is navigated away from, and
* the document is not being cached
*
* 2) The document the editor belongs to is expired from the cache
*
* 3) The tab containing the owning document is closed
*
* 4) The <input> or <textarea> that owns the editor is explicitly
* removed from the DOM
*
* @param the listener that was invoked
*/
_onEditorDestruction: function (aListener) {
// First find the index of the editor the given listener listens to.
// The listeners and editors arrays must always be in sync.
// The listener will be in our array of cached listeners, as this
// method could not have been called otherwise.
let idx = 0;
while (this._stateListeners[idx] != aListener)
idx++;
// Unhook both listeners
this._unhookListenersAtIndex(idx);
},
/*
* Creates a unique document state listener for an editor.
*
* It is not possible to simply have the findbar implement the
* listener interface itself, as it wouldn't have sufficient information
* to work out which editor was being destroyed. Therefore, we create new
* listeners on the fly, and cache them in sync with the editors they
* listen to.
*/
_createStateListener: function () {
return {
findbar: this,
QueryInterface: function(aIID) {
if (aIID.equals(Ci.nsIDocumentStateListener) ||
aIID.equals(Ci.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
NotifyDocumentWillBeDestroyed: function() {
this.findbar._onEditorDestruction(this);
},
// Unimplemented
notifyDocumentCreated: function() {},
notifyDocumentStateChanged: function(aDirty) {}
};
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -26,18 +26,6 @@ function RemoteFinder(browser) {
}
RemoteFinder.prototype = {
destroy() {
this._browser.messageManager.sendAsyncMessage("Finder:Destroy");
if (this._messageManager) {
this._messageManager.removeMessageListener("Finder:Result", this);
this._messageManager.removeMessageListener("Finder:MatchesResult", this);
this._messageManager.removeMessageListener("Finder:CurrentSelectionResult",this);
this._messageManager.removeMessageListener("Finder:HighlightFinished",this);
}
this._listeners.clear();
this._browser = this._messageManager = null;
},
swapBrowser: function(aBrowser) {
if (this._messageManager) {
this._messageManager.removeMessageListener("Finder:Result", this);
@ -175,16 +163,6 @@ RemoteFinder.prototype = {
this._browser.messageManager.sendAsyncMessage("Finder:FocusContent");
},
onFindbarClose: function () {
this._browser.messageManager.sendAsyncMessage("Finder:FindbarClose");
},
onModalHighlightChange: function(aUseModalHighlight) {
this._browser.messageManager.sendAsyncMessage("Finder:ModalHighlightChange", {
useModalHighlight: aUseModalHighlight
});
},
keyPress: function (aEvent) {
this._browser.messageManager.sendAsyncMessage("Finder:KeyPress",
{ keyCode: aEvent.keyCode,
@ -216,7 +194,6 @@ function RemoteFinderListener(global) {
RemoteFinderListener.prototype = {
MESSAGES: [
"Finder:CaseSensitive",
"Finder:Destroy",
"Finder:FastFind",
"Finder:FindAgain",
"Finder:SetSearchStringToSelection",
@ -225,10 +202,8 @@ RemoteFinderListener.prototype = {
"Finder:EnableSelection",
"Finder:RemoveSelection",
"Finder:FocusContent",
"Finder:FindbarClose",
"Finder:KeyPress",
"Finder:MatchesCount",
"Finder:ModalHighlightChange"
"Finder:MatchesCount"
],
onFindResult: function (aData) {
@ -249,10 +224,6 @@ RemoteFinderListener.prototype = {
let data = aMessage.data;
switch (aMessage.name) {
case "Finder:Destroy":
this._finder.destroy();
break;
case "Finder:CaseSensitive":
this._finder.caseSensitive = data.caseSensitive;
break;
@ -297,10 +268,6 @@ RemoteFinderListener.prototype = {
this._finder.focusContent();
break;
case "Finder:FindbarClose":
this._finder.onFindbarClose();
break;
case "Finder:KeyPress":
this._finder.keyPress(data);
break;
@ -308,10 +275,6 @@ RemoteFinderListener.prototype = {
case "Finder:MatchesCount":
this._finder.requestMatchesCount(data.searchString, data.matchLimit, data.linksOnly);
break;
case "Finder:ModalHighlightChange":
this._finder.ModalHighlightChange(data.useModalHighlight);
break;
}
}
};

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

@ -38,7 +38,6 @@ EXTRA_JS_MODULES += [
'Deprecated.jsm',
'FileUtils.jsm',
'Finder.jsm',
'FinderHighlighter.jsm',
'Geometry.jsm',
'GMPInstallManager.jsm',
'GMPUtils.jsm',

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

@ -26,8 +26,6 @@ support-files =
[browser_Deprecated.js]
[browser_Finder.js]
[browser_Finder_hidden_textarea.js]
[browser_FinderHighlighter.js]
skip-if = debug
[browser_Geometry.js]
[browser_InlineSpellChecker.js]
[browser_WebNavigation.js]

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

@ -1,188 +0,0 @@
"use strict";
Cu.import("resource://testing-common/BrowserTestUtils.jsm", this);
Cu.import("resource://testing-common/ContentTask.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this);
Cu.import("resource://gre/modules/AppConstants.jsm");
const kPrefModalHighlight = "findbar.modalHighlight";
function promiseOpenFindbar(findbar) {
findbar.onFindCommand()
return gFindBar._startFindDeferred && gFindBar._startFindDeferred.promise;
}
function promiseFindResult(findbar, str = null) {
return new Promise(resolve => {
let listener = {
onFindResult: function({ searchString }) {
if (str !== null && str != searchString) {
return;
}
findbar.browser.finder.removeResultListener(listener);
resolve();
}
};
findbar.browser.finder.addResultListener(listener);
});
}
function promiseEnterStringIntoFindField(findbar, str) {
let promise = promiseFindResult(findbar, str);
for (let i = 0; i < str.length; i++) {
let event = document.createEvent("KeyEvents");
event.initKeyEvent("keypress", true, true, null, false, false,
false, false, 0, str.charCodeAt(i));
findbar._findField.inputField.dispatchEvent(event);
}
return promise;
}
function promiseTestHighlighterOutput(browser, word, expectedResult) {
return ContentTask.spawn(browser, { word, expectedResult }, function* ({ word, expectedResult }) {
let document = content.document;
return new Promise((resolve, reject) => {
let stubbed = [document.insertAnonymousContent,
document.removeAnonymousContent];
let callCounts = {
insertCalls: [],
removeCalls: []
};
// Amount of milliseconds to wait after the last time one of our stubs
// was called.
const kTimeoutMs = 500;
// The initial timeout may wait for a while for results to come in.
let timeout = content.setTimeout(finish, kTimeoutMs * 4);
function finish(ok = true, message) {
// Restore the functions we stubbed out.
document.insertAnonymousContent = stubbed[0];
document.removeAnonymousContent = stubbed[1];
content.clearTimeout(timeout);
Assert.equal(callCounts.insertCalls.length, expectedResult.insertCalls,
`Insert calls should match for '${word}'.`);
Assert.equal(callCounts.removeCalls.length, expectedResult.removeCalls,
`Remove calls should match for '${word}'.`);
// We reached the amount of calls we expected, so now we can check
// the amount of rects.
let lastSVGNode = callCounts.insertCalls.pop();
if (!lastSVGNode && expectedResult.rectCount !== 0) {
Assert.ok(false, `No SVG node found, but expected ${expectedResult.rectCount} rects.`);
}
if (lastSVGNode) {
Assert.equal(lastSVGNode.getElementsByTagName("mask")[0]
.getElementsByTagName("rect").length, expectedResult.rectCount,
`Amount of inserted rects should match for '${word}'.`);
}
resolve();
}
// Create a function that will stub the original version and collects
// the arguments so we can check the results later.
function stub(which) {
let prop = which + "Calls";
return function(node) {
callCounts[prop].push(node);
content.clearTimeout(timeout);
timeout = content.setTimeout(finish, kTimeoutMs);
return node;
};
}
document.insertAnonymousContent = stub("insert");
document.removeAnonymousContent = stub("remove");
});
});
}
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({ set: [
["findbar.highlightAll", true],
["findbar.modalHighlight", true]
]});
});
// Test the results of modal highlighting, which is on by default.
add_task(function* testModalResults() {
let tests = new Map([
["mo", {
rectCount: 5,
insertCalls: 2,
removeCalls: AppConstants.platform == "linux" ? 1 : 2
}],
["m", {
rectCount: 9,
insertCalls: 1,
removeCalls: 1
}],
["new", {
rectCount: 2,
insertCalls: 1,
removeCalls: 1
}],
["o", {
rectCount: 1218,
insertCalls: 1,
removeCalls: 1
}]
]);
yield BrowserTestUtils.withNewTab("about:mozilla", function* (browser) {
// We're inserting 1200 additional o's at the end of the document.
yield ContentTask.spawn(browser, null, function* () {
let document = content.document;
document.getElementsByTagName("section")[0].innerHTML += "<p>" +
(new Array(1200).join(" o ")) + "</p>";
});
let findbar = gBrowser.getFindBar();
for (let [word, expectedResult] of tests) {
yield promiseOpenFindbar(findbar);
Assert.ok(!findbar.hidden, "Findbar should be open now.");
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
yield promiseEnterStringIntoFindField(findbar, word);
yield promise;
findbar.close();
}
});
});
// Test if runtime switching of highlight modes between modal and non-modal works
// as expected.
add_task(function* testModalSwitching() {
yield BrowserTestUtils.withNewTab("about:mozilla", function* (browser) {
let findbar = gBrowser.getFindBar();
yield promiseOpenFindbar(findbar);
Assert.ok(!findbar.hidden, "Findbar should be open now.");
let word = "mo";
let expectedResult = {
rectCount: 5,
insertCalls: 2,
removeCalls: AppConstants.platform == "linux" ? 1 : 2
};
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
yield promiseEnterStringIntoFindField(findbar, word);
yield promise;
yield SpecialPowers.pushPrefEnv({ "set": [[ kPrefModalHighlight, false ]] });
expectedResult = {
rectCount: 0,
insertCalls: 0,
removeCalls: 0
};
promise = promiseTestHighlighterOutput(browser, word, expectedResult);
findbar.clear();
yield promiseEnterStringIntoFindField(findbar, word);
yield promise;
});
});

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

@ -247,7 +247,6 @@ int32_t nsXPLookAndFeel::sCachedColorBits[COLOR_CACHE_SIZE] = {0};
bool nsXPLookAndFeel::sInitialized = false;
bool nsXPLookAndFeel::sUseNativeColors = true;
bool nsXPLookAndFeel::sUseStandinsForNativeColors = false;
bool nsXPLookAndFeel::sFindbarModalHighlight = false;
nsLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
bool nsXPLookAndFeel::sShutdown = false;
@ -466,9 +465,6 @@ nsXPLookAndFeel::Init()
Preferences::AddBoolVarCache(&sUseStandinsForNativeColors,
"ui.use_standins_for_native_colors",
sUseStandinsForNativeColors);
Preferences::AddBoolVarCache(&sFindbarModalHighlight,
"findbar.modalHighlight",
sFindbarModalHighlight);
if (XRE_IsContentProcess()) {
mozilla::dom::ContentChild* cc =
@ -777,11 +773,6 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
}
if (aID == eColorID_TextSelectBackgroundAttention) {
if (sFindbarModalHighlight) {
aResult = NS_RGBA(0, 0, 0, 0);
return NS_OK;
}
// This makes the selection stand out when typeaheadfind is on
// Used with nsISelectionController::SELECTION_ATTENTION
aResult = NS_RGB(0x38, 0xd8, 0x78);

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

@ -111,7 +111,6 @@ protected:
static int32_t sCachedColorBits[COLOR_CACHE_SIZE];
static bool sUseNativeColors;
static bool sUseStandinsForNativeColors;
static bool sFindbarModalHighlight;
static nsLookAndFeel* sInstance;
static bool sShutdown;