PageRenderTime 262ms CodeModel.GetById 81ms app.highlight 4ms RepoModel.GetById 73ms app.codeStats 0ms

/src/PluginInstance.mm

http://firefox-mac-pdf.googlecode.com/
Objective C++ | 416 lines | 312 code | 62 blank | 42 comment | 48 complexity | 33e804b1e44de18e7ca999b23dd120ed 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 */
 22#import "PluginInstance.h"
 23#import "PluginPDFView.h"
 24#import "PluginProgressView.h"
 25#import "SelectionController.h"
 26#import "Preferences.h"
 27#import "PDFPluginShim.h"
 28
 29#include "PDFService.h"
 30#include "nsStringAPI.h"
 31
 32#ifndef NSAppKitVersionNumber10_4
 33#define NSAppKitVersionNumber10_4 824
 34#endif
 35
 36@interface PluginInstance (FileInternal)
 37- (void)_applyDefaults;
 38@end
 39
 40
 41@implementation PluginInstance
 42
 43- (id)initWithService:(PDFService*)pdfService plugin_id:(NSString*)plugin_id npp:(NPP)npp mimeType:(NSString*)mimeType;
 44{
 45  if (self = [super init]) {
 46    _npp = npp;
 47    _mimeType = [mimeType retain];
 48
 49    // load nib file
 50    [NSBundle loadNibNamed:@"PluginView" owner:self];
 51    pdfView = [pluginView pdfView];
 52
 53    // listen to scale changes
 54    [[NSNotificationCenter defaultCenter] 
 55        addObserver:self 
 56        selector:@selector(updatePreferences)
 57        name:PDFViewScaleChangedNotification
 58        object:pdfView];
 59
 60    [self _applyDefaults];
 61    
 62    selectionController = [[SelectionController forPDFView:pdfView] retain];
 63    _pdfService = pdfService;
 64    _pdfService->AddRef();
 65    _plugin_id = [plugin_id retain];
 66    _shim = new PDFPluginShim(self);
 67    _shim->AddRef();
 68    nsCAutoString idString([_plugin_id UTF8String]);
 69    nsresult r = _pdfService->Init(idString, _shim);
 70    if (r < 0) {
 71        NSLog(@"PDFService Init failed: %d", (int) r);
 72    }
 73  }
 74  return self;
 75}
 76
 77- (void)dealloc
 78{
 79  nsCAutoString idString([_plugin_id UTF8String]);
 80  
 81  if (pluginView) {
 82    [pluginView removeFromSuperview];
 83    [pluginView release];
 84  }
 85  if (progressView) {
 86    [progressView removeFromSuperview];
 87    [progressView release];
 88  }
 89  [parentView release];
 90  [selectionController release];
 91  [_searchResults release];
 92  [path release];
 93  _pdfService->CleanUp(idString);
 94  _shim->Release();
 95  _pdfService->Release();
 96  [_plugin_id release];
 97  [_url release];
 98  [_mimeType release];
 99  [_data release];
100  [super dealloc];
101}
102
103- (BOOL)attached
104{
105  return _attached;
106}
107
108- (void)attachToWindow:(NSWindow*)window at:(NSPoint)point
109{
110  // find the NSView at the point
111  NSView* hitView = [[window contentView] hitTest:NSMakePoint(point.x+1, point.y+1)];
112  if (hitView == nil || ![[hitView className] isEqualToString:@"ChildView"]) {
113    return;
114  }
115  parentView = [hitView retain];
116
117  [parentView addSubview:pluginView];
118  [pluginView setFrameSize:[parentView frame].size];
119  [pluginView setNextResponder:pdfView];
120  [pdfView setNextResponder:nil];
121
122  if (progressView) {
123    [parentView addSubview:progressView positioned:NSWindowAbove relativeTo:pluginView];
124    // set the next responder to nil to prevent infinite loop
125    // due to weirdness in event handling in nsChildView.mm
126    [progressView setNextResponder:nil];
127
128    int x = ([parentView frame].size.width - [progressView frame].size.width) / 2;
129    int y = ([parentView frame].size.height - [progressView frame].size.height) / 2;
130    [progressView setFrameOrigin:NSMakePoint(x, y)];
131  }
132
133  _attached = true;
134}
135
136- (void)print 
137{
138  [pdfView printWithInfo:[NSPrintInfo sharedPrintInfo] autoRotate:YES];
139}
140
141- (void)save
142{
143  nsCAutoString idString([_plugin_id UTF8String]);
144  nsCAutoString urlString([_url UTF8String]);
145  _pdfService->Save(idString, urlString);
146}
147
148- (void)requestFocus
149{
150//  if (![pluginView isHiddenOrHasHiddenAncestor]) {
151//    [[pluginView window] makeFirstResponder:[pdfView documentView]];
152//  }
153}
154
155- (void)setProgress:(int)progress total:(int)total
156{
157  if (progressView) {
158    [progressView setProgress:progress total:total];
159  }
160}
161
162- (void)downloadFailed
163{
164  NSLog(@"PDF plugin download failed");
165  if (progressView) {
166    [progressView downloadFailed];
167  }
168}
169
170- (void)setData:(NSData*)data
171{
172  if (progressView) {
173    [progressView removeFromSuperview];
174    [progressView release];
175    progressView = nil;
176  }
177
178  // create PDF document
179  _data = [data retain];
180  
181  NSData* pdfData;
182  if ([_mimeType isEqualToString:@"application/postscript"]) {
183    pdfData = [self convertPostScriptDataSourceToPDF:_data];
184  } else {
185    pdfData = _data;
186  }
187
188  PDFDocument* document = [[[PDFDocument alloc] initWithData:pdfData] autorelease];
189  [document setDelegate:self];
190  [pdfView setDocument:document];
191}
192
193- (void)_applyDefaults
194{
195  bool autoScales = [Preferences getBoolPreference:"autoScales"];
196  int displayMode = [Preferences getIntPreference:"displayMode"];
197  
198  [pdfView setAutoScales:autoScales];
199    
200  if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) {
201    [pdfView setScaleFactor:1.0];
202  } else {
203    if (!autoScales) {
204      float scaleFactor = [Preferences getFloatPreference:"scaleFactor"];
205      [pdfView setScaleFactor:scaleFactor];
206    }
207  }
208  
209  [pdfView setDisplayMode:displayMode];
210}
211
212- (void)updatePreferences
213{
214  if ([pdfView scaleFactor] == 20.0) {
215    // Mac OS 10.4 has a bug relating to saving the zoom level that manifest
216    // itself as zoom=20 and autoScales=false. I don't know the cause, but this
217    // seems to work around the issue.
218    return;
219  }
220
221  [Preferences setBoolPreference:"autoScales" value:[pdfView autoScales]];
222  [Preferences setFloatPreference:"scaleFactor" value:[pdfView scaleFactor]];
223  [Preferences setIntPreference:"displayMode" value:[pdfView displayMode]];
224}
225
226static bool selectionsAreEqual(PDFSelection* sel1, PDFSelection* sel2)
227{
228  NSArray* pages1 = [sel1 pages];
229  NSArray* pages2 = [sel2 pages];
230  if (![pages1 isEqual:pages2]) {
231    return false;
232  }
233  for (int i = 0; i < [pages1 count]; i++) {
234    if (!NSEqualRects([sel1 boundsForPage:[pages1 objectAtIndex:i]],
235                      [sel2 boundsForPage:[pages2 objectAtIndex:i]])) {
236      return false;
237    }
238  }
239  return true;
240}
241
242- (int)find:(NSString*)string caseSensitive:(bool)caseSensitive forwards:(bool)forwards
243{
244  const int FOUND = 0;
245  const int NOT_FOUND = 1;
246  const int WRAPPED = 2;
247  int ret;
248
249  PDFDocument* doc = [pdfView document];
250  if (!doc) {
251    return FOUND;
252  }
253
254  // only one search can take place at a time
255  if ([doc isFinding]) {
256    [doc cancelFindString];
257  }
258
259  if ([string length] == 0) {
260    [selectionController setCurrentSelection:nil];
261    return FOUND;
262  }
263
264  // see WebPDFView.mm in WebKit for general technique
265  PDFSelection* initialSelection = [[pdfView currentSelection] copy];
266  PDFSelection* searchSelection = [initialSelection copy];
267  
268  // collapse selection to before start/end
269  int length = [[searchSelection string] length];
270  if (forwards) {
271    [searchSelection extendSelectionAtStart:1];
272    [searchSelection extendSelectionAtEnd:-length];
273  } else {
274    [searchSelection extendSelectionAtEnd:1];
275    [searchSelection extendSelectionAtStart:-length];
276  }
277    
278  int options = 0;
279  options |= (caseSensitive ? 0 : NSCaseInsensitiveSearch);
280  options |= (forwards ? 0 : NSBackwardsSearch);
281
282  // search!
283  PDFSelection* result = [doc findString:string fromSelection:searchSelection withOptions:options];
284  [searchSelection release];
285  
286  // advance search if we get the same selection
287  if (result && initialSelection && selectionsAreEqual(result, initialSelection)) {
288    result = [doc findString:string fromSelection:initialSelection withOptions:options];
289  }
290  [initialSelection release];
291  
292  // wrap search
293  if (!result) {
294    result = [doc findString:string fromSelection:result withOptions:options];
295    ret = result ? WRAPPED : NOT_FOUND;
296  } else {
297    ret = FOUND;
298  }
299
300  // scroll to the selection
301  [selectionController setCurrentSelection:result];
302  return ret;
303}
304
305- (void)findPrevious
306{
307  nsCAutoString idString([_plugin_id UTF8String]);
308  _pdfService->FindPrevious(idString);
309}
310
311- (void)findAll:(NSString*)string caseSensitive:(bool)caseSensitive
312{
313  PDFDocument* doc = [pdfView document];
314  if ([doc isFinding]) {
315    [doc cancelFindString];
316  }
317  if ([string length] == 0) {
318    [selectionController setHighlightedSelections:nil];
319    return;
320  }
321  if (_searchResults == NULL) {
322    _searchResults = [[NSMutableArray arrayWithCapacity: 10] retain];
323  }
324  int options = (caseSensitive ? 0 : NSCaseInsensitiveSearch);
325  [doc beginFindString:string withOptions:options];
326}
327
328- (void)removeHighlights
329{
330  [selectionController setHighlightedSelections:nil];
331}
332
333- (void)documentDidBeginDocumentFind:(NSNotification *)notification
334{
335  [_searchResults removeAllObjects];
336}
337
338- (void)documentDidEndDocumentFind:(NSNotification *)notification
339{
340  [selectionController setHighlightedSelections:_searchResults];
341}
342
343- (void)didMatchString:(PDFSelection*)instance
344{
345  [_searchResults addObject: [instance copy]];
346}
347
348- (void)copy
349{
350  [pdfView copy:nil];
351}
352
353- (BOOL)zoom:(int)zoomArg
354{
355  switch (zoomArg) {
356    case -1:
357      [pdfView zoomOut:nil];
358      break;
359    case 0:
360      [pdfView setScaleFactor:1.0];
361      break;
362    case 1:
363      [pdfView zoomIn:nil];
364      break;
365    default:
366      return NO;
367  }
368  return YES;
369}
370
371- (void)setUrl:(NSString*)url
372{
373  [_url autorelease];
374  _url = [url retain];
375  if (progressView && url) {
376    NSString* filename = [[[NSURL URLWithString:url] path] lastPathComponent];
377    [progressView setFilename:filename];
378  }
379}
380
381- (void)setVisible:(bool)visible
382{
383  if ([pluginView inLiveResize]) {
384    return;
385  }
386  if (pluginView && _attached) {
387    if (visible && ![pluginView superview]) {
388      [pluginView setFrameSize:[parentView frame].size];
389      [parentView addSubview:pluginView positioned:NSWindowBelow relativeTo:nil];
390    } else if (!visible && [pluginView isHiddenOrHasHiddenAncestor]) {
391      [pluginView removeFromSuperviewWithoutNeedingDisplay];
392    }
393  }
394
395}
396
397// PDFView delegate methods
398
399- (void)PDFViewWillClickOnLink:(PDFView *)sender withURL:(NSURL *)url
400{
401  NPN_GetURL(_npp, [[url absoluteString] UTF8String], "_self");
402}
403
404// undocumented delegate methods
405
406- (void)PDFViewOpenPDFInNativeApplication:(PDFView*)sender
407{
408  [self openWithFinder];
409}
410
411- (void)PDFViewSavePDFToDownloadFolder:(PDFView*)sender
412{
413  [self save];
414}
415
416@end