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 "QuickDrawCompatibility.h" 34 #import "WebNSObjectExtras.h" 35 #import <wtf/Assertions.h> 36 37 static void SetViewNeedsDisplay(HIViewRef inView, RgnHandle inRegion, Boolean inNeedsDisplay); 38 39 #define WATCH_INVALIDATION 0 40 41 @interface NSView(ShhhhDontTell) 42 - (NSRect)_dirtyRect; 43 @end 44 45 @implementation HIViewAdapter 46 47 static CFMutableDictionaryRef sViewMap; 48 49 static IMP oldNSViewSetNeedsDisplayIMP; 50 static IMP oldNSViewSetNeedsDisplayInRectIMP; 51 static IMP oldNSViewNextValidKeyViewIMP; 52 53 static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag); 54 static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect); 55 static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd); 56 57 + (void)bindHIViewToNSView:(HIViewRef)hiView nsView:(NSView*)nsView 58 { 59 if (sViewMap == NULL) { 60 sViewMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 61 62 // Override -[NSView setNeedsDisplay:] 63 Method setNeedsDisplayMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplay:)); 64 ASSERT(setNeedsDisplayMethod); 65 ASSERT(!oldNSViewSetNeedsDisplayIMP); 66 oldNSViewSetNeedsDisplayIMP = method_setImplementation(setNeedsDisplayMethod, (IMP)_webkit_NSView_setNeedsDisplay); 67 68 // Override -[NSView setNeedsDisplayInRect:] 69 Method setNeedsDisplayInRectMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(setNeedsDisplayInRect:)); 70 ASSERT(setNeedsDisplayInRectMethod); 71 ASSERT(!oldNSViewSetNeedsDisplayInRectIMP); 72 oldNSViewSetNeedsDisplayInRectIMP = method_setImplementation(setNeedsDisplayInRectMethod, (IMP)_webkit_NSView_setNeedsDisplayInRect); 73 74 // Override -[NSView nextValidKeyView] 75 Method nextValidKeyViewMethod = class_getInstanceMethod(objc_getClass("NSView"), @selector(nextValidKeyView)); 76 ASSERT(nextValidKeyViewMethod); 77 ASSERT(!oldNSViewNextValidKeyViewIMP); 78 oldNSViewNextValidKeyViewIMP = method_setImplementation(nextValidKeyViewMethod, (IMP)_webkit_NSView_nextValidKeyView); 79 } 80 81 CFDictionaryAddValue(sViewMap, nsView, hiView); 82 } 83 84 + (HIViewRef)getHIViewForNSView:(NSView*)inView 85 { 86 return sViewMap ? (HIViewRef)CFDictionaryGetValue(sViewMap, inView) : NULL; 87 } 88 89 + (void)unbindNSView:(NSView*)inView 90 { 91 CFDictionaryRemoveValue(sViewMap, inView); 92 } 93 94 static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag) 95 { 96 oldNSViewSetNeedsDisplayIMP(self, _cmd, flag); 97 98 if (!flag) { 99 HIViewRef hiView = NULL; 100 NSRect targetBounds = [self visibleRect]; 101 NSRect validRect = targetBounds; 102 NSView *view = self; 103 104 while (view) { 105 targetBounds = [view visibleRect]; 106 if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) 107 break; 108 validRect = [view convertRect:validRect toView:[view superview]]; 109 view = [view superview]; 110 } 111 112 if (hiView) { 113 // Flip rect here and convert to region 114 HIRect rect; 115 rect.origin.x = validRect.origin.x; 116 rect.origin.y = targetBounds.size.height - NSMaxY(validRect); 117 rect.size.height = validRect.size.height; 118 rect.size.width = validRect.size.width; 119 120 // For now, call the region-based API. 121 RgnHandle rgn = NewRgn(); 122 if (rgn) { 123 Rect qdRect; 124 qdRect.top = (SInt16)rect.origin.y; 125 qdRect.left = (SInt16)rect.origin.x; 126 qdRect.bottom = CGRectGetMaxY(rect); 127 qdRect.right = CGRectGetMaxX(rect); 128 129 RectRgn(rgn, &qdRect); 130 SetViewNeedsDisplay(hiView, rgn, false); 131 DisposeRgn(rgn); 132 } 133 } 134 } 135 } 136 137 static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect) 138 { 139 invalidRect = NSUnionRect(invalidRect, [self _dirtyRect]); 140 oldNSViewSetNeedsDisplayInRectIMP(self, _cmd, invalidRect); 141 142 if (!NSIsEmptyRect(invalidRect)) { 143 HIViewRef hiView = NULL; 144 NSRect targetBounds = [self bounds]; 145 NSView *view = self; 146 147 while (view) { 148 targetBounds = [view bounds]; 149 if ((hiView = [HIViewAdapter getHIViewForNSView:view]) != NULL) 150 break; 151 invalidRect = [view convertRect:invalidRect toView:[view superview]]; 152 view = [view superview]; 153 } 154 155 if (hiView) { 156 if (NSWidth(invalidRect) > 0 && NSHeight(invalidRect)) { 157 // Flip rect here and convert to region 158 HIRect rect; 159 rect.origin.x = invalidRect.origin.x; 160 rect.origin.y = targetBounds.size.height - NSMaxY(invalidRect); 161 rect.size.height = invalidRect.size.height; 162 rect.size.width = invalidRect.size.width; 163 164 // For now, call the region-based API. 165 RgnHandle rgn = NewRgn(); 166 if (rgn) { 167 Rect qdRect; 168 qdRect.top = (SInt16)rect.origin.y; 169 qdRect.left = (SInt16)rect.origin.x; 170 qdRect.bottom = CGRectGetMaxY(rect); 171 qdRect.right = CGRectGetMaxX(rect); 172 173 RectRgn(rgn, &qdRect); 174 SetViewNeedsDisplay(hiView, rgn, true); 175 DisposeRgn(rgn); 176 } 177 } 178 } else 179 [[self window] setViewsNeedDisplay:YES]; 180 } 181 } 182 183 static NSView *_webkit_NSView_nextValidKeyView(id self, SEL _cmd) 184 { 185 if ([HIViewAdapter getHIViewForNSView:self]) 186 return [[self window] contentView]; 187 else 188 return oldNSViewNextValidKeyViewIMP(self, _cmd); 189 } 190 191 @end 192 193 static void SetViewNeedsDisplay(HIViewRef inHIView, RgnHandle inRegion, Boolean inNeedsDisplay) 194 { 195 WindowAttributes attrs; 196 197 GetWindowAttributes(GetControlOwner(inHIView), &attrs); 198 199 if (attrs & kWindowCompositingAttribute) { 200 #if WATCH_INVALIDATION 201 Rect bounds; 202 GetRegionBounds(inRegion, &bounds); 203 printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", 204 bounds.top, bounds.left, bounds.bottom, bounds.right); 205 #endif 206 HIViewSetNeedsDisplayInRegion(inHIView, inRegion, inNeedsDisplay); 207 } else { 208 Rect bounds, cntlBounds; 209 GrafPtr port, savePort; 210 Rect portBounds; 211 212 #if WATCH_INVALIDATION 213 printf("%s: rect on input %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", 214 bounds.top, bounds.left, bounds.bottom, bounds.right); 215 #endif 216 GetControlBounds(inHIView, &cntlBounds); 217 218 #if WATCH_INVALIDATION 219 printf("%s: control bounds are %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", 220 cntlBounds.top, cntlBounds.left, cntlBounds.bottom, cntlBounds.right); 221 #endif 222 223 port = GetWindowPort(GetControlOwner(inHIView)); 224 225 GetPort(&savePort); 226 SetPort(port); 227 GetPortBounds(port, &portBounds); 228 SetOrigin(0, 0); 229 230 OffsetRgn(inRegion, cntlBounds.left, cntlBounds.top); 231 232 GetRegionBounds(inRegion, &bounds); 233 234 #if WATCH_INVALIDATION 235 printf("%s: rect in port coords %d %d %d %d\n", inNeedsDisplay ? "INVALIDATE" : "VALIDATE", 236 bounds.top, bounds.left, bounds.bottom, bounds.right); 237 #endif 238 239 if (inNeedsDisplay) 240 InvalWindowRgn(GetControlOwner(inHIView), inRegion); 241 else 242 ValidWindowRgn(GetControlOwner(inHIView), inRegion); 243 244 SetOrigin(portBounds.left, portBounds.top); 245 SetPort(savePort); 246 } 247 } 248 249 #endif 250