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