60bfe6ced10af7e18c1b723e47d886776aa1f754
[WebKit-https.git] / Source / WebCore / editing / mac / EditorMac.mm
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "Editor.h"
28
29 #import "ColorMac.h"
30 #import "ClipboardMac.h"
31 #import "CachedResourceLoader.h"
32 #import "DocumentFragment.h"
33 #import "Editor.h"
34 #import "EditorClient.h"
35 #import "Frame.h"
36 #import "FrameView.h"
37 #import "Pasteboard.h"
38 #import "RenderBlock.h"
39 #import "RuntimeApplicationChecks.h"
40 #import "Sound.h"
41
42 namespace WebCore {
43
44 PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
45 {
46     return ClipboardMac::create(Clipboard::CopyAndPaste, [NSPasteboard generalPasteboard], policy, frame);
47 }
48
49 void Editor::showFontPanel()
50 {
51     [[NSFontManager sharedFontManager] orderFrontFontPanel:nil];
52 }
53
54 void Editor::showStylesPanel()
55 {
56     [[NSFontManager sharedFontManager] orderFrontStylesPanel:nil];
57 }
58
59 void Editor::showColorPanel()
60 {
61     [[NSApplication sharedApplication] orderFrontColorPanel:nil];
62 }
63
64 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
65 {
66     RefPtr<Range> range = selectedRange();
67     bool choosePlainText;
68     
69     m_frame->editor()->client()->setInsertionPasteboard([NSPasteboard generalPasteboard]);
70 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
71     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, choosePlainText);
72     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
73         pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), false);
74 #else
75     // Mail is ignoring the frament passed to the delegate and creates a new one.
76     // We want to avoid creating the fragment twice.
77     if (applicationIsAppleMail()) {
78         if (shouldInsertFragment(NULL, range, EditorInsertActionPasted)) {
79             RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, choosePlainText);
80             if (fragment)
81                 pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), false);
82         }        
83     } else {
84         RefPtr<DocumentFragment>fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, choosePlainText);
85         if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
86             pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), false);
87     }
88 #endif
89     m_frame->editor()->client()->setInsertionPasteboard(nil);
90 }
91
92 NSDictionary* Editor::fontAttributesForSelectionStart() const
93 {
94     Node* nodeToRemove;
95     RenderStyle* style = styleForSelectionStart(nodeToRemove);
96     if (!style)
97         return nil;
98
99     NSMutableDictionary* result = [NSMutableDictionary dictionary];
100
101     if (style->visitedDependentColor(CSSPropertyBackgroundColor).isValid() && style->visitedDependentColor(CSSPropertyBackgroundColor).alpha() != 0)
102         [result setObject:nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)) forKey:NSBackgroundColorAttributeName];
103
104     if (style->font().primaryFont()->getNSFont())
105         [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
106
107     if (style->visitedDependentColor(CSSPropertyColor).isValid() && style->visitedDependentColor(CSSPropertyColor) != Color::black)
108         [result setObject:nsColor(style->visitedDependentColor(CSSPropertyColor)) forKey:NSForegroundColorAttributeName];
109
110     const ShadowData* shadow = style->textShadow();
111     if (shadow) {
112         NSShadow* s = [[NSShadow alloc] init];
113         [s setShadowOffset:NSMakeSize(shadow->x(), shadow->y())];
114         [s setShadowBlurRadius:shadow->blur()];
115         [s setShadowColor:nsColor(shadow->color())];
116         [result setObject:s forKey:NSShadowAttributeName];
117     }
118
119     int decoration = style->textDecorationsInEffect();
120     if (decoration & LINE_THROUGH)
121         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
122
123     int superscriptInt = 0;
124     switch (style->verticalAlign()) {
125         case BASELINE:
126         case BOTTOM:
127         case BASELINE_MIDDLE:
128         case LENGTH:
129         case MIDDLE:
130         case TEXT_BOTTOM:
131         case TEXT_TOP:
132         case TOP:
133             break;
134         case SUB:
135             superscriptInt = -1;
136             break;
137         case SUPER:
138             superscriptInt = 1;
139             break;
140     }
141     if (superscriptInt)
142         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
143
144     if (decoration & UNDERLINE)
145         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
146
147     if (nodeToRemove) {
148         ExceptionCode ec = 0;
149         nodeToRemove->remove(ec);
150         ASSERT(ec == 0);
151     }
152
153     return result;
154 }
155
156 NSWritingDirection Editor::baseWritingDirectionForSelectionStart() const
157 {
158     NSWritingDirection result = NSWritingDirectionLeftToRight;
159
160     Position pos = m_frame->selection()->selection().visibleStart().deepEquivalent();
161     Node* node = pos.deprecatedNode();
162     if (!node)
163         return result;
164
165     RenderObject* renderer = node->renderer();
166     if (!renderer)
167         return result;
168
169     if (!renderer->isBlockFlow()) {
170         renderer = renderer->containingBlock();
171         if (!renderer)
172             return result;
173     }
174
175     RenderStyle* style = renderer->style();
176     if (!style)
177         return result;
178         
179     switch (style->direction()) {
180         case LTR:
181             result = NSWritingDirectionLeftToRight;
182             break;
183         case RTL:
184             result = NSWritingDirectionRightToLeft;
185             break;
186     }
187
188     return result;
189 }
190
191 bool Editor::canCopyExcludingStandaloneImages()
192 {
193     SelectionController* selection = m_frame->selection();
194     return selection->isRange() && !selection->isInPasswordField();
195 }
196
197 void Editor::takeFindStringFromSelection()
198 {
199     if (!canCopyExcludingStandaloneImages()) {
200         systemBeep();
201         return;
202     }
203
204     NSString *nsSelectedText = m_frame->displayStringModifiedByEncoding(selectedText());
205
206     NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
207     [findPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
208     [findPasteboard setString:nsSelectedText forType:NSStringPboardType];
209 }
210
211 void Editor::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes)
212 {
213     RetainPtr<NSMutableArray> types(AdoptNS, [[NSMutableArray alloc] init]);    
214     for (size_t i = 0; i < pasteboardTypes.size(); ++i)
215         [types.get() addObject:pasteboardTypes[i]];
216     Pasteboard::writeSelection([NSPasteboard pasteboardWithName:pasteboardName], types.get(), selectedRange().get(), true, m_frame);
217 }
218     
219 void Editor::readSelectionFromPasteboard(const String& pasteboardName)
220 {
221     Pasteboard pasteboard([NSPasteboard pasteboardWithName:pasteboardName]);
222     if (m_frame->selection()->isContentRichlyEditable())
223         pasteWithPasteboard(&pasteboard, true);
224     else
225         pasteAsPlainTextWithPasteboard(&pasteboard);   
226 }
227
228 } // namespace WebCore