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
base / apple / bridging.h [blame]
// 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_