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 36static 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 46static CFMutableDictionaryRef sViewMap; 47 48static IMP oldNSViewSetNeedsDisplayIMP; 49static IMP oldNSViewSetNeedsDisplayInRectIMP; 50static IMP oldNSViewNextValidKeyViewIMP; 51 52static void _webkit_NSView_setNeedsDisplay(id self, SEL _cmd, BOOL flag); 53static void _webkit_NSView_setNeedsDisplayInRect(id self, SEL _cmd, NSRect invalidRect); 54static 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 93static 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 136static 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 182static 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 192static 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