7 extern "C" void WebThreadLock();
8 extern "C" CGContextRef WKGetCurrentGraphicsContext();
10 static void (*WKViewLockFocus$)(WKView *);
11 static void (*WKViewUnlockFocus$)(WKView *);
12 static void (*WKViewDisplayRect$)(WKView *, CGRect);
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;
25 @interface DOMDocument : NSObject
26 - (DOMElement *) getElementById:(NSString *)id;
29 @interface WebPreferences : NSObject
30 - (id) initWithIdentifier:(NSString *)identifier;
31 - (void) setPlugInsEnabled:(BOOL)value;
34 @interface WebFrameView : NSObject
35 - (void) setAllowsScrolling:(BOOL)value;
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;
47 @interface WAKView : NSObject
48 - (void) _drawRect:(CGRect)rect context:(CGContext *)context lockFocus:(bool)focus;
51 @interface WebView : WAKView
52 - (id) initWithFrame:(CGRect)frame;
53 - (WebFrame *) mainFrame;
54 - (void) setDrawsBackground:(BOOL)value;
55 - (void) setPreferences:(WebPreferences *)preferences;
56 - (WKView *) _viewRef;
59 @interface WAKWindow : NSObject
60 - (id) initWithFrame:(CGRect)frame;
61 - (void) setContentView:(WebView *)view;
64 static WBMarkup *SharedMarkup_;
66 @implementation WBMarkup
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);
74 MSImageRef JavaScriptCore(MSGetImageByName("/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore"));
76 void (*_ZN3JSC19initializeThreadingEv)();
77 MSHookSymbol(_ZN3JSC19initializeThreadingEv, "__ZN3JSC19initializeThreadingEv", JavaScriptCore);
78 if (_ZN3JSC19initializeThreadingEv != NULL)
79 (*_ZN3JSC19initializeThreadingEv)();
82 + (BOOL) isSharedMarkupCreated {
83 return SharedMarkup_ != nil;
86 + (WBMarkup *) sharedMarkup {
87 if (SharedMarkup_ == nil)
88 SharedMarkup_ = [[WBMarkup alloc] init];
93 if ((self = [super init]) != nil) {
98 view_ = [[WebView alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)];
99 [view_ setDrawsBackground:NO];
101 WebPreferences *preferences([[WebPreferences alloc] initWithIdentifier:@"com.apple.webkit.webmarkup"]);
102 [preferences setPlugInsEnabled:NO];
103 [view_ setPreferences:preferences];
104 [preferences release];
106 window_ = [[WAKWindow alloc] initWithFrame:CGRectMake(0, 0, 640, 5000)];
107 [window_ setContentView:view_];
109 WebFrame *frame([view_ mainFrame]);
110 [[frame frameView] setAllowsScrolling:NO];
111 [frame _setLoadsSynchronously:YES];
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];
123 - (void) drawRect:(CGRect)rect {
124 [text_ setScrollXOffset:origin_.x scrollYOffset:origin_.y];
126 CGRect draw(CGRectMake(0, 0, rect.size.width - rect.origin.x, rect.size.height - rect.origin.y));
128 CGContextSaveGState(context_); {
129 CGContextTranslateCTM(context_, rect.origin.x, rect.origin.y);
131 if (kCFCoreFoundationVersionNumber > 700)
132 [view_ _drawRect:draw context:context_ lockFocus:YES];
134 WKView *view([view_ _viewRef]);
135 WKViewLockFocus$(view); {
136 WKViewDisplayRect$(view, draw);
137 } WKViewUnlockFocus$(view);
139 } CGContextRestoreGState(context_);
142 - (WebView *) _webView {
146 - (void) setStringDrawingOrigin:(CGPoint)origin {
150 - (void) clearStringDrawingOrigin {
151 origin_ = CGPointZero;
154 - (CGSize) sizeOfMarkup:(NSString *)markup forWidth:(CGFloat)width {
157 if (![self _webPrepareContextForTextDrawing:NO])
160 [text_ setInnerHTML:markup];
161 [text_ removeAttribute:@"style"];
163 NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: 5000px"], width]);
164 [size_ setAttribute:@"style" value:value];
167 [[view_ mainFrame] forceLayoutAdjustingViewSize:YES];
168 return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width];
171 - (CGSize) sizeOfString:(NSString *)string withStyle:(NSString *)style forWidth:(CGFloat)width {
174 if (![self _webPrepareContextForTextDrawing:NO])
177 [size_ removeChild:[size_ firstChild]];
179 WebFrame *frame([view_ mainFrame]);
181 [frame forceLayoutAdjustingViewSize:YES];
182 [text_ setInnerText:string];
183 [self _setupWithStyle:style width:width height:5000];
184 [frame forceLayoutAdjustingViewSize:YES];
186 return [[view_ mainFrame] renderedSizeOfNode:text_ constrainedToWidth:width];
189 - (NSString *) _styleFormatString:(NSString *)style {
193 - (void) _setupWithStyle:(NSString *)style width:(CGFloat)width height:(CGFloat)height {
196 if (style != nil && [style length] != 0)
197 [text_ setAttribute:@"style" value:style];
199 [text_ removeAttribute:@"style"];
201 NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], width, height]);
202 [size_ setAttribute:@"style" value:value];
205 [size_ appendChild:text_];
208 - (BOOL) _webPrepareContextForTextDrawing:(BOOL)drawing {
211 if (document_ == nil) {
212 WebFrame *frame([view_ mainFrame]);
214 document_ = [[frame DOMDocument] retain];
215 if (document_ == nil) {
216 NSLog(@"*** ERROR: no DOM document in text-drawing webview");
220 text_ = [[document_ getElementById:@"text"] retain];
221 size_ = [[document_ getElementById:@"size"] retain];
223 if (text_ == nil || size_ == nil) {
224 NSLog(@"*** ERROR: cannot find DOM element required for text drawing");
234 context_ = WKGetCurrentGraphicsContext();
235 if (context_ == NULL) {
236 NSLog(@"*** ERROR: no CGContext set for drawing");
244 - (void) drawMarkup:(NSString *)markup atPoint:(CGPoint)point {
245 [self drawMarkup:markup inRect:CGRectMake(point.x, point.y, 65535, 65535)];
248 - (void) drawMarkup:(NSString *)markup inRect:(CGRect)rect {
251 if (![self _webPrepareContextForTextDrawing:YES])
254 [text_ setInnerHTML:markup];
255 [text_ removeAttribute:@"style"];
257 NSString *value([[NSString alloc] initWithFormat:[self _styleFormatString:@"width: %.0fpx; height: %.0fpx"], CGRectGetWidth(rect), CGRectGetHeight(rect)]);
258 [size_ setAttribute:@"style" value:value];
261 [[view_ mainFrame] forceLayoutAdjustingViewSize:YES];
263 [self drawRect:rect];
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];
270 - (void) drawString:(NSString *)string inRect:(CGRect)rect withStyle:(NSString *)style {
273 if (![self _webPrepareContextForTextDrawing:YES])
276 [size_ removeChild:[size_ firstChild]];
278 WebFrame *frame([view_ mainFrame]);
280 [frame forceLayoutAdjustingViewSize:YES];
281 [text_ setInnerText:string];
282 [self _setupWithStyle:style width:CGRectGetWidth(rect) height:CGRectGetHeight(rect)];
283 [frame forceLayoutAdjustingViewSize:YES];
285 [self drawRect:rect];