+2007-04-17 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Tim Hatcher
+
+ - fixed <rdar://problem/5138492> Safari doesn't remember some changes to the PDF scale and display mode
+
+ Some of the user interactions that could change the PDF scale and display mode were not going through
+ the proxy mechanism in WebPDFView that updates preferences. Now we also listen to PDFKit notifications
+ in order to catch the other cases.
+
+ * WebView/WebPDFView.h:
+ new _ignoreScaleAndDisplayModeNotifications and _updatePreferencesTimer ivars
+
+ * WebView/WebPDFView.mm:
+ (-[WebPDFView setPDFDocument:]):
+ ignore scale and display mode notifications while we're setting up a fresh document
+ (-[WebPDFView dealloc]):
+ cancel the new timer (which releases it)
+ (-[WebPDFView viewDidMoveToWindow]):
+ listen for two PDFKit notifications
+ (-[WebPDFView viewWillMoveToWindow:]):
+ stop listening to the two PDFKit notifications
+ (-[WebPDFView _applyPDFDefaults]):
+ white space change
+ (-[WebPDFView _cancelUpdatePreferencesTimer]):
+ invalidate, release, and nil out the timer
+ (-[WebPDFView _scaleOrDisplayModeChanged:]):
+ update preferences soon, unless deliberately ignoring these notifications
+ (-[WebPDFView _updatePreferencesNow]):
+ cancel timer, then save data to preferences (code for saving the data was extracted from
+ -[PDFPrefUpdatingProxy forwardInvocation:])
+ (-[WebPDFView _updatePreferencesSoon]):
+ use timer to consolidate multiple calls into one action; formerly we were setting preferences
+ multiple times for some atomic user actions
+ (-[PDFPrefUpdatingProxy forwardInvocation:]):
+ call _updatePreferencesSoon where we used to immediately set preferences
+
2007-04-17 John Sullivan <sullivan@apple.com>
Reviewed by Kevin Decker
using namespace WebCore;
using namespace EventNames;
-#define PDFKitLaunchNotification @"PDFPreviewLaunchPreview"
+// Redeclarations of PDFKit notifications. We can't use the API since we use a weak link to the framework.
+#define _webkit_PDFKitLaunchNotification @"PDFPreviewLaunchPreview"
+#define _webkit_PDFViewDisplayModeChangedNotification @"PDFViewDisplayModeChanged"
+#define _webkit_PDFViewScaleChangedNotification @"PDFViewScaleChanged"
// QuartzPrivate.h doesn't include the PDFKit private headers, so we can't get at PDFViewPriv.h. (3957971)
// Even if that was fixed, we'd have to tweak compile options to include QuartzPrivate.h. (3957839)
+ (Class)_PDFViewClass;
- (BOOL)_anyPDFTagsFoundInMenu:(NSMenu *)menu;
- (void)_applyPDFDefaults;
+- (void)_cancelUpdatePreferencesTimer;
- (BOOL)_canLookUpInDictionary;
- (NSEvent *)_fakeKeyEventWithFunctionKey:(unichar)functionKey;
- (NSMutableArray *)_menuItemsFromPDFKitForEvent:(NSEvent *)theEvent;
- (NSAttributedString *)_scaledAttributedString:(NSAttributedString *)unscaledAttributedString;
- (NSString *)_temporaryPDFDirectoryPath;
- (void)_trackFirstResponder;
+- (void)_updatePreferencesSoon;
@end;
// PDFPrefUpdatingProxy is a class that forwards everything it gets to a target and updates the PDF viewing prefs
- (void)setPDFDocument:(PDFDocument *)doc
{
+ // Both setDocument: and _applyPDFDefaults will trigger scale and mode-changed notifications.
+ // Those aren't reflecting user actions, so we need to ignore them.
+ _ignoreScaleAndDisplayModeNotifications = YES;
[PDFSubview setDocument:doc];
[self _applyPDFDefaults];
+ _ignoreScaleAndDisplayModeNotifications = NO;
}
#pragma mark NSObject OVERRIDES
- (void)dealloc
{
ASSERT(!trackedFirstResponder);
+ [self _cancelUpdatePreferencesTimer];
[previewView release];
[PDFSubview release];
[path release];
name:NSWindowDidUpdateNotification
object:newWindow];
+ [notificationCenter addObserver:self
+ selector:@selector(_scaleOrDisplayModeChanged:)
+ name:_webkit_PDFViewScaleChangedNotification
+ object:PDFSubview];
+
+ [notificationCenter addObserver:self
+ selector:@selector(_scaleOrDisplayModeChanged:)
+ name:_webkit_PDFViewDisplayModeChangedNotification
+ object:PDFSubview];
+
if (previewView)
[notificationCenter addObserver:self
selector:@selector(_receivedPDFKitLaunchNotification:)
- name:PDFKitLaunchNotification
+ name:_webkit_PDFKitLaunchNotification
object:previewView];
}
[notificationCenter removeObserver:self
name:NSWindowDidUpdateNotification
object:oldWindow];
+ [notificationCenter removeObserver:self
+ name:_webkit_PDFViewScaleChangedNotification
+ object:PDFSubview];
+ [notificationCenter removeObserver:self
+ name:_webkit_PDFViewDisplayModeChangedNotification
+ object:PDFSubview];
if (previewView)
[notificationCenter removeObserver:self
- name:PDFKitLaunchNotification
+ name:_webkit_PDFKitLaunchNotification
object:previewView];
[trackedFirstResponder release];
[PDFSubview setAutoScales:NO];
[PDFSubview setScaleFactor:scaleFactor];
}
- [PDFSubview setDisplayMode:[prefs PDFDisplayMode]];
+ [PDFSubview setDisplayMode:[prefs PDFDisplayMode]];
+}
+
+- (void)_cancelUpdatePreferencesTimer
+{
+ [_updatePreferencesTimer invalidate];
+ [_updatePreferencesTimer release];
+ _updatePreferencesTimer = nil;
}
- (BOOL)_canLookUpInDictionary
[self _openWithFinder:self];
}
+- (void)_scaleOrDisplayModeChanged:(NSNotification *)notification
+{
+ ASSERT([notification object] == PDFSubview);
+ if (!_ignoreScaleAndDisplayModeNotifications)
+ [self _updatePreferencesSoon];
+}
+
- (NSAttributedString *)_scaledAttributedString:(NSAttributedString *)unscaledAttributedString
{
if (!unscaledAttributedString)
trackedFirstResponder = [newFirstResponder retain];
}
+- (void)_updatePreferencesNow
+{
+ [self _cancelUpdatePreferencesTimer];
+
+ WebPreferences *prefs = [[dataSource _webView] preferences];
+ float scaleFactor = [PDFSubview autoScales] ? 0.0f : [PDFSubview scaleFactor];
+ [prefs setPDFScaleFactor:scaleFactor];
+ [prefs setPDFDisplayMode:[PDFSubview displayMode]];
+}
+
+- (void)_updatePreferencesSoon
+{
+ // Consolidate calls; due to the PDFPrefUpdatingProxy method, this can be called multiple times with a single user action
+ // such as showing the context menu.
+ if (_updatePreferencesTimer)
+ return;
+
+ _updatePreferencesTimer = [[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(_updatePreferencesNow) userInfo:nil repeats:NO] retain];
+}
+
@end;
@implementation PDFPrefUpdatingProxy
- (void)forwardInvocation:(NSInvocation *)invocation
{
- PDFView *PDFSubview = [view _PDFSubview];
- [invocation invokeWithTarget:PDFSubview];
-
- WebPreferences *prefs = [[view->dataSource _webView] preferences];
- float scaleFactor = [PDFSubview autoScales] ? 0.0f : [PDFSubview scaleFactor];
- [prefs setPDFScaleFactor:scaleFactor];
- [prefs setPDFDisplayMode:[PDFSubview displayMode]];
+ [invocation invokeWithTarget:[view _PDFSubview]];
+ [view _updatePreferencesSoon];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel