PageRenderTime 121ms CodeModel.GetById 40ms app.highlight 30ms RepoModel.GetById 28ms app.codeStats 1ms

/prebuilt/extension/components/PDFService.js

http://firefox-mac-pdf.googlecode.com/
JavaScript | 295 lines | 210 code | 39 blank | 46 comment | 47 complexity | 0bea677eeeb29508f024b5ffb2b5dbd2 MD5 | raw file
  1/*
  2 * Copyright (c) 2008 Samuel Gross.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 */
 22Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 23var consoleservice = Components.classes["@mozilla.org/consoleservice;1"].
 24     getService(Components.interfaces.nsIConsoleService);
 25function log(message) {
 26  consoleservice.logStringMessage(message);
 27}
 28
 29function findPluginWithId(window, plugin_id) {
 30  var embeds = window.document.embeds;
 31  
 32  if (embeds.length == 1) {
 33    if (embeds[0].wrappedJSObject.plugin_id == plugin_id) {
 34      return window;
 35    }
 36  }
 37  
 38  var frames = window.frames;
 39  for (var i = 0; i < frames.length; ++i) {
 40    var found = findPluginWithId(frames[i], plugin_id);
 41    if (found) {
 42      return found;
 43    }
 44  }
 45
 46  return null;
 47}
 48
 49function getWindowForPluginId(plugin_id) {
 50  var console = Components.classes["@mozilla.org/consoleservice;1"].
 51     getService(Components.interfaces.nsIConsoleService);
 52
 53  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
 54      getService(Components.interfaces.nsIWindowMediator);
 55  var enumerator = wm.getEnumerator("navigator:browser");
 56
 57  while(enumerator.hasMoreElements()) {
 58    var chromeWindow = enumerator.getNext();
 59    var browsers = chromeWindow.gBrowser.browsers;
 60
 61    for (var i = 0; i < browsers.length; ++i) {
 62      var window = browsers[i].contentWindow;
 63      var found = findPluginWithId(window, plugin_id);
 64      if (found) {
 65        return {window:found, chromeWindow:chromeWindow};
 66      }
 67    }
 68  }
 69
 70  return null;
 71}
 72
 73function getChromeWindowForPluginId(plugin_id) {
 74  for (var i = 0; i < plugins.length; i++) {
 75    if (plugins[i].plugin_id == plugin_id) {
 76      return plugins[i].chromeWindow;
 77    }
 78  }
 79  return null;
 80}
 81
 82function getTabBrowserForWindow(plugin_id) {
 83  var chromeWindow = getChromeWindowForPluginId(plugin_id);
 84  return chromeWindow && chromeWindow.gBrowser;
 85}
 86
 87function getPluginShim(chromeWindow) {
 88  var window = chromeWindow.gBrowser.contentWindow;
 89
 90  for (var i = 0; i < plugins.length; i++) {
 91    if (plugins[i].window == chromeWindow.gBrowser.contentWindow) {
 92      return plugins[i].plugin;
 93    }
 94  }
 95
 96  return null;
 97}
 98
 99var plugins = [];
100
101function PDFService() {
102};
103
104PDFService.prototype = {
105  classDescription: "Firefox PDF Plugin Service",
106  classID: Components.ID("{862827b0-98ac-4b68-a0c9-4ccd8ff35a02}"),
107  contractID: "@sgross.mit.edu/pdfservice;1",
108  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.PDFService]),
109
110  Init: function(plugin_id, plugin) {
111    var obj = getWindowForPluginId(plugin_id);
112    
113    if (obj == null) {
114      return;
115    }
116    
117    var window = obj.window;
118    var chromeWindow = obj.chromeWindow;
119    
120    plugins.push({plugin_id:plugin_id, plugin:plugin, window:window, chromeWindow:chromeWindow});
121
122    if (!chromeWindow.edu_mit_sgross_pdfplugin_swizzled) {
123      var browser = chromeWindow.gBrowser;
124      browser._fastFind = new FastFindShim(chromeWindow, browser._fastFind);
125
126      // also 'swizzle' the close function on the find bar to cause the elem to regain focus
127      var findBar = chromeWindow.gFindBar;
128      findBar.toggleHighlight = createFindbarToggleHighlight(chromeWindow, findBar.toggleHighlight);
129      findBar._setHighlightTimeout = createSetHighlightTimeout(chromeWindow, findBar._setHighlightTimeout);
130      
131      // route zoom commands to the plugin
132      var FullZoom = chromeWindow.FullZoom;
133      FullZoom.reduce = createZoom(chromeWindow, FullZoom.reduce, -1);
134      FullZoom.reset = createZoom(chromeWindow, FullZoom.reset, 0);
135      FullZoom.enlarge = createZoom(chromeWindow, FullZoom.enlarge, 1);
136      
137      chromeWindow.goDoCommand = createGoDoCommand(chromeWindow, chromeWindow.goDoCommand);
138
139      chromeWindow.edu_mit_sgross_pdfplugin_swizzled = true;
140    }
141    return;
142  },
143  
144  CleanUp: function(plugin_id) {
145    for (var i = 0; i < plugins.length; i++) {
146      var obj = plugins[i];
147      if (obj.plugin_id == plugin_id) {
148        plugins = plugins.slice(0, i).concat(plugins.slice(i+1, plugins.length));
149        return;
150      }
151    }
152  },
153  
154  FindPrevious: function(plugin_id) {
155      var chromeWindow = getChromeWindowForPluginId(plugin_id);
156      chromeWindow.gFindBar.onFindAgainCommand(true);
157  },
158  
159  Save: function(plugin_id, url) {
160    var chromeWindow = getChromeWindowForPluginId(plugin_id);
161    chromeWindow.internalSave(url, null, null, null, "application/pdf", false,
162               null, null, null, null);
163
164  }
165}
166
167/**
168 * Wraps a nsITypeAheadFind object to route find queries to the plugin when appropriate
169 */
170function FastFindShim(chromeWindow, fastfind) {
171  this.fastfind = fastfind;
172  this.chromeWindow = chromeWindow;
173  for (let prop in fastfind) {
174   if (fastfind.__lookupGetter__(prop)) {
175     this.__defineGetter__(prop, createDelegateGetter(chromeWindow, this.fastfind, prop));
176   }
177   if (fastfind.__lookupSetter__(prop)) {
178     this.__defineSetter__(prop, createDelegateSetter(chromeWindow, this.fastfind, prop));
179   }
180  }
181}
182
183/**
184 * Delegates gets to underlying fastfind.
185 */
186function createDelegateGetter(chromeWindow, fastfind, prop) {
187  if (prop == 'searchString') {
188    return function() {
189      // TODO: improve condition based on last search type (PDF versus HTML)
190      return getPluginShim(chromeWindow) ? this.lastSearchString : fastfind[prop];
191    }
192  }
193  return function() {
194    return fastfind[prop];
195  }
196}
197
198function createDelegateSetter(chromeWindow, fastfind, prop) {
199  return function(val) {
200    return fastfind[prop] = val;
201  }
202}
203
204/**
205 * Delegate all other methods to wrapped fastfind object.
206 */
207FastFindShim.prototype.__noSuchMethod__ = function(id, args) {
208  if (id == 'find' || id == 'findAgain') {
209    var plugin = getPluginShim(this.chromeWindow);
210    if (plugin) {
211      var str, reverse;
212      if (id == 'find') {
213        str = args[0];
214        reverse = false;
215      } else { // findAgain
216        str = this.lastSearchString;
217        reverse = args[0];
218      }
219      this.lastSearchString = str;
220      // find must take place before findAll because find cancels any current searches
221      var ret = plugin.Find(str, this.fastfind.caseSensitive, !reverse);
222      var findBar = this.chromeWindow.gFindBar;
223      if (findBar.getElement("highlight").checked) {
224        plugin.FindAll(str, this.fastfind.caseSensitive);
225      }
226      return ret;
227    }
228  }
229  return this.fastfind[id].apply(this.fastfind, args);
230}
231
232/**
233 * Creates a function that calls toggleHighlight on the plugin.
234 */
235function createFindbarToggleHighlight(chromeWindow, orig) {
236  return function(shouldHighlight) {
237    var plugin = getPluginShim(chromeWindow);
238    if (plugin) {
239      if (shouldHighlight) {
240        var word = this._findField.value;
241        // TODO: better choice for determining case sensitivity?
242        var caseSensitive = this._shouldBeCaseSensitive(word);
243        plugin.FindAll(word, caseSensitive);
244      } else {
245        plugin.RemoveHighlights();
246      }
247    } else {
248      orig.call(this, shouldHighlight);
249    }
250  };
251}
252
253/**
254 * Creates a function that only sets the highlight timeout when 
255 * the plugin is not present.
256 */
257function createSetHighlightTimeout(chromeWindow, orig) {
258  return function() {
259    if (!getPluginShim(chromeWindow)) {
260      orig.call(this);
261    }
262  };
263}
264
265function createZoom(chromeWindow, orig, arg) {
266  return function() {
267    var plugin = getPluginShim(chromeWindow);
268    if (plugin) {
269      plugin.Zoom(arg);
270    } else {
271      orig.call(this);
272    }
273  }
274}
275
276function createGoDoCommand(chromeWindow, orig) {
277  return function(cmd) {
278    var plugin;
279    if (cmd == 'cmd_copy' && (plugin = getPluginShim(chromeWindow))) {
280      plugin.Copy();
281    } else {
282      return orig.call(this, cmd);
283    }
284  }
285}
286
287var components = [PDFService];
288/**
289* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
290* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6).
291*/
292if (XPCOMUtils.generateNSGetFactory)
293    var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
294else
295    var NSGetModule = XPCOMUtils.generateNSGetModule(components);