/src/PluginInstance.mm
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