Home | History | Annotate | Download | only in Carbon
      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