--- a/toolkit/modules/FinderHighlighter.jsm
+++ b/toolkit/modules/FinderHighlighter.jsm
@@ -757,23 +757,24 @@ FinderHighlighter.prototype = {
return false;
},
/**
* Read and store the rectangles that encompass the entire region of a range
* for use by the drawing function of the highlighter.
*
- * @param {nsIDOMRange} range Range to fetch the rectangles from
- * @param {Boolean} [checkIfDynamic] Whether we should check if the range
- * is dynamic as per the rules in
- * `_isInDynamicContainer()`. Optional,
- * defaults to `true`
- * @param {Object} [dict] Dictionary of properties belonging to
- * the currently active window
+ * @param {nsIDOMRange} range Range to fetch the rectangles from
+ * @param {Boolean} [checkIfDynamic] Whether we should check if the range
+ * is dynamic as per the rules in
+ * `_isInDynamicContainer()`. Optional,
+ * defaults to `true`
+ * @param {Object} [dict] Dictionary of properties belonging to
+ * the currently active window
+ * @return {Set} Set of rects that were found for the range
*/
_updateRangeRects(range, checkIfDynamic = true, dict = null) {
let window = range.startContainer.ownerDocument.defaultView;
let bounds;
// If the window is part of a frameset, try to cache the bounds query.
if (dict && dict.frames.has(window)) {
bounds = dict.frames.get(window);
if (!bounds) {
@@ -795,16 +796,17 @@ FinderHighlighter.prototype = {
x: dims.left + bounds.left
});
}
dict = dict || this.getForWindow(window.top);
dict.modalHighlightRectsMap.set(range, rects);
if (checkIfDynamic && this._isInDynamicContainer(range))
dict.dynamicRangesSet.add(range);
+ return rects;
},
/**
* Re-read the rectangles of the ranges that we keep track of separately,
* because they're enclosed by a position: fixed container DOM node.
*
* @param {Object} dict Dictionary of properties belonging to the currently
* active window
@@ -825,17 +827,17 @@ FinderHighlighter.prototype = {
* currently active window
* @param {Array} [textContent] Array of text that's inside the range. Optional,
* defaults to an empty array
* @param {Object} [fontStyle] Dictionary of CSS styles in camelCase as
* returned by `_getRangeFontStyle()`. Optional
*/
_updateRangeOutline(dict, textContent = [], fontStyle = null) {
let outlineNode = dict.modalHighlightOutline;
- let range = dict.currentFoundRange;
+ let range = this.finder._fastFind.getFoundRange();
if (!outlineNode || !range)
return;
let rect = range.getClientRects()[0];
if (!rect)
return;
if (!fontStyle)
fontStyle = this._getRangeFontStyle(range);
@@ -959,21 +961,24 @@ FinderHighlighter.prototype = {
if (paintContent || dict.modalHighlightAllMask) {
this._updateRangeOutline(dict);
this._updateFixedRangesRects(dict);
// Create a DOM node for each rectangle representing the ranges we found.
let maskContent = [];
const kRectClassName = kModalIdPrefix + "-findbar-modalHighlight-rect";
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;
left: ${rect.x}px; height: ${rect.height}px; width: ${rect.width}px;"></div>`);
}
}
+ dict.updateAllRanges = false;
maskNode.innerHTML = maskContent.join("");
}
// Always remove the current mask and insert it a-fresh, because we're not
// free to alter DOM nodes inside the CanvasFrame.
this._removeHighlightAllMask(window);
dict.modalHighlightAllMask = kDebug ?
@@ -1007,35 +1012,41 @@ FinderHighlighter.prototype = {
/**
* Doing a full repaint each time a range is delivered by the highlight iterator
* is way too costly, thus we pipe the frequency down to every
* `kModalHighlightRepaintFreqMs` milliseconds.
*
* @param {nsIDOMWindow} window
* @param {Object} options Dictionary of painter hints that contains the
* following properties:
- * {Boolean} contentChanged Whether the documents' content changed in the
- * 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.
+ * {Boolean} contentChanged Whether the documents' content changed in the
+ * 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.
+ * {Boolean} updateAllRanges Whether to recalculate the rects of all ranges
+ * that were found up until now.
*/
- _scheduleRepaintOfMask(window, { contentChanged, scrollOnly } = { contentChanged: false, scrollOnly: false }) {
+ _scheduleRepaintOfMask(window, { contentChanged, scrollOnly, updateAllRanges } =
+ { contentChanged: false, scrollOnly: false, updateAllRanges: false }) {
if (!this._modal)
return;
window = window.top;
let dict = this.getForWindow(window);
let repaintFixedNodes = (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;
+ // Some events, like a resize, call for recalculation of all the rects of all ranges.
+ if (!dict.updateAllRanges)
+ dict.updateAllRanges = updateAllRanges;
if (dict.modalRepaintScheduler)
return;
dict.modalRepaintScheduler = window.setTimeout(() => {
dict.modalRepaintScheduler = null;
if (dict.unconditionalRepaintRequested) {
@@ -1089,42 +1100,45 @@ FinderHighlighter.prototype = {
window = window.top;
let dict = this.getForWindow(window);
if (dict.highlightListeners)
return;
window = window.top;
dict.highlightListeners = [
this._scheduleRepaintOfMask.bind(this, window, { contentChanged: true }),
+ this._scheduleRepaintOfMask.bind(this, window, { updateAllRanges: true }),
this._scheduleRepaintOfMask.bind(this, window, { scrollOnly: true }),
this.hide.bind(this, window, null)
];
let target = this.iterator._getDocShell(window).chromeEventHandler;
target.addEventListener("MozAfterPaint", dict.highlightListeners[0]);
- target.addEventListener("DOMMouseScroll", dict.highlightListeners[1]);
- target.addEventListener("mousewheel", dict.highlightListeners[1]);
- target.addEventListener("click", dict.highlightListeners[2]);
+ target.addEventListener("resize", dict.highlightListeners[1]);
+ target.addEventListener("DOMMouseScroll", dict.highlightListeners[2]);
+ target.addEventListener("mousewheel", dict.highlightListeners[2]);
+ target.addEventListener("click", dict.highlightListeners[3]);
},
/**
* Remove event listeners from content.
*
* @param {nsIDOMWindow} window
*/
_removeModalHighlightListeners(window) {
window = window.top;
let dict = this.getForWindow(window);
if (!dict.highlightListeners)
return;
let target = this.iterator._getDocShell(window).chromeEventHandler;
target.removeEventListener("MozAfterPaint", dict.highlightListeners[0]);
- target.removeEventListener("DOMMouseScroll", dict.highlightListeners[1]);
- target.removeEventListener("mousewheel", dict.highlightListeners[1]);
- target.removeEventListener("click", dict.highlightListeners[2]);
+ target.removeEventListener("resize", dict.highlightListeners[1]);
+ target.removeEventListener("DOMMouseScroll", dict.highlightListeners[2]);
+ target.removeEventListener("mousewheel", dict.highlightListeners[2]);
+ target.removeEventListener("click", dict.highlightListeners[3]);
dict.highlightListeners = null;
},
/**
* For a given node returns its editable parent or null if there is none.
* It's enough to check if node is a text node and its parent's parent is
* instance of nsIDOMNSEditableElement.