1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_APPLE_BRIDGING_H_
#define BASE_APPLE_BRIDGING_H_
#include <CoreText/CoreText.h>
#import <Foundation/Foundation.h>
#include "base/apple/scoped_cftyperef.h"
#include "base/base_export.h"
#include "base/check.h"
#include "base/types/always_false.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_IOS)
#import <UIKit/UIKit.h>
#endif
#if BUILDFLAG(IS_MAC)
#import <AppKit/AppKit.h>
#endif
// These functions convert pointers of bridged CFTypes to NSTypes and
// vice-versa. They come in two flavors: those that transfer ownership
// (`OwnershipCast`) and those that just convert the pointer (`PtrCast`).
//
// Examples:
//
// Ownership transference (as in `CFBridgingRetain`/`Release`):
// CFStringRef cf_string = CFStringCreateWithCString(...);
// NSString* ns_string = CFToNSOwnershipCast(cf_string);
// // At this point, `cf_string` does not need releasing.
//
// NSString* ns_string = [[NSString alloc] initWithString:...];
// CFStringRef cf_string = NSToCFOwnershipCast(ns_string);
// // At this point, `cf_string` must be released.
//
// Pointer conversion (as in `__bridge`):
// // `cf_data` is some `CFDataRef` from somewhere.
// NSImage* ns_image = [[NSImage alloc] initWithData:CFToNSPtrCast(cf_data)];
//
// // `ns_data` is some `NSData *` from somewhere.
// SecKeyRef sec_key = SecKeyCreateFromData(..., NSToCFPtrCast(ns_data), ...);
//
// The reason to use these functions (rather than using `__bridge` and
// `CFBridgingRetain`/`Release`) is because they are type-safe. The OS-provided
// bridging calls do not type check, while these calls do the appropriate type
// checking via the magic of macros.
//
// Implementation note: Why not templates? Type checking in Core Foundation
// involves functions named in a specific pattern, and only macro token pasting
// works for this purpose.
#define CF_TO_NS_CAST_IMPL(TypeCF, TypeNS) \
namespace base::apple { \
inline BASE_EXPORT TypeNS* _Nullable CFToNSOwnershipCast( \
TypeCF##Ref CF_CONSUMED _Nullable cf_val) { \
DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
return (__bridge_transfer TypeNS*)cf_val; \
} \
inline BASE_EXPORT CF_RETURNS_RETAINED \
TypeCF##Ref _Nullable NSToCFOwnershipCast(TypeNS* _Nullable ns_val) { \
TypeCF##Ref cf_val = (__bridge_retained TypeCF##Ref)ns_val; \
DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
} \
inline BASE_EXPORT TypeNS* _Nullable CFToNSPtrCast( \
TypeCF##Ref _Nullable cf_val) { \
DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
return (__bridge TypeNS*)cf_val; \
} \
inline BASE_EXPORT TypeCF##Ref _Nullable NSToCFPtrCast( \
TypeNS* _Nullable ns_val) { \
TypeCF##Ref cf_val = (__bridge TypeCF##Ref)ns_val; \
DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
} \
}
#define CF_TO_NS_MUTABLE_CAST_IMPL(name) \
CF_TO_NS_CAST_IMPL(CF##name, NS##name) \
namespace base::apple { \
inline BASE_EXPORT NSMutable##name* _Nullable CFToNSOwnershipCast( \
CFMutable##name##Ref CF_CONSUMED _Nullable cf_val) { \
DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
return (__bridge_transfer NSMutable##name*)cf_val; \
} \
inline BASE_EXPORT CF_RETURNS_RETAINED \
CFMutable##name##Ref _Nullable NSToCFOwnershipCast( \
NSMutable##name* _Nullable ns_val) { \
CFMutable##name##Ref cf_val = \
(__bridge_retained CFMutable##name##Ref)ns_val; \
DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
} \
inline BASE_EXPORT NSMutable##name* _Nullable CFToNSPtrCast( \
CFMutable##name##Ref _Nullable cf_val) { \
DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
return (__bridge NSMutable##name*)cf_val; \
} \
inline BASE_EXPORT CFMutable##name##Ref _Nullable NSToCFPtrCast( \
NSMutable##name* _Nullable ns_val) { \
CFMutable##name##Ref cf_val = (__bridge CFMutable##name##Ref)ns_val; \
DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
return cf_val; \
} \
}
// List of toll-free bridged types taken from:
// https://web.archive.org/web/20111124025525/http://www.cocoadev.com/index.pl?TollFreeBridged
// https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html#//apple_ref/doc/uid/TP40010677-SW4
// Foundation
CF_TO_NS_MUTABLE_CAST_IMPL(Array)
CF_TO_NS_MUTABLE_CAST_IMPL(AttributedString)
CF_TO_NS_CAST_IMPL(CFCalendar, NSCalendar)
CF_TO_NS_MUTABLE_CAST_IMPL(CharacterSet)
CF_TO_NS_MUTABLE_CAST_IMPL(Data)
CF_TO_NS_CAST_IMPL(CFDate, NSDate)
CF_TO_NS_MUTABLE_CAST_IMPL(Dictionary)
CF_TO_NS_CAST_IMPL(CFError, NSError)
CF_TO_NS_CAST_IMPL(CFLocale, NSLocale)
CF_TO_NS_CAST_IMPL(CFNumber, NSNumber)
CF_TO_NS_CAST_IMPL(CFRunLoopTimer, NSTimer)
CF_TO_NS_CAST_IMPL(CFTimeZone, NSTimeZone)
CF_TO_NS_MUTABLE_CAST_IMPL(Set)
CF_TO_NS_CAST_IMPL(CFReadStream, NSInputStream)
CF_TO_NS_CAST_IMPL(CFWriteStream, NSOutputStream)
CF_TO_NS_MUTABLE_CAST_IMPL(String)
CF_TO_NS_CAST_IMPL(CFURL, NSURL)
// AppKit / UIKit
#if BUILDFLAG(IS_IOS)
CF_TO_NS_CAST_IMPL(CTFont, UIFont)
#else
CF_TO_NS_CAST_IMPL(CTFont, NSFont)
#endif // BUILDFLAG(IS_IOS)
#undef CF_TO_NS_CAST_IMPL
#undef CF_TO_NS_MUTABLE_CAST_IMPL
namespace base::apple {
template <typename CFT>
id _Nullable CFToNSOwnershipCast(ScopedCFTypeRef<CFT>) {
static_assert(
AlwaysFalse<CFT>,
"Error: Do not pass a ScopedCFTypeRef to CFToNSOwnershipCast. "
"Call .release() on the ScopedCFTypeRef and pass the result in.");
return nil;
}
} // namespace base::apple
#endif // BASE_APPLE_BRIDGING_H_
|