|
1 /* |
|
2 * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
14 * its contributors may be used to endorse or promote products derived |
|
15 * from this software without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #ifndef __LP64__ |
|
30 |
|
31 #import "HIViewAdapter.h" |
|
32 |
|
33 #import "WebNSObjectExtras.h" |
|
34 #import <JavaScriptCore/Assertions.h> |
|
35 |
|
36 static void SetViewNeedsDisplay(HIViewRef inView, RgnHandle inRegion, Boolean inNeedsDisplay); |
|
37 |
|
38 #define WATCH_INVALIDATION 0 |
|
39 |
|
40 @interface NSView(ShhhhDontTell) |
|
41 - (NSRect)_dirtyRect; |
|
42 @end |
|
43 |
|
44 @implementation HIViewAdapter |
|
45 |
|
46 static CFMutableDictionaryRef sViewMap; |
|
47 |
|
48 static IMP oldNSViewSetNeedsDisplayIMP; |
|
49 static IMP oldNSViewSetNeedsDisplayInRectIMP; |
|
50 static IMP oldNSViewNextValidKeyViewIMP; |
|
51 |
|
52 static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag); |
|
53 static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect); |
|
54 static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd); |
|
55 |
|
56 + (void)bindHIViewToNSView:(HIViewRef)hiView nsView:(NSView*)nsView |
|
57 { |
|
58 if (sViewMap == NULL) { |
|
59 sViewMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); |
|
60 |
|
61 // Override -[NSView setNeedsDisplay:] |
|
62 Method setNeedsDisplayMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplay:)); |
|
63 ASSERT(setNeedsDisplayMethod); |
|
64 ASSERT(!oldNSViewSetNeedsDisplayIMP); |
|
65 oldNSViewSetNeedsDisplayIMP = method_setImplementation(setNeedsDisplayMethod, (IMP)_webkit_NSView_setNeedsDisplay); |
|
66 |
|
67 // Override -[NSView setNeedsDisplayInRect:] |
|
68 Method setNeedsDisplayInRectMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplayInRect:)); |
|
69 ASSERT(setNeedsDisplayInRectMethod); |
|
70 ASSERT(!oldNSViewSetNeedsDisplayInRectIMP); |
|
71 oldNSViewSetNeedsDisplayInRectIMP = method_setImplementation(setNeedsDisplayInRectMethod, (IMP)_webkit_NSView_setNeedsDisplayInRect); |
|
72 |
|
73 // Override -[NSView nextValidKeyView] |
|
74 Method nextValidKeyViewMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(nextValidKeyView)); |
|
75 ASSERT(nextValidKeyViewMethod); |
|
76 ASSERT(!oldNSViewNextValidKeyViewIMP); |
|
77 oldNSViewNextValidKeyViewIMP = method_setImplementation(nextValidKeyViewMethod, (IMP)_webkit_NSView_nextValidKeyView); |
|
78 } |
|
79 |
|
80 CFDictionaryAddValue(sViewMap, nsView, hiView); |
|
81 } |
|
82 |
|
83 + (HIViewRef)getHIViewForNSView:(NSView*)inView |
|
84 { |
|
85 return sViewMap ? (HIViewRef)CFDictionaryGetValue(sViewMap, inView) : NULL; |
|
86 } |
|
87 |
|
88 + (void)unbindNSView:(NSView*)inView |
|
89 { |
|
90 CFDictionaryRemoveValue(sViewMap, inView); |
|
91 } |
|
92 |
|
93 static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag) |
|
94 { |
|
95 oldNSViewSetNeedsDisplayIMP(self, _cmd, flag); |
|
96 |
|
97 if (!flag) { |
|
98 HIViewRef hiView = NULL; |
|
99 NSRect targetBounds = [self visibleRect]; |
|
100 NSRect validRect = targetBounds; |
|
101 NSView *view = self; |
|
102 |
|
103 while (view) { |
|
104 targetBounds = [view visibleRect]; |
|
105 if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) |
|
106 break; |
|
107 validRect = [view convertRect:validRect toView:[view superview]]; |
|
108 view = [view superview]; |
|
109 } |
|
110 |
|
111 if (hiView) { |
|
112 // Flip rect here and convert to region |
|
113 HIRect rect; |
|
114 rect.origin.x = validRect.origin.x; |
|
115 rect.origin.y = targetBounds.size.height - NSMaxY(validRect); |
|
116 rect.size.height = validRect.size.height; |
|
117 rect.size.width = validRect.size.width; |
|
118 |
|
119 // For now, call the region-based API. |
|
120 RgnHandle rgn = NewRgn(); |
|
121 if (rgn) { |
|
122 Rect qdRect; |
|
123 qdRect.top = (SInt16)rect.origin.y; |
|
124 qdRect.left = (SInt16)rect.origin.x; |
|
125 qdRect.bottom = CGRectGetMaxY(rect); |
|
126 qdRect.right = CGRectGetMaxX(rect); |
|
127 |
|
128 RectRgn(rgn, &qdRect); |
|
129 SetViewNeedsDisplay(hiView, rgn, false); |
|
130 DisposeRgn(rgn); |
|
131 } |
|
132 } |
|
133 } |
|
134 } |
|
135 |
|
136 static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect) |
|
137 { |
|
138 invalidRect = NSUnionRect(invalidRect, [self _dirtyRect]); |
|
139 oldNSViewSetNeedsDisplayInRectIMP(self, _cmd, invalidRect); |
|
140 |
|
141 if (!NSIsEmptyRect(invalidRect)) { |
|
142 HIViewRef hiView = NULL; |
|
143 NSRect targetBounds = [self bounds]; |
|
144 NSView *view = self; |
|
145 |
|
146 while (view) { |
|
147 targetBounds = [view bounds]; |
|
148 if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) |
|
149 break; |
|
150 invalidRect = [view convertRect:invalidRect toView:[view superview]]; |
|
151 view = [view superview]; |
|
152 } |
|
153 |
|
154 if (hiView) { |
|
155 if (NSWidth(invalidRect) > 0 && NSHeight(invalidRect)) { |
|
156 // Flip rect here and convert to region |
|
157 HIRect rect; |
|
158 rect.origin.x = invalidRect.origin.x; |
|
159 rect.origin.y = targetBounds.size.height - NSMaxY(invalidRect); |
|
160 rect.size.height = invalidRect.size.height; |
|
161 rect.size.width = invalidRect.size.width; |
|
162 |
|
163 // For now, call the region-based API. |
|
164 RgnHandle rgn = NewRgn(); |
|
165 if (rgn) { |
|
166 Rect qdRect; |
|
167 qdRect.top = (SInt16)rect.origin.y; |
|
168 qdRect.left = (SInt16)rect.origin.x; |
|
169 qdRect.bottom = CGRectGetMaxY(rect); |
|
170 qdRect.right = CGRectGetMaxX(rect); |
|
171 |
|
172 RectRgn(rgn, &qdRect); |
|
173 SetViewNeedsDisplay(hiView, rgn, true); |
|
174 DisposeRgn(rgn); |
|
175 } |
|
176 } |
|
177 } else |
|
178 [[self window] setViewsNeedDisplay:YES]; |
|
179 } |
|
180 } |
|
181 |
|
182 static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd) |
|
183 { |
|
184 if ([HIViewAdapter getHIViewForNSView:self]) |
|
185 return [[self window] contentView]; |
|
186 else |
|
187 return oldNSViewNextValidKeyViewIMP(self, _cmd); |
|
188 } |
|
189 |
|
190 @end |
|
191 |
|
192 static void SetViewNeedsDisplay(HIViewRef inHIView, RgnHandle inRegion, Boolean inNeedsDisplay) |
|
193 { |
|
194 WindowAttributes attrs; |
|
195 |
|
196 GetWindowAttributes(GetControlOwner(inHIView), &attrs); |
|
197 |
|
198 if (attrs & kWindowCompositingAttribute) { |
|
199 #if WATCH_INVALIDATION |
|
200 Rect bounds; |
|
201 GetRegionBounds(inRegion, &bounds); |
|
202 printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", |
|
203 bounds.top, bounds.left, bounds.bottom, bounds.right); |
|
204 #endif |
|
205 HIViewSetNeedsDisplayInRegion(inHIView, inRegion, inNeedsDisplay); |
|
206 } else { |
|
207 Rect bounds, cntlBounds; |
|
208 GrafPtr port, savePort; |
|
209 Rect portBounds; |
|
210 |
|
211 #if WATCH_INVALIDATION |
|
212 printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", |
|
213 bounds.top, bounds.left, bounds.bottom, bounds.right); |
|
214 #endif |
|
215 GetControlBounds(inHIView, &cntlBounds); |
|
216 |
|
217 #if WATCH_INVALIDATION |
|
218 printf("%s: control bounds are %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", |
|
219 cntlBounds.top, cntlBounds.left, cntlBounds.bottom, cntlBounds.right); |
|
220 #endif |
|
221 |
|
222 port = GetWindowPort(GetControlOwner(inHIView)); |
|
223 |
|
224 GetPort(&savePort); |
|
225 SetPort(port); |
|
226 GetPortBounds(port, &portBounds); |
|
227 SetOrigin(0, 0); |
|
228 |
|
229 OffsetRgn(inRegion, cntlBounds.left, cntlBounds.top); |
|
230 |
|
231 GetRegionBounds(inRegion, &bounds); |
|
232 |
|
233 #if WATCH_INVALIDATION |
|
234 printf("%s: rect in port coords %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", |
|
235 bounds.top, bounds.left, bounds.bottom, bounds.right); |
|
236 #endif |
|
237 |
|
238 if (inNeedsDisplay) |
|
239 InvalWindowRgn(GetControlOwner(inHIView), inRegion); |
|
240 else |
|
241 ValidWindowRgn(GetControlOwner(inHIView), inRegion); |
|
242 |
|
243 SetOrigin(portBounds.left, portBounds.top); |
|
244 SetPort(savePort); |
|
245 } |
|
246 } |
|
247 |
|
248 #endif |