Unreviewed, rolling out r244627.
[WebKit-https.git] / Source / WebCore / platform / mac / SerializedPlatformRepresentationMac.mm
1 /*
2  * Copyright (C) 2014, 2015 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO_TRACK) && ENABLE(DATACUE_VALUE)
29 #include "SerializedPlatformRepresentationMac.h"
30
31 #import "JSDOMConvertBufferSource.h"
32 #import <AVFoundation/AVMetadataItem.h>
33 #import <Foundation/NSString.h>
34 #import <JavaScriptCore/APICast.h>
35 #import <JavaScriptCore/ArrayBuffer.h>
36 #import <JavaScriptCore/JSArrayBuffer.h>
37 #import <JavaScriptCore/JSContextRef.h>
38 #import <JavaScriptCore/JSObjectRef.h>
39 #import <JavaScriptCore/JavaScriptCore.h>
40 #import <objc/runtime.h>
41 #import <wtf/SoftLinking.h>
42 #import <wtf/text/Base64.h>
43
44 typedef AVMetadataItem AVMetadataItemType;
45 SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
46 SOFT_LINK_CLASS(AVFoundation, AVMetadataItem)
47 #define AVMetadataItem getAVMetadataItemClass()
48
49
50 namespace WebCore {
51
52 #if JSC_OBJC_API_ENABLED
53 static JSValue *jsValueWithDataInContext(NSData *, JSContext *);
54 static JSValue *jsValueWithArrayInContext(NSArray *, JSContext *);
55 static JSValue *jsValueWithDictionaryInContext(NSDictionary *, JSContext *);
56 static JSValue *jsValueWithAVMetadataItemInContext(AVMetadataItemType *, JSContext *);
57 static JSValue *jsValueWithValueInContext(id, JSContext *);
58 #endif
59
60 SerializedPlatformRepresentationMac::SerializedPlatformRepresentationMac(id nativeValue)
61     : SerializedPlatformRepresentation()
62     , m_nativeValue(nativeValue)
63 {
64 }
65
66 SerializedPlatformRepresentationMac::~SerializedPlatformRepresentationMac()
67 {
68 }
69
70 Ref<SerializedPlatformRepresentation> SerializedPlatformRepresentationMac::create(id nativeValue)
71 {
72     return adoptRef(*new SerializedPlatformRepresentationMac(nativeValue));
73 }
74
75 RefPtr<ArrayBuffer> SerializedPlatformRepresentationMac::data() const
76 {
77     return nullptr;
78 }
79
80 JSC::JSValue SerializedPlatformRepresentationMac::deserialize(JSC::ExecState* exec) const
81 {
82 #if JSC_OBJC_API_ENABLED
83     if (!m_nativeValue)
84         return JSC::jsNull();
85
86     JSGlobalContextRef jsGlobalContextRef = toGlobalRef(exec->lexicalGlobalObject()->globalExec());
87     JSContext *jsContext = [JSContext contextWithJSGlobalContextRef:jsGlobalContextRef];
88     JSValue *serializedValue = jsValueWithValueInContext(m_nativeValue.get(), jsContext);
89
90     return toJS(exec, [serializedValue JSValueRef]);
91 #else
92     UNUSED_PARAM(exec);
93     return JSC::jsNull();
94 #endif
95 }
96
97 bool SerializedPlatformRepresentationMac::isEqual(const SerializedPlatformRepresentation& other) const
98 {
99     if (other.platformType() != SerializedPlatformRepresentation::ObjC)
100         return false;
101
102     const SerializedPlatformRepresentationMac* otherObjC = toSerializedPlatformRepresentationMac(&other);
103
104     if (!m_nativeValue || !otherObjC->nativeValue())
105         return false;
106
107     return [m_nativeValue.get() isEqual:otherObjC->nativeValue()];
108 }
109
110 SerializedPlatformRepresentationMac* toSerializedPlatformRepresentationMac(SerializedPlatformRepresentation* rep)
111 {
112     return const_cast<SerializedPlatformRepresentationMac*>(toSerializedPlatformRepresentationMac(const_cast<const SerializedPlatformRepresentation*>(rep)));
113 }
114
115 const SerializedPlatformRepresentationMac* toSerializedPlatformRepresentationMac(const SerializedPlatformRepresentation* rep)
116 {
117     ASSERT_WITH_SECURITY_IMPLICATION(rep->platformType() == SerializedPlatformRepresentation::ObjC);
118     return static_cast<const SerializedPlatformRepresentationMac*>(rep);
119 }
120
121 #if JSC_OBJC_API_ENABLED
122 static JSValue *jsValueWithValueInContext(id value, JSContext *context)
123 {
124     if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]])
125         return [JSValue valueWithObject:value inContext:context];
126
127     if ([value isKindOfClass:[NSLocale class]])
128         return [JSValue valueWithObject:[value localeIdentifier] inContext:context];
129
130     if ([value isKindOfClass:[NSDictionary class]])
131         return jsValueWithDictionaryInContext(value, context);
132
133     if ([value isKindOfClass:[NSArray class]])
134         return jsValueWithArrayInContext(value, context);
135
136     if ([value isKindOfClass:[NSData class]])
137         return jsValueWithDataInContext(value, context);
138
139     if ([value isKindOfClass:[AVMetadataItem class]])
140         return jsValueWithAVMetadataItemInContext(value, context);
141
142     return nil;
143 }
144
145 static JSValue *jsValueWithDataInContext(NSData *data, JSContext *context)
146 {
147     auto dataArray = ArrayBuffer::tryCreate([data bytes], [data length]);
148
149     auto* state = toJS([context JSGlobalContextRef]);
150     JSC::JSValue array = toJS(state, JSC::jsCast<JSDOMGlobalObject*>(state->lexicalGlobalObject()), dataArray.get());
151
152     return [JSValue valueWithJSValueRef:toRef(state, array) inContext:context];
153 }
154
155 static JSValue *jsValueWithArrayInContext(NSArray *array, JSContext *context)
156 {
157     JSValueRef exception = 0;
158     JSValue *result = [JSValue valueWithNewArrayInContext:context];
159     JSObjectRef resultObject = JSValueToObject([context JSGlobalContextRef], [result JSValueRef], &exception);
160     if (exception)
161         return [JSValue valueWithUndefinedInContext:context];
162
163     NSUInteger count = [array count];
164     for (NSUInteger i = 0; i < count; ++i) {
165         JSValue *value = jsValueWithValueInContext([array objectAtIndex:i], context);
166         if (!value)
167             continue;
168
169         JSObjectSetPropertyAtIndex([context JSGlobalContextRef], resultObject, (unsigned)i, [value JSValueRef], &exception);
170         if (exception)
171             continue;
172     }
173
174     return result;
175 }
176
177 static JSValue *jsValueWithDictionaryInContext(NSDictionary *dictionary, JSContext *context)
178 {
179     JSValueRef exception = 0;
180     JSValue *result = [JSValue valueWithNewObjectInContext:context];
181     JSObjectRef resultObject = JSValueToObject([context JSGlobalContextRef], [result JSValueRef], &exception);
182     if (exception)
183         return [JSValue valueWithUndefinedInContext:context];
184
185     for (id key in [dictionary keyEnumerator]) {
186         if (![key isKindOfClass:[NSString class]])
187             continue;
188
189         JSValue *value = jsValueWithValueInContext([dictionary objectForKey:key], context);
190         if (!value)
191             continue;
192
193         auto name = OpaqueJSString::tryCreate(key);
194         JSObjectSetProperty([context JSGlobalContextRef], resultObject, name.get(), [value JSValueRef], 0, &exception);
195         if (exception)
196             continue;
197     }
198
199     return result;
200 }
201
202 static JSValue *jsValueWithAVMetadataItemInContext(AVMetadataItemType *item, JSContext *context)
203 {
204     NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
205
206     NSDictionary *extras = [item extraAttributes];
207     for (id key in [extras keyEnumerator]) {
208         if (![key isKindOfClass:[NSString class]])
209             continue;
210         id value = [extras objectForKey:key];
211         NSString *keyString = key;
212
213         if ([key isEqualToString:@"MIMEtype"])
214             keyString = @"type";
215         else if ([key isEqualToString:@"dataTypeNamespace"] || [key isEqualToString:@"pictureType"])
216             continue;
217         else if ([key isEqualToString:@"dataType"]) {
218             id dataTypeNamespace = [extras objectForKey:@"dataTypeNamespace"];
219             if (!dataTypeNamespace || ![dataTypeNamespace isKindOfClass:[NSString class]] || ![dataTypeNamespace isEqualToString:@"org.iana.media-type"])
220                 continue;
221             keyString = @"type";
222         } else if ([value isKindOfClass:[NSString class]]) {
223             if (![value length])
224                 continue;
225             keyString = [key lowercaseString];
226         }
227
228         [dictionary setObject:value forKey:keyString];
229     }
230
231     if (item.key)
232         [dictionary setObject:item.key forKey:@"key"];
233
234     if (item.locale)
235         [dictionary setObject:item.locale forKey:@"locale"];
236
237     if (item.value)
238         [dictionary setObject:item.value forKey:@"data"];
239
240     return jsValueWithDictionaryInContext(dictionary, context);
241 }
242 #endif
243
244 } // namespace WebCore
245
246 #endif