]>
Commit | Line | Data |
---|---|---|
2de63e63 JF |
1 | #include "WBMarkup.h" |
2 | ||
fdac1738 JF |
3 | #include <substrate.h> |
4 | ||
2de63e63 JF |
5 | @class WKView; |
6 | ||
fdac1738 JF |
7 | extern "C" void WebThreadLock(); |
8 | extern "C" CGContextRef WKGetCurrentGraphicsContext(); | |
9 | ||
10 | static void (*WKViewLockFocus$)(WKView *); | |
11 | static void (*WKViewUnlockFocus$)(WKView *); | |
12 | static void (*WKViewDisplayRect$)(WKView *, CGRect); | |
2de63e63 JF |
13 | |
14 | @interface DOMElement : NSObject | |
15 | - (void) setInnerHTML:(NSString *)value; | |
16 | - (void) setInnerText:(NSString *)value; | |
17 | - (void) setAttribute:(NSString *)name value:(NSString *)value; | |
18 | - (void) removeAttribute:(NSString *)name; | |
19 | - (DOMElement *) firstChild; | |
20 | - (void) appendChild:(DOMElement *)child; | |
21 | - (void) removeChild:(DOMElement *)child; | |
22 | - (void) setScrollXOffset:(float)x scrollYOffset:(float)y; | |
23 | @end | |
24 | ||
25 | @interface DOMDocument : NSObject | |
26 | - (DOMElement *) getElementById:(NSString *)id; | |
27 | @end | |
28 | ||
29 | @interface WebPreferences : NSObject | |
30 | - (id) initWithIdentifier:(NSString *)identifier; | |
31 | - (void) setPlugInsEnabled:(BOOL)value; | |
32 | @end | |
33 | ||
34 | @interface WebFrameView : NSObject | |
35 | - (void) setAllowsScrolling:(BOOL)value; | |
36 | @end | |
37 | ||
38 | @interface WebFrame : NSObject | |
39 | - (WebFrameView *) frameView; | |
40 | - (void) _setLoadsSynchronously:(BOOL)value; | |
41 | - (void) loadHTMLString:(NSString *)string baseURL:(id)url; | |
42 | - (void) forceLayoutAdjustingViewSize:(BOOL)adjust; | |
43 | - (CGSize) renderedSizeOfNode:(DOMElement *)node constrainedToWidth:(float)width; | |
44 | - (DOMDocument *) DOMDocument; | |
45 | @end | |
46 | ||
09ea4166 JF |
47 | @interface WAKView : NSObject |
48 | - (void) _drawRect:(CGRect)rect context:(CGContext *)context lockFocus:(bool)focus; | |
49 | @end | |
50 | ||
51 | @interface WebView : WAKView | |
2de63e63 JF |
52 | - (id) initWithFrame:(CGRect)frame; |
53 | - (WebFrame *) mainFrame; | |
54 | - (void) setDrawsBackground:(BOOL)value; | |
55 | - (void) setPreferences:(WebPreferences *)preferences; | |
56 | - (WKView *) _viewRef; | |
57 | @end | |
58 | ||
59 | @interface WAKWindow : NSObject | |
60 | - (id) initWithFrame:(CGRect)frame; | |
61 | - (void) setContentView:(WebView *)view; | |
62 | @end | |
63 | ||
64 | static WBMarkup *SharedMarkup_; | |
65 | ||
66 | @implementation WBMarkup | |
67 | ||
fdac1738 JF |
68 | + (void) initialize { |
69 | MSImageRef WebCore(MSGetImageByName("/System/Library/PrivateFrameworks/WebCore.framework/WebCore")); | |
70 | MSHookSymbol(WKViewLockFocus$, "WKViewLockFocus", WebCore); | |
71 | MSHookSymbol(WKViewUnlockFocus$, "WKViewUnlockFocus", WebCore); | |
72 | MSHookSymbol(WKViewDisplayRect$, "WKViewDisplayRect", WebCore); | |
73 | } | |
74 | ||
2de63e63 JF |
75 | + (BOOL) isSharedMarkupCreated { |
76 | return SharedMarkup_ != nil; | |
77 | } | |
78 | ||
79 | + (WBMarkup *) sharedMarkup { | |
80 | if (SharedMarkup_ == nil) | |
81 | SharedMarkup_ = [[WBMarkup alloc] init]; | |
82 | return SharedMarkup_; | |
83 | } | |
84 | ||
85 | - (id) init { | |
86 | if ((self = [super init]) != nil) { | |
87 | WebThreadLock(); | |
88 | ||
89 | SharedMarkup_ = self; | |
90 | ||
91 | view_ = [[WebView alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)]; | |
92 | [view_ setDrawsBackground:NO]; | |
93 | ||
94 | WebPreferences *preferences([[WebPreferences alloc] initWithIdentifier:@"com.apple.webkit.webmarkup"]); | |
95 | [preferences setPlugInsEnabled:NO]; | |
96 | [view_ setPreferences:preferences]; | |
97 | [preferences release]; | |
98 | ||
99 | window_ = [[WAKWindow alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)]; | |
100 | [window_ setContentView:view_]; | |
101 | ||
102 | WebFrame *frame([view_ mainFrame]); | |
103 | [[frame frameView] setAllowsScrolling:NO]; | |
104 | [frame _setLoadsSynchronously:YES]; | |
105 | ||
106 | [frame loadHTMLString:@"<html><body style='margin: 0px; word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space'><div id='size'><div id='text'></div></div></body></html>" baseURL:nil]; | |
107 | } return self; | |
108 | } | |
109 | ||
110 | - (void) dealloc { | |
111 | [window_ release]; | |
112 | [view_ release]; | |
113 | [super dealloc]; | |
114 | } | |
115 | ||
09ea4166 JF |
116 | - (void) drawRect:(CGRect)rect { |
117 | [text_ setScrollXOffset:origin_.x scrollYOffset:origin_.y]; | |
118 | ||
119 | CGRect draw(CGRectMake(0, 0, rect.size.width - rect.origin.x, rect.size.height - rect.origin.y)); | |
120 | ||
121 | CGContextSaveGState(context_); { | |
122 | CGContextTranslateCTM(context_, rect.origin.x, rect.origin.y); | |
123 | ||
124 | if (kCFCoreFoundationVersionNumber > 700) | |
125 | [view_ _drawRect:draw context:context_ lockFocus:YES]; | |
126 | else { | |
127 | WKView *view([view_ _viewRef]); | |
fdac1738 JF |
128 | WKViewLockFocus$(view); { |
129 | WKViewDisplayRect$(view, draw); | |
130 | } WKViewUnlockFocus$(view); | |
09ea4166 JF |
131 | } |
132 | } CGContextRestoreGState(context_); | |
133 | } | |
134 | ||
2de63e63 JF |
135 | - (WebView *) _webView { |
136 | return view_; | |
137 | } | |
138 | ||
139 | - (void) setStringDrawingOrigin:(CGPoint)origin { | |
140 | origin_ = origin; | |
141 | } | |
142 | ||
143 | - (void) clearStringDrawingOrigin { | |
144 | origin_ = CGPointZero; | |
145 | } | |
146 | ||
147 | - (CGSize) sizeOfMarkup:(NSString *)markup forWidth:(float)width { | |
148 | WebThreadLock(); | |
149 | ||
150 | if (![self _webPrepareContextForTextDrawing:NO]) | |
151 | return CGSizeZero; | |
152 | ||
153 | [text_ setInnerHTML:markup]; | |
154 | [text_ removeAttribute:@"style"]; | |
155 | ||
156 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: 5000px"], width]); | |
157 | [size_ setAttribute:@"style" value:value]; | |
158 | [value release]; | |
159 | ||
160 | [[view_ mainFrame] forceLayoutAdjustingViewSize:YES]; | |
161 | return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width]; | |
162 | } | |
163 | ||
164 | - (CGSize) sizeOfString:(NSString *)string withStyle:(NSString *)style forWidth:(float)width { | |
165 | WebThreadLock(); | |
166 | ||
167 | if (![self _webPrepareContextForTextDrawing:NO]) | |
168 | return CGSizeZero; | |
169 | ||
170 | [size_ removeChild:[size_ firstChild]]; | |
171 | ||
172 | WebFrame *frame([view_ mainFrame]); | |
173 | ||
174 | [frame forceLayoutAdjustingViewSize:YES]; | |
175 | [text_ setInnerText:string]; | |
176 | [self _setupWithStyle:style width:width height:5000]; | |
177 | [frame forceLayoutAdjustingViewSize:YES]; | |
178 | ||
179 | return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width]; | |
180 | } | |
181 | ||
182 | - (NSString *) _styleFormatString:(NSString *)style { | |
183 | return style; | |
184 | } | |
185 | ||
186 | - (void) _setupWithStyle:(NSString *)style width:(float)width height:(float)height { | |
187 | WebThreadLock(); | |
188 | ||
189 | if (style != nil && [style length] != 0) | |
190 | [text_ setAttribute:@"style" value:style]; | |
191 | else | |
192 | [text_ removeAttribute:@"style"]; | |
193 | ||
194 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], width, height]); | |
195 | [size_ setAttribute:@"style" value:value]; | |
196 | [value release]; | |
197 | ||
198 | [size_ appendChild:text_]; | |
199 | } | |
200 | ||
201 | - (BOOL) _webPrepareContextForTextDrawing:(BOOL)drawing { | |
202 | WebThreadLock(); | |
203 | ||
204 | if (document_ == nil) { | |
205 | WebFrame *frame([view_ mainFrame]); | |
206 | ||
207 | document_ = [[frame DOMDocument] retain]; | |
208 | if (document_ == nil) { | |
209 | NSLog(@"*** ERROR: no DOM document in text-drawing webview"); | |
210 | return NO; | |
211 | } | |
212 | ||
213 | text_ = [[document_ getElementById:@"text"] retain]; | |
214 | size_ = [[document_ getElementById:@"size"] retain]; | |
215 | ||
216 | if (text_ == nil || size_ == nil) { | |
217 | NSLog(@"*** ERROR: cannot find DOM element required for text drawing"); | |
218 | return NO; | |
219 | } | |
220 | } | |
221 | ||
222 | context_ = NULL; | |
223 | ||
224 | if (!drawing) | |
225 | context_ = NULL; | |
226 | else { | |
227 | context_ = WKGetCurrentGraphicsContext(); | |
228 | if (context_ == NULL) { | |
229 | NSLog(@"*** ERROR: no CGContext set for drawing"); | |
230 | return NO; | |
231 | } | |
232 | } | |
233 | ||
234 | return YES; | |
235 | } | |
236 | ||
237 | - (void) drawMarkup:(NSString *)markup atPoint:(CGPoint)point { | |
238 | [self drawMarkup:markup inRect:CGRectMake(point.x, point.y, 65535, 65535)]; | |
239 | } | |
240 | ||
241 | - (void) drawMarkup:(NSString *)markup inRect:(CGRect)rect { | |
242 | WebThreadLock(); | |
243 | ||
244 | if (![self _webPrepareContextForTextDrawing:YES]) | |
245 | return; | |
246 | ||
247 | [text_ setInnerHTML:markup]; | |
248 | [text_ removeAttribute:@"style"]; | |
249 | ||
250 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], CGRectGetWidth(rect), CGRectGetHeight(rect)]); | |
251 | [size_ setAttribute:@"style" value:value]; | |
252 | [value release]; | |
253 | ||
254 | [[view_ mainFrame] forceLayoutAdjustingViewSize:YES]; | |
255 | ||
09ea4166 | 256 | [self drawRect:rect]; |
2de63e63 JF |
257 | } |
258 | ||
259 | - (void) drawString:(NSString *)string atPoint:(CGPoint)point withStyle:(NSString *)style { | |
260 | [self drawString:string inRect:CGRectMake(point.x, point.y, 65535, 65535) withStyle:style]; | |
261 | } | |
262 | ||
263 | - (void) drawString:(NSString *)string inRect:(CGRect)rect withStyle:(NSString *)style { | |
264 | WebThreadLock(); | |
265 | ||
266 | if (![self _webPrepareContextForTextDrawing:YES]) | |
267 | return; | |
268 | ||
269 | [size_ removeChild:[size_ firstChild]]; | |
270 | ||
271 | WebFrame *frame([view_ mainFrame]); | |
272 | ||
273 | [frame forceLayoutAdjustingViewSize:YES]; | |
274 | [text_ setInnerText:string]; | |
275 | [self _setupWithStyle:style width:CGRectGetWidth(rect) height:CGRectGetHeight(rect)]; | |
276 | [frame forceLayoutAdjustingViewSize:YES]; | |
277 | ||
09ea4166 | 278 | [self drawRect:rect]; |
2de63e63 JF |
279 | } |
280 | ||
281 | @end |