]> git.saurik.com Git - winterboard.git/blame - WBMarkup.mm
Support NSAttributedString for iOS 9 calendar day.
[winterboard.git] / WBMarkup.mm
CommitLineData
2de63e63
JF
1#include "WBMarkup.h"
2
fdac1738
JF
3#include <substrate.h>
4
0032040f
JF
5MSClassHook(UIWebDocumentView)
6
2de63e63
JF
7@class WKView;
8
fdac1738
JF
9extern "C" void WebThreadLock();
10extern "C" CGContextRef WKGetCurrentGraphicsContext();
11
12static void (*WKViewLockFocus$)(WKView *);
13static void (*WKViewUnlockFocus$)(WKView *);
14static 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
70static 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