3 Copyright 2002, Apple, Inc. All rights reserved.
6 #import <WebKit/WebTextView.h>
8 #import <WebKit/WebAssertions.h>
9 #import <WebKit/WebBridge.h>
10 #import <WebKit/WebDataSourcePrivate.h>
11 #import <WebKit/WebDocumentInternal.h>
12 #import <WebKit/WebFramePrivate.h>
13 #import <WebKit/WebFrameView.h>
14 #import <WebKit/WebNSObjectExtras.h>
15 #import <WebKit/WebNSURLExtras.h>
16 #import <WebKit/WebNSViewExtras.h>
17 #import <WebKit/WebPreferences.h>
18 #import <WebKit/WebTextRendererFactory.h>
19 #import <WebKit/WebViewPrivate.h>
21 #import <Foundation/NSURLResponse.h>
23 @interface NSTextView (AppKitSecret)
24 + (NSURL *)_URLForString:(NSString *)string;
27 @interface WebTextView (ForwardDeclarations)
28 - (void)_updateTextSizeMultiplier;
31 @interface WebTextView (TextSizing) <_web_WebDocumentTextSizing>
34 @implementation WebTextView
36 + (NSArray *)unsupportedTextMIMETypes
38 return [NSArray arrayWithObjects:
39 @"text/calendar", // iCal
43 @"text/vcard", // vCard
46 @"text/ldif", // Netscape Address Book
47 @"text/qif", // Quicken
49 @"text/x-csv", // CSV (for Address Book and Microsoft Outlook)
50 @"text/x-vcf", // vCard type used in Sun affinity app
54 - (id)initWithFrame:(NSRect)frame
56 self = [super initWithFrame:frame];
58 _textSizeMultiplier = 1.0;
59 [self setAutoresizingMask:NSViewWidthSizable];
60 [self setEditable:NO];
61 [[NSNotificationCenter defaultCenter] addObserver:self
62 selector:@selector(defaultsChanged:)
63 name:WebPreferencesChangedNotification
71 [[NSNotificationCenter defaultCenter] removeObserver:self];
77 [[NSNotificationCenter defaultCenter] removeObserver:self];
81 - (float)_textSizeMultiplierFromWebView
83 // Note that we are not guaranteed to be the subview of a WebView at any given time.
84 WebView *webView = [self _web_parentWebView];
85 return webView ? [webView textSizeMultiplier] : 1.0;
88 - (WebPreferences *)_preferences
90 // Handle nil result because we might not be in a WebView at any given time.
91 WebPreferences *preferences = [[self _web_parentWebView] preferences];
92 if (preferences == nil) {
93 preferences = [WebPreferences standardPreferences];
99 - (void)setFixedWidthFont
101 WebPreferences *preferences = [self _preferences];
102 NSString *families[2];
103 families[0] = [preferences fixedFontFamily];
105 NSFont *font = [[WebTextRendererFactory sharedFactory] fontWithFamilies:families
107 size:[preferences defaultFixedFontSize]*_textSizeMultiplier];
113 // This method was borrowed from Mail and changed to use ratios rather than deltas.
114 // Also, I removed the isEditable clause since RTF displayed in WebKit is never editable.
115 - (void)_adjustRichTextFontSizeByRatio:(float)ratio
117 NSTextStorage *storage = [self textStorage];
118 NSRange remainingRange = NSMakeRange(0, [storage length]);
120 while (remainingRange.length > 0) {
121 NSRange effectiveRange;
122 NSFont *font = [storage attribute:NSFontAttributeName atIndex:remainingRange.location longestEffectiveRange:&effectiveRange inRange:remainingRange];
125 font = [[NSFontManager sharedFontManager] convertFont:font toSize:[font pointSize]*ratio];
126 [storage addAttribute:NSFontAttributeName value:font range:effectiveRange];
128 if (NSMaxRange(effectiveRange) < NSMaxRange(remainingRange)) {
129 remainingRange.length = NSMaxRange(remainingRange) - NSMaxRange(effectiveRange);
130 remainingRange.location = NSMaxRange(effectiveRange);
137 - (void)_updateTextSizeMultiplier
139 float newMultiplier = [self _textSizeMultiplierFromWebView];
140 if (newMultiplier == _textSizeMultiplier) {
144 float oldMultiplier = _textSizeMultiplier;
145 _textSizeMultiplier = newMultiplier;
147 if ([self isRichText]) {
148 [self _adjustRichTextFontSizeByRatio:newMultiplier/oldMultiplier];
150 [self setFixedWidthFont];
154 - (void)setDataSource:(WebDataSource *)dataSource
156 [self setRichText:[[[dataSource response] MIMEType] isEqualToString:@"text/rtf"]];
158 float oldMultiplier = _textSizeMultiplier;
159 [self _updateTextSizeMultiplier];
160 // If the multiplier didn't change, we still need to update the fixed-width font.
161 // If the multiplier did change, this was already handled.
162 if (_textSizeMultiplier == oldMultiplier && ![self isRichText]) {
163 [self setFixedWidthFont];
168 // We handle incoming data here rather than in dataSourceUpdated because we
169 // need to distinguish the last hunk of received data from the whole glob
170 // of data received so far. This is a bad design in that it requires
171 // WebTextRepresentation to know that it's view is a WebTextView, but this
172 // bad design already existed.
173 - (void)appendReceivedData:(NSData *)data fromDataSource:(WebDataSource *)dataSource;
175 if ([self isRichText]) {
176 // FIXME: We should try to progressively load RTF.
177 [self replaceCharactersInRange:NSMakeRange(0, [[self string] length])
178 withRTF:[dataSource data]];
179 if (_textSizeMultiplier != 1.0) {
180 [self _adjustRichTextFontSizeByRatio:_textSizeMultiplier];
183 [self replaceCharactersInRange:NSMakeRange([[self string] length], 0)
184 withString:[dataSource _stringWithData:data]];
189 - (void)dataSourceUpdated:(WebDataSource *)dataSource
193 - (void)viewDidMoveToSuperview
195 NSView *superview = [self superview];
197 [self setFrameSize:NSMakeSize([superview frame].size.width, [self frame].size.height)];
201 - (void)setNeedsLayout:(BOOL)flag
210 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
215 - (void)viewDidMoveToHostWindow
220 - (void)defaultsChanged:(NSNotification *)notification
222 // We use the default fixed-width font, but rich text
223 // pages specify their own fonts
224 if (![self isRichText]) {
225 [self setFixedWidthFont];
229 - (BOOL)canTakeFindStringFromSelection
231 return [self isSelectable] && [self selectedRange].length && ![self hasMarkedText];
235 - (IBAction)takeFindStringFromSelection:(id)sender
237 if (![self canTakeFindStringFromSelection]) {
242 // Note: can't use writeSelectionToPasteboard:type: here, though it seems equivalent, because
243 // it doesn't declare the types to the pasteboard and thus doesn't bump the change count
244 [self writeSelectionToPasteboard:[NSPasteboard pasteboardWithName:NSFindPboard]
245 types:[NSArray arrayWithObject:NSStringPboardType]];
248 - (BOOL)supportsTextEncoding
255 return [super string];
258 - (NSAttributedString *)attributedString
260 return [self attributedSubstringFromRange:NSMakeRange(0, [[self string] length])];
263 - (NSString *)selectedString
265 return [[self string] substringWithRange:[self selectedRange]];
268 - (NSAttributedString *)selectedAttributedString
270 return [self attributedSubstringFromRange:[self selectedRange]];
275 [self setSelectedRange:NSMakeRange(0, [[self string] length])];
280 [self setSelectedRange:NSMakeRange(0,0)];
283 - (void)keyDown:(NSEvent *)event
285 [[self nextResponder] keyDown:event];
288 - (void)keyUp:(NSEvent *)event
290 [[self nextResponder] keyUp:event];
293 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
295 WebFrame *frame = [[self _web_parentWebFrameView] webFrame];
298 NSPoint screenPoint = [[self window] convertBaseToScreen:windowPoint];
299 BOOL isPointSelected = NSLocationInRange([self characterIndexForPoint:screenPoint], [self selectedRange]);
300 return [NSDictionary dictionaryWithObjectsAndKeys:
301 [NSNumber numberWithBool:isPointSelected], WebElementIsSelectedKey,
302 frame, WebElementFrameKey, nil];
305 - (NSDictionary *)elementAtPoint:(NSPoint)point
307 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
310 - (NSMenu *)menuForEvent:(NSEvent *)event
312 WebView *webView = [self _web_parentWebView];
314 return [webView _menuForElement:[self _elementAtWindowPoint:[event locationInWindow]]];
317 - (NSArray *)pasteboardTypesForSelection
319 return [self writablePasteboardTypes];
322 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
324 [self writeSelectionToPasteboard:pasteboard types:types];
327 // This approach could be relaxed when dealing with 3228554
328 - (BOOL)resignFirstResponder
330 BOOL resign = [super resignFirstResponder];
332 [self setSelectedRange:NSMakeRange(0,0)];
337 - (void)clickedOnLink:(id)link atIndex:(unsigned)charIndex
340 if ([link isKindOfClass:[NSURL class]]) {
342 } else if ([link isKindOfClass:[NSString class]]) {
343 URL = [[self class] _URLForString:(NSString *)link];
346 // Call the bridge because this is where our security checks are made.
347 WebFrame *frame = [[self _web_parentWebFrameView] webFrame];
348 [[frame _bridge] loadURL:URL
349 referrer:[[[[frame dataSource] request] URL] _web_originalDataAsString]
353 triggeringEvent:[[self window] currentEvent]
359 #pragma mark PRINTING
361 - (void)drawPageBorderWithSize:(NSSize)borderSize
363 ASSERT(NSEqualSizes(borderSize, [[[NSPrintOperation currentOperation] printInfo] paperSize]));
364 [[self _web_parentWebView] _drawHeaderAndFooter];
367 - (BOOL)knowsPageRange:(NSRangePointer)range {
368 // Waiting for beginDocument to adjust the printing margins is too late.
369 [[self _web_parentWebView] _adjustPrintingMarginsForHeaderAndFooter];
370 return [super knowsPageRange:range];
373 - (BOOL)canPrintHeadersAndFooters
380 @implementation WebTextView (TextSizing)
382 - (void)_web_textSizeMultiplierChanged
384 [self _updateTextSizeMultiplier];