Merge pull request #5749 from krizsa/removeCPOWs

Bug 1072350 - Removing CPOWs used by Find events.
This commit is contained in:
Yury Delendik 2015-03-24 11:59:06 -05:00
commit 5cbb5004a3
2 changed files with 127 additions and 126 deletions

View File

@ -72,7 +72,7 @@ function getChromeWindow(domWindow) {
function getFindBar(domWindow) {
if (PdfjsContentUtils.isRemote) {
return PdfjsContentUtils.getFindBar(domWindow);
throw new Error('FindBar is not accessible from the content process.');
}
var browser = getContainingBrowser(domWindow);
try {
@ -397,7 +397,13 @@ ChromeActions.prototype = {
if (this.domWindow.frameElement !== null) {
return false;
}
// ... and when the new find events code exists.
// ... and we are in a child process
if (PdfjsContentUtils.isRemote) {
return true;
}
// ... or when the new find events code exists.
var findBar = getFindBar(this.domWindow);
return findBar && ('updateControlState' in findBar);
},
@ -499,7 +505,15 @@ ChromeActions.prototype = {
(findPreviousType !== 'undefined' && findPreviousType !== 'boolean')) {
return;
}
getFindBar(this.domWindow).updateControlState(result, findPrevious);
var winmm = this.domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
winmm.sendAsyncMessage('PDFJS:Parent:updateControlState', data);
},
setPreferences: function(prefs, sendResponse) {
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
@ -804,14 +818,14 @@ RequestListener.prototype.receive = function(event) {
// Forwards events from the eventElement to the contentWindow only if the
// content window matches the currently selected browser window.
function FindEventManager(eventElement, contentWindow, chromeWindow) {
this.types = ['find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'];
this.chromeWindow = chromeWindow;
function FindEventManager(contentWindow) {
this.contentWindow = contentWindow;
this.eventElement = eventElement;
this.winmm = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}
FindEventManager.prototype.bind = function() {
@ -821,41 +835,27 @@ FindEventManager.prototype.bind = function() {
}.bind(this);
this.contentWindow.addEventListener('unload', unload);
for (var i = 0; i < this.types.length; i++) {
var type = this.types[i];
this.eventElement.addEventListener(type, this, true);
}
// We cannot directly attach listeners to for the find events
// since the FindBar is in the parent process. Instead we're
// asking the PdfjsChromeUtils to do it for us and forward
// all the find events to us.
this.winmm.sendAsyncMessage('PDFJS:Parent:addEventListener');
this.winmm.addMessageListener('PDFJS:Child:handleEvent', this);
};
FindEventManager.prototype.handleEvent = function(e) {
var chromeWindow = this.chromeWindow;
FindEventManager.prototype.receiveMessage = function(msg) {
var detail = msg.data.detail;
var type = msg.data.type;
var contentWindow = this.contentWindow;
// Only forward the events if they are for our dom window.
if (chromeWindow.gBrowser.selectedBrowser.contentWindow === contentWindow) {
var detail = {
query: e.detail.query,
caseSensitive: e.detail.caseSensitive,
highlightAll: e.detail.highlightAll,
findPrevious: e.detail.findPrevious
};
detail = makeContentReadable(detail, contentWindow);
var forward = contentWindow.document.createEvent('CustomEvent');
forward.initCustomEvent(e.type, true, true, detail);
// Due to restrictions with cpow use, we can't dispatch
// dom events with an urgent message on the stack. So bounce
// this off the main thread to make it async.
Services.tm.mainThread.dispatch(function () {
contentWindow.dispatchEvent(forward);
}, Ci.nsIThread.DISPATCH_NORMAL);
e.preventDefault();
}
detail = makeContentReadable(detail, contentWindow);
var forward = contentWindow.document.createEvent('CustomEvent');
forward.initCustomEvent(type, true, true, detail);
contentWindow.dispatchEvent(forward);
};
FindEventManager.prototype.unbind = function() {
for (var i = 0; i < this.types.length; i++) {
var type = this.types[i];
this.eventElement.removeEventListener(type, this, true);
}
this.winmm.sendAsyncMessage('PDFJS:Parent:removeEventListener');
};
function PdfStreamConverter() {
@ -1019,11 +1019,7 @@ PdfStreamConverter.prototype = {
requestListener.receive(event);
}, false, true);
if (actions.supportsIntegratedFind()) {
var chromeWindow = getChromeWindow(domWindow);
var findBar = getFindBar(domWindow);
var findEventManager = new FindEventManager(findBar,
domWindow,
chromeWindow);
var findEventManager = new FindEventManager(domWindow);
findEventManager.bind();
}
listener.onStopRequest(aRequest, context, statusCode);

View File

@ -51,6 +51,7 @@ let PdfjsChromeUtils = {
*/
init: function () {
this._browsers = new Set();
if (!this._ppmm) {
// global parent process message manager (PPMM)
this._ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'].
@ -65,10 +66,12 @@ let PdfjsChromeUtils = {
// global dom message manager (MMg)
this._mmg = Cc['@mozilla.org/globalmessagemanager;1'].
getService(Ci.nsIMessageListenerManager);
this._mmg.addMessageListener('PDFJS:Parent:getChromeWindow', this);
this._mmg.addMessageListener('PDFJS:Parent:getFindBar', this);
this._mmg.addMessageListener('PDFJS:Parent:displayWarning', this);
this._mmg.addMessageListener('PDFJS:Parent:addEventListener', this);
this._mmg.addMessageListener('PDFJS:Parent:removeEventListener', this);
this._mmg.addMessageListener('PDFJS:Parent:updateControlState', this);
// observer to handle shutdown
Services.obs.addObserver(this, 'quit-application', false);
}
@ -84,10 +87,12 @@ let PdfjsChromeUtils = {
this._ppmm.removeMessageListener('PDFJS:Parent:isDefaultHandlerApp',
this);
this._mmg.removeMessageListener('PDFJS:Parent:getChromeWindow', this);
this._mmg.removeMessageListener('PDFJS:Parent:getFindBar', this);
this._mmg.removeMessageListener('PDFJS:Parent:displayWarning', this);
this._mmg.removeMessageListener('PDFJS:Parent:addEventListener', this);
this._mmg.removeMessageListener('PDFJS:Parent:removeEventListener', this);
this._mmg.removeMessageListener('PDFJS:Parent:updateControlState', this);
Services.obs.removeObserver(this, 'quit-application', false);
this._mmg = null;
@ -146,11 +151,13 @@ let PdfjsChromeUtils = {
this._displayWarning(aMsg);
break;
// CPOW getters
case 'PDFJS:Parent:getChromeWindow':
return this._getChromeWindow(aMsg);
case 'PDFJS:Parent:getFindBar':
return this._getFindBar(aMsg);
case 'PDFJS:Parent:updateControlState':
return this._updateControlState(aMsg);
case 'PDFJS:Parent:addEventListener':
return this._addEventListener(aMsg);
case 'PDFJS:Parent:removeEventListener':
return this._removeEventListener(aMsg);
}
},
@ -158,24 +165,81 @@ let PdfjsChromeUtils = {
* Internal
*/
_getChromeWindow: function (aMsg) {
// See the child module, our return result here can't be the element
// since return results don't get auto CPOW'd.
_findbarFromMessage: function(aMsg) {
let browser = aMsg.target;
let wrapper = new PdfjsWindowWrapper(browser);
let suitcase = aMsg.objects.suitcase;
suitcase.setChromeWindow(wrapper);
return true;
let tabbrowser = browser.getTabBrowser();
let tab = tabbrowser.getTabForBrowser(browser);
return tabbrowser.getFindBar(tab);
},
_getFindBar: function (aMsg) {
// We send this over via the window's message manager, so target should
// be the dom window.
_updateControlState: function (aMsg) {
let data = aMsg.data;
this._findbarFromMessage(aMsg)
.updateControlState(data.result, data.findPrevious);
},
handleEvent: function(aEvent) {
// We cannot just forward the message as a CPOW without setting up
// __exposedProps__ on it. Instead, let's just create a structured
// cloneable version of the event for performance and for the ease of usage.
let type = aEvent.type;
let detail = {
query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive,
highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious
};
let chromeWindow = aEvent.target.ownerDocument.defaultView;
let browser = chromeWindow.gBrowser.selectedBrowser;
if (this._browsers.has(browser)) {
// Only forward the events if the selected browser is a registered
// browser.
let mm = browser.messageManager;
mm.sendAsyncMessage('PDFJS:Child:handleEvent',
{ type: type, detail: detail });
aEvent.preventDefault();
}
},
_types: ['find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'],
_addEventListener: function (aMsg) {
let browser = aMsg.target;
let wrapper = new PdfjsFindbarWrapper(browser);
let suitcase = aMsg.objects.suitcase;
suitcase.setFindBar(wrapper);
return true;
if (this._browsers.has(browser)) {
throw new Error('FindEventManager was bound 2nd time ' +
'without unbinding it first.');
}
// Since this jsm is global, we need to store all the browsers
// we have to forward the messages for.
this._browsers.add(browser);
// And we need to start listening to find events.
for (var i = 0; i < this._types.length; i++) {
var type = this._types[i];
this._findbarFromMessage(aMsg)
.addEventListener(type, this, true);
}
},
_removeEventListener: function (aMsg) {
let browser = aMsg.target;
if (!this._browsers.has(browser)) {
throw new Error('FindEventManager was unbound without binding it first.');
}
this._browsers.delete(browser);
// No reason to listen to find events any longer.
for (var i = 0; i < this._types.length; i++) {
var type = this._types[i];
this._findbarFromMessage(aMsg)
.removeEventListener(type, this, true);
}
},
_ensurePreferenceAllowed: function (aPrefName) {
@ -268,62 +332,3 @@ let PdfjsChromeUtils = {
}
};
/*
* CPOW security features require chrome objects declare exposed
* properties via __exposedProps__. We don't want to expose things
* directly on the findbar, so we wrap the findbar in a smaller
* object here that supports the features pdf.js needs.
*/
function PdfjsFindbarWrapper(aBrowser) {
let tabbrowser = aBrowser.getTabBrowser();
let tab;
//#if MOZCENTRAL
tab = tabbrowser.getTabForBrowser(aBrowser);
//#else
if (tabbrowser.getTabForBrowser) {
tab = tabbrowser.getTabForBrowser(aBrowser);
} else {
// _getTabForBrowser is depreciated in Firefox 35, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1039500.
tab = tabbrowser._getTabForBrowser(aBrowser);
}
//#endif
this._findbar = tabbrowser.getFindBar(tab);
}
PdfjsFindbarWrapper.prototype = {
__exposedProps__: {
addEventListener: 'r',
removeEventListener: 'r',
updateControlState: 'r',
},
_findbar: null,
updateControlState: function (aResult, aFindPrevious) {
this._findbar.updateControlState(aResult, aFindPrevious);
},
addEventListener: function (aType, aListener, aUseCapture, aWantsUntrusted) {
this._findbar.addEventListener(aType, aListener, aUseCapture,
aWantsUntrusted);
},
removeEventListener: function (aType, aListener, aUseCapture) {
this._findbar.removeEventListener(aType, aListener, aUseCapture);
}
};
function PdfjsWindowWrapper(aBrowser) {
this._window = aBrowser.ownerDocument.defaultView;
}
PdfjsWindowWrapper.prototype = {
__exposedProps__: {
valueOf: 'r',
},
_window: null,
valueOf: function () {
return this._window.valueOf();
}
};