]>
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); | |
67daf503 JF |
73 | |
74 | MSImageRef JavaScriptCore(MSGetImageByName("/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore")); | |
75 | ||
76 | void (*_ZN3JSC19initializeThreadingEv)(); | |
77 | MSHookSymbol(_ZN3JSC19initializeThreadingEv, "__ZN3JSC19initializeThreadingEv", JavaScriptCore); | |
78 | if (_ZN3JSC19initializeThreadingEv != NULL) | |
79 | (*_ZN3JSC19initializeThreadingEv)(); | |
fdac1738 JF |
80 | } |
81 | ||
2de63e63 JF |
82 | + (BOOL) isSharedMarkupCreated { |
83 | return SharedMarkup_ != nil; | |
84 | } | |
85 | ||
86 | + (WBMarkup *) sharedMarkup { | |
87 | if (SharedMarkup_ == nil) | |
88 | SharedMarkup_ = [[WBMarkup alloc] init]; | |
89 | return SharedMarkup_; | |
90 | } | |
91 | ||
92 | - (id) init { | |
93 | if ((self = [super init]) != nil) { | |
94 | WebThreadLock(); | |
95 | ||
96 | SharedMarkup_ = self; | |
97 | ||
98 | view_ = [[WebView alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)]; | |
99 | [view_ setDrawsBackground:NO]; | |
100 | ||
101 | WebPreferences *preferences([[WebPreferences alloc] initWithIdentifier:@"com.apple.webkit.webmarkup"]); | |
102 | [preferences setPlugInsEnabled:NO]; | |
103 | [view_ setPreferences:preferences]; | |
104 | [preferences release]; | |
105 | ||
106 | window_ = [[WAKWindow alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)]; | |
107 | [window_ setContentView:view_]; | |
108 | ||
109 | WebFrame *frame([view_ mainFrame]); | |
110 | [[frame frameView] setAllowsScrolling:NO]; | |
111 | [frame _setLoadsSynchronously:YES]; | |
112 | ||
113 | [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]; | |
114 | } return self; | |
115 | } | |
116 | ||
117 | - (void) dealloc { | |
118 | [window_ release]; | |
119 | [view_ release]; | |
120 | [super dealloc]; | |
121 | } | |
122 | ||
09ea4166 JF |
123 | - (void) drawRect:(CGRect)rect { |
124 | [text_ setScrollXOffset:origin_.x scrollYOffset:origin_.y]; | |
125 | ||
126 | CGRect draw(CGRectMake(0, 0, rect.size.width - rect.origin.x, rect.size.height - rect.origin.y)); | |
127 | ||
128 | CGContextSaveGState(context_); { | |
129 | CGContextTranslateCTM(context_, rect.origin.x, rect.origin.y); | |
130 | ||
131 | if (kCFCoreFoundationVersionNumber > 700) | |
132 | [view_ _drawRect:draw context:context_ lockFocus:YES]; | |
133 | else { | |
134 | WKView *view([view_ _viewRef]); | |
fdac1738 JF |
135 | WKViewLockFocus$(view); { |
136 | WKViewDisplayRect$(view, draw); | |
137 | } WKViewUnlockFocus$(view); | |
09ea4166 JF |
138 | } |
139 | } CGContextRestoreGState(context_); | |
140 | } | |
141 | ||
2de63e63 JF |
142 | - (WebView *) _webView { |
143 | return view_; | |
144 | } | |
145 | ||
146 | - (void) setStringDrawingOrigin:(CGPoint)origin { | |
147 | origin_ = origin; | |
148 | } | |
149 | ||
150 | - (void) clearStringDrawingOrigin { | |
151 | origin_ = CGPointZero; | |
152 | } | |
153 | ||
154 | - (CGSize) sizeOfMarkup:(NSString *)markup forWidth:(float)width { | |
155 | WebThreadLock(); | |
156 | ||
157 | if (![self _webPrepareContextForTextDrawing:NO]) | |
158 | return CGSizeZero; | |
159 | ||
160 | [text_ setInnerHTML:markup]; | |
161 | [text_ removeAttribute:@"style"]; | |
162 | ||
163 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: 5000px"], width]); | |
164 | [size_ setAttribute:@"style" value:value]; | |
165 | [value release]; | |
166 | ||
167 | [[view_ mainFrame] forceLayoutAdjustingViewSize:YES]; | |
168 | return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width]; | |
169 | } | |
170 | ||
171 | - (CGSize) sizeOfString:(NSString *)string withStyle:(NSString *)style forWidth:(float)width { | |
172 | WebThreadLock(); | |
173 | ||
174 | if (![self _webPrepareContextForTextDrawing:NO]) | |
175 | return CGSizeZero; | |
176 | ||
177 | [size_ removeChild:[size_ firstChild]]; | |
178 | ||
179 | WebFrame *frame([view_ mainFrame]); | |
180 | ||
181 | [frame forceLayoutAdjustingViewSize:YES]; | |
182 | [text_ setInnerText:string]; | |
183 | [self _setupWithStyle:style width:width height:5000]; | |
184 | [frame forceLayoutAdjustingViewSize:YES]; | |
185 | ||
186 | return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width]; | |
187 | } | |
188 | ||
189 | - (NSString *) _styleFormatString:(NSString *)style { | |
190 | return style; | |
191 | } | |
192 | ||
193 | - (void) _setupWithStyle:(NSString *)style width:(float)width height:(float)height { | |
194 | WebThreadLock(); | |
195 | ||
196 | if (style != nil && [style length] != 0) | |
197 | [text_ setAttribute:@"style" value:style]; | |
198 | else | |
199 | [text_ removeAttribute:@"style"]; | |
200 | ||
201 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], width, height]); | |
202 | [size_ setAttribute:@"style" value:value]; | |
203 | [value release]; | |
204 | ||
205 | [size_ appendChild:text_]; | |
206 | } | |
207 | ||
208 | - (BOOL) _webPrepareContextForTextDrawing:(BOOL)drawing { | |
209 | WebThreadLock(); | |
210 | ||
211 | if (document_ == nil) { | |
212 | WebFrame *frame([view_ mainFrame]); | |
213 | ||
214 | document_ = [[frame DOMDocument] retain]; | |
215 | if (document_ == nil) { | |
216 | NSLog(@"*** ERROR: no DOM document in text-drawing webview"); | |
217 | return NO; | |
218 | } | |
219 | ||
220 | text_ = [[document_ getElementById:@"text"] retain]; | |
221 | size_ = [[document_ getElementById:@"size"] retain]; | |
222 | ||
223 | if (text_ == nil || size_ == nil) { | |
224 | NSLog(@"*** ERROR: cannot find DOM element required for text drawing"); | |
225 | return NO; | |
226 | } | |
227 | } | |
228 | ||
229 | context_ = NULL; | |
230 | ||
231 | if (!drawing) | |
232 | context_ = NULL; | |
233 | else { | |
234 | context_ = WKGetCurrentGraphicsContext(); | |
235 | if (context_ == NULL) { | |
236 | NSLog(@"*** ERROR: no CGContext set for drawing"); | |
237 | return NO; | |
238 | } | |
239 | } | |
240 | ||
241 | return YES; | |
242 | } | |
243 | ||
244 | - (void) drawMarkup:(NSString *)markup atPoint:(CGPoint)point { | |
245 | [self drawMarkup:markup inRect:CGRectMake(point.x, point.y, 65535, 65535)]; | |
246 | } | |
247 | ||
248 | - (void) drawMarkup:(NSString *)markup inRect:(CGRect)rect { | |
249 | WebThreadLock(); | |
250 | ||
251 | if (![self _webPrepareContextForTextDrawing:YES]) | |
252 | return; | |
253 | ||
254 | [text_ setInnerHTML:markup]; | |
255 | [text_ removeAttribute:@"style"]; | |
256 | ||
257 | NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], CGRectGetWidth(rect), CGRectGetHeight(rect)]); | |
258 | [size_ setAttribute:@"style" value:value]; | |
259 | [value release]; | |
260 | ||
261 | [[view_ mainFrame] forceLayoutAdjustingViewSize:YES]; | |
262 | ||
09ea4166 | 263 | [self drawRect:rect]; |
2de63e63 JF |
264 | } |
265 | ||
266 | - (void) drawString:(NSString *)string atPoint:(CGPoint)point withStyle:(NSString *)style { | |
267 | [self drawString:string inRect:CGRectMake(point.x, point.y, 65535, 65535) withStyle:style]; | |
268 | } | |
269 | ||
270 | - (void) drawString:(NSString *)string inRect:(CGRect)rect withStyle:(NSString *)style { | |
271 | WebThreadLock(); | |
272 | ||
273 | if (![self _webPrepareContextForTextDrawing:YES]) | |
274 | return; | |
275 | ||
276 | [size_ removeChild:[size_ firstChild]]; | |
277 | ||
278 | WebFrame *frame([view_ mainFrame]); | |
279 | ||
280 | [frame forceLayoutAdjustingViewSize:YES]; | |
281 | [text_ setInnerText:string]; | |
282 | [self _setupWithStyle:style width:CGRectGetWidth(rect) height:CGRectGetHeight(rect)]; | |
283 | [frame forceLayoutAdjustingViewSize:YES]; | |
284 | ||
09ea4166 | 285 | [self drawRect:rect]; |
2de63e63 JF |
286 | } |
287 | ||
288 | @end |