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 <wtf/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 249