]>
Commit | Line | Data |
---|---|---|
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 |