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