/* * Copyright (C) 2016-2021 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "WebCoreArgumentCoders.h" #import "ArgumentCodersCF.h" #import "ArgumentCodersCocoa.h" #import #import #import #import #import #import #import #import #import #import #if PLATFORM(IOS_FAMILY) #import #endif #if ENABLE(WIRELESS_PLAYBACK_TARGET) #import #import #endif #if USE(APPLE_INTERNAL_SDK) #include #endif #if USE(AVFOUNDATION) #import #endif #if ENABLE(APPLE_PAY) #import "DataReference.h" #import #endif #if ENABLE(WIRELESS_PLAYBACK_TARGET) #import #endif #if ENABLE(DATA_DETECTION) #import #endif #if USE(AVFOUNDATION) #import #endif #import namespace IPC { void ArgumentCoder::encode(Encoder& encoder, const WebCore::AttributedString& attributedString) { encoder << attributedString.string << attributedString.documentAttributes; } std::optional ArgumentCoder::decode(Decoder& decoder) { RetainPtr attributedString; if (!IPC::decode(decoder, attributedString)) return std::nullopt; RetainPtr documentAttributes; if (!IPC::decode(decoder, documentAttributes)) return std::nullopt; return { { WTFMove(attributedString), WTFMove(documentAttributes) } }; } #if ENABLE(APPLE_PAY) #if HAVE(PASSKIT_INSTALLMENTS) void ArgumentCoder::encode(Encoder& encoder, const WebCore::PaymentInstallmentConfiguration& configuration) { encoder << configuration.platformConfiguration(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto configuration = IPC::decode(decoder, PAL::getPKPaymentInstallmentConfigurationClass()); if (!configuration) return std::nullopt; return { WTFMove(*configuration) }; } #endif // HAVE(PASSKIT_INSTALLMENTS) void ArgumentCoder::encode(Encoder& encoder, const WebCore::Payment& payment) { encoder << payment.pkPayment(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto payment = IPC::decode(decoder, PAL::getPKPaymentClass()); if (!payment) return std::nullopt; return WebCore::Payment { WTFMove(*payment) }; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::PaymentContact& paymentContact) { encoder << paymentContact.pkContact(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto contact = IPC::decode(decoder, PAL::getPKContactClass()); if (!contact) return std::nullopt; return WebCore::PaymentContact { WTFMove(*contact) }; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::PaymentMerchantSession& paymentMerchantSession) { encoder << paymentMerchantSession.pkPaymentMerchantSession(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto paymentMerchantSession = IPC::decode(decoder, PAL::getPKPaymentMerchantSessionClass()); if (!paymentMerchantSession) return std::nullopt; return WebCore::PaymentMerchantSession { WTFMove(*paymentMerchantSession) }; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::PaymentMethod& paymentMethod) { encoder << paymentMethod.pkPaymentMethod(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto paymentMethod = IPC::decode(decoder, PAL::getPKPaymentMethodClass()); if (!paymentMethod) return std::nullopt; return WebCore::PaymentMethod { WTFMove(*paymentMethod) }; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::ApplePaySessionPaymentRequest& request) { encoder << request.countryCode(); encoder << request.currencyCode(); encoder << request.requiredBillingContactFields(); encoder << request.billingContact(); encoder << request.requiredShippingContactFields(); encoder << request.shippingContact(); encoder << request.merchantCapabilities(); encoder << request.supportedNetworks(); encoder << request.shippingType(); encoder << request.shippingMethods(); encoder << request.lineItems(); encoder << request.total(); encoder << request.applicationData(); encoder << request.supportedCountries(); encoder << request.requester(); #if ENABLE(APPLE_PAY_INSTALLMENTS) encoder << request.installmentConfiguration(); #endif #if ENABLE(APPLE_PAY_COUPON_CODE) encoder << request.supportsCouponCode(); encoder << request.couponCode(); #endif #if ENABLE(APPLE_PAY_SHIPPING_CONTACT_EDITING_MODE) encoder << request.shippingContactEditingMode(); #endif #if ENABLE(APPLE_PAY_RECURRING_PAYMENTS) encoder << request.recurringPaymentRequest(); #endif #if ENABLE(APPLE_PAY_AUTOMATIC_RELOAD_PAYMENTS) encoder << request.automaticReloadPaymentRequest(); #endif #if ENABLE(APPLE_PAY_MULTI_MERCHANT_PAYMENTS) encoder << request.multiTokenContexts(); #endif } bool ArgumentCoder::decode(Decoder& decoder, WebCore::ApplePaySessionPaymentRequest& request) { String countryCode; if (!decoder.decode(countryCode)) return false; request.setCountryCode(countryCode); String currencyCode; if (!decoder.decode(currencyCode)) return false; request.setCurrencyCode(currencyCode); WebCore::ApplePaySessionPaymentRequest::ContactFields requiredBillingContactFields; if (!decoder.decode((requiredBillingContactFields))) return false; request.setRequiredBillingContactFields(requiredBillingContactFields); std::optional billingContact; decoder >> billingContact; if (!billingContact) return false; request.setBillingContact(*billingContact); WebCore::ApplePaySessionPaymentRequest::ContactFields requiredShippingContactFields; if (!decoder.decode((requiredShippingContactFields))) return false; request.setRequiredShippingContactFields(requiredShippingContactFields); std::optional shippingContact; decoder >> shippingContact; if (!shippingContact) return false; request.setShippingContact(*shippingContact); WebCore::ApplePaySessionPaymentRequest::MerchantCapabilities merchantCapabilities; if (!decoder.decode(merchantCapabilities)) return false; request.setMerchantCapabilities(merchantCapabilities); Vector supportedNetworks; if (!decoder.decode(supportedNetworks)) return false; request.setSupportedNetworks(supportedNetworks); WebCore::ApplePaySessionPaymentRequest::ShippingType shippingType; if (!decoder.decode(shippingType)) return false; request.setShippingType(shippingType); Vector shippingMethods; if (!decoder.decode(shippingMethods)) return false; request.setShippingMethods(shippingMethods); Vector lineItems; if (!decoder.decode(lineItems)) return false; request.setLineItems(lineItems); std::optional total; decoder >> total; if (!total) return false; request.setTotal(*total); String applicationData; if (!decoder.decode(applicationData)) return false; request.setApplicationData(applicationData); Vector supportedCountries; if (!decoder.decode(supportedCountries)) return false; request.setSupportedCountries(WTFMove(supportedCountries)); WebCore::ApplePaySessionPaymentRequest::Requester requester; if (!decoder.decode(requester)) return false; request.setRequester(requester); #if ENABLE(APPLE_PAY_INSTALLMENTS) std::optional installmentConfiguration; decoder >> installmentConfiguration; if (!installmentConfiguration) return false; request.setInstallmentConfiguration(WTFMove(*installmentConfiguration)); #endif #if ENABLE(APPLE_PAY_COUPON_CODE) std::optional> supportsCouponCode; decoder >> supportsCouponCode; if (!supportsCouponCode) return false; request.setSupportsCouponCode(WTFMove(*supportsCouponCode)); std::optional couponCode; decoder >> couponCode; if (!couponCode) return false; request.setCouponCode(WTFMove(*couponCode)); #endif #if ENABLE(APPLE_PAY_SHIPPING_CONTACT_EDITING_MODE) std::optional> shippingContactEditingMode; decoder >> shippingContactEditingMode; if (!shippingContactEditingMode) return false; request.setShippingContactEditingMode(WTFMove(*shippingContactEditingMode)); #endif #if ENABLE(APPLE_PAY_RECURRING_PAYMENTS) std::optional> recurringPaymentRequest; decoder >> recurringPaymentRequest; if (!recurringPaymentRequest) return false; request.setRecurringPaymentRequest(WTFMove(*recurringPaymentRequest)); #endif #if ENABLE(APPLE_PAY_AUTOMATIC_RELOAD_PAYMENTS) std::optional> automaticReloadPaymentRequest; decoder >> automaticReloadPaymentRequest; if (!automaticReloadPaymentRequest) return false; request.setAutomaticReloadPaymentRequest(WTFMove(*automaticReloadPaymentRequest)); #endif #if ENABLE(APPLE_PAY_MULTI_MERCHANT_PAYMENTS) std::optional>> multiTokenContexts; decoder >> multiTokenContexts; if (!multiTokenContexts) return false; request.setMultiTokenContexts(WTFMove(*multiTokenContexts)); #endif return true; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::ApplePaySessionPaymentRequest::ContactFields& contactFields) { encoder << contactFields.postalAddress; encoder << contactFields.phone; encoder << contactFields.email; encoder << contactFields.name; encoder << contactFields.phoneticName; } bool ArgumentCoder::decode(Decoder& decoder, WebCore::ApplePaySessionPaymentRequest::ContactFields& contactFields) { if (!decoder.decode(contactFields.postalAddress)) return false; if (!decoder.decode(contactFields.phone)) return false; if (!decoder.decode(contactFields.email)) return false; if (!decoder.decode(contactFields.name)) return false; if (!decoder.decode(contactFields.phoneticName)) return false; return true; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::ApplePaySessionPaymentRequest::MerchantCapabilities& merchantCapabilities) { encoder << merchantCapabilities.supports3DS; encoder << merchantCapabilities.supportsEMV; encoder << merchantCapabilities.supportsCredit; encoder << merchantCapabilities.supportsDebit; } bool ArgumentCoder::decode(Decoder& decoder, WebCore::ApplePaySessionPaymentRequest::MerchantCapabilities& merchantCapabilities) { if (!decoder.decode(merchantCapabilities.supports3DS)) return false; if (!decoder.decode(merchantCapabilities.supportsEMV)) return false; if (!decoder.decode(merchantCapabilities.supportsCredit)) return false; if (!decoder.decode(merchantCapabilities.supportsDebit)) return false; return true; } void ArgumentCoder>::encode(Encoder& encoder, const RefPtr& error) { encoder << !!error; if (error) encoder << *error; } std::optional> ArgumentCoder>::decode(Decoder& decoder) { std::optional isValid; decoder >> isValid; if (!isValid) return std::nullopt; RefPtr error; if (!*isValid) return { nullptr }; error = WebCore::ApplePayError::decode(decoder); if (!error) return std::nullopt; return error; } void ArgumentCoder::encode(Encoder& encoder, const WebCore::PaymentSessionError& error) { encoder << error.platformError(); } std::optional ArgumentCoder::decode(Decoder& decoder) { auto platformError = IPC::decode(decoder); if (!platformError) return std::nullopt; return { WTFMove(*platformError) }; } #endif // ENABLE(APPLEPAY) void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::DictionaryPopupInfo& info) { encoder << info.options << info.attributedString; } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::DictionaryPopupInfo& result) { if (!IPC::decode(decoder, result.options)) return false; if (!IPC::decode(decoder, result.attributedString)) return false; return true; } void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::Font& font) { const auto& platformData = font.platformData(); encoder << platformData.orientation(); encoder << platformData.widthVariant(); encoder << platformData.textRenderingMode(); encoder << platformData.size(); encoder << platformData.syntheticBold(); encoder << platformData.syntheticOblique(); auto ctFont = platformData.font(); auto fontDescriptor = adoptCF(CTFontCopyFontDescriptor(ctFont)); auto attributes = adoptCF(CTFontDescriptorCopyAttributes(fontDescriptor.get())); encoder << attributes; const auto& creationData = platformData.creationData(); encoder << static_cast(creationData); if (creationData) { encoder << creationData->fontFaceData; encoder << creationData->itemInCollection; } else { auto options = CTFontDescriptorGetOptions(fontDescriptor.get()); encoder << options; auto referenceURL = adoptCF(static_cast(CTFontCopyAttribute(ctFont, kCTFontReferenceURLAttribute))); auto string = CFURLGetString(referenceURL.get()); encoder << string; encoder << adoptCF(CTFontCopyPostScriptName(ctFont)).get(); } } static RetainPtr findFontDescriptor(CFStringRef referenceURL, CFStringRef postScriptName) { auto url = adoptCF(CFURLCreateWithString(kCFAllocatorDefault, referenceURL, nullptr)); if (!url) return nullptr; auto fontDescriptors = adoptCF(CTFontManagerCreateFontDescriptorsFromURL(url.get())); if (!fontDescriptors || !CFArrayGetCount(fontDescriptors.get())) return nullptr; if (CFArrayGetCount(fontDescriptors.get()) == 1) return static_cast(CFArrayGetValueAtIndex(fontDescriptors.get(), 0)); for (CFIndex i = 0; i < CFArrayGetCount(fontDescriptors.get()); ++i) { auto fontDescriptor = static_cast(CFArrayGetValueAtIndex(fontDescriptors.get(), i)); auto currentPostScriptName = adoptCF(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontNameAttribute)); if (CFEqual(currentPostScriptName.get(), postScriptName)) return fontDescriptor; } return nullptr; } static RetainPtr createCTFont(CFDictionaryRef attributes, float size, CTFontDescriptorOptions options, CFStringRef referenceURL, CFStringRef desiredPostScriptName) { auto fontDescriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes)); if (fontDescriptor) { auto font = adoptCF(CTFontCreateWithFontDescriptorAndOptions(fontDescriptor.get(), size, nullptr, options)); auto actualPostScriptName = adoptCF(CTFontCopyPostScriptName(font.get())); if (CFEqual(actualPostScriptName.get(), desiredPostScriptName)) return font; } // CoreText couldn't round-trip the font. // We can fall back to doing our best to find it ourself. fontDescriptor = findFontDescriptor(referenceURL, desiredPostScriptName); if (!fontDescriptor) { ASSERT_NOT_REACHED(); fontDescriptor = adoptCF(CTFontDescriptorCreateLastResort()); } ASSERT(fontDescriptor); return adoptCF(CTFontCreateWithFontDescriptorAndOptions(fontDescriptor.get(), size, nullptr, options)); } std::optional ArgumentCoder::decodePlatformData(Decoder& decoder) { std::optional orientation; decoder >> orientation; if (!orientation) return std::nullopt; std::optional widthVariant; decoder >> widthVariant; if (!widthVariant) return std::nullopt; std::optional textRenderingMode; decoder >> textRenderingMode; if (!textRenderingMode) return std::nullopt; std::optional size; decoder >> size; if (!size) return std::nullopt; std::optional syntheticBold; decoder >> syntheticBold; if (!syntheticBold) return std::nullopt; std::optional syntheticOblique; decoder >> syntheticOblique; if (!syntheticOblique) return std::nullopt; std::optional> attributes; decoder >> attributes; if (!attributes) return std::nullopt; std::optional includesCreationData; decoder >> includesCreationData; if (!includesCreationData) return std::nullopt; if (*includesCreationData) { std::optional> fontFaceData; decoder >> fontFaceData; if (!fontFaceData) return std::nullopt; auto localFontFaceData = fontFaceData.value()->makeContiguous(); std::optional itemInCollection; decoder >> itemInCollection; if (!itemInCollection) return std::nullopt; auto fontCustomPlatformData = createFontCustomPlatformData(localFontFaceData, *itemInCollection); if (!fontCustomPlatformData) return std::nullopt; auto baseFontDescriptor = fontCustomPlatformData->fontDescriptor.get(); if (!baseFontDescriptor) return std::nullopt; auto fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithAttributes(baseFontDescriptor, attributes->get())); auto ctFont = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), *size, nullptr)); auto creationData = WebCore::FontPlatformData::CreationData { localFontFaceData, *itemInCollection }; return WebCore::FontPlatformData(ctFont.get(), *size, *syntheticBold, *syntheticOblique, *orientation, *widthVariant, *textRenderingMode, &creationData); } std::optional options; decoder >> options; if (!options) return std::nullopt; std::optional> referenceURL; decoder >> referenceURL; if (!referenceURL || !*referenceURL) return std::nullopt; std::optional> postScriptName; decoder >> postScriptName; if (!postScriptName || !*postScriptName) return std::nullopt; auto ctFont = createCTFont(attributes->get(), *size, *options, referenceURL->get(), postScriptName->get()); if (!ctFont) return std::nullopt; return WebCore::FontPlatformData(ctFont.get(), *size, *syntheticBold, *syntheticOblique, *orientation, *widthVariant, *textRenderingMode); } void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::ResourceRequest& resourceRequest) { auto requestToSerialize = retainPtr(resourceRequest.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)); if (Class requestClass = [requestToSerialize class]; UNLIKELY(requestClass != [NSURLRequest class] && requestClass != [NSMutableURLRequest class])) { WebCore::ResourceRequest request(requestToSerialize.get()); request.replacePlatformRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody); requestToSerialize = retainPtr(request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)); } ASSERT([requestToSerialize class] == [NSURLRequest class] || [requestToSerialize class] == [NSMutableURLRequest class]); bool requestIsPresent = requestToSerialize; encoder << requestIsPresent; if (!requestIsPresent) return; // We don't send HTTP body over IPC for better performance. // Also, it's not always possible to do, as streams can only be created in process that does networking. if ([requestToSerialize HTTPBody] || [requestToSerialize HTTPBodyStream]) { auto mutableRequest = adoptNS([requestToSerialize mutableCopy]); [mutableRequest setHTTPBody:nil]; [mutableRequest setHTTPBodyStream:nil]; requestToSerialize = WTFMove(mutableRequest); } IPC::encode(encoder, requestToSerialize.get()); encoder << resourceRequest.requester(); encoder << resourceRequest.isAppInitiated(); } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::ResourceRequest& resourceRequest) { bool requestIsPresent; if (!decoder.decode(requestIsPresent)) return false; if (!requestIsPresent) { resourceRequest = WebCore::ResourceRequest(); return true; } auto request = IPC::decode(decoder, NSURLRequest.class); if (!request) return false; WebCore::ResourceRequest::Requester requester; if (!decoder.decode(requester)) return false; bool isAppInitiated; if (!decoder.decode(isAppInitiated)) return false; resourceRequest = WebCore::ResourceRequest(request->get()); resourceRequest.setRequester(requester); resourceRequest.setIsAppInitiated(isAppInitiated); return true; } #if ENABLE(DATA_DETECTION) void ArgumentCoder::encode(Encoder& encoder, const WebCore::DataDetectorElementInfo& info) { encoder << info.result.get(); encoder << info.elementBounds; } std::optional ArgumentCoder::decode(Decoder& decoder) { auto result = IPC::decode(decoder, PAL::getDDScannerResultClass()); if (!result) return std::nullopt; std::optional elementBounds; decoder >> elementBounds; if (!elementBounds) return std::nullopt; return std::make_optional({ WTFMove(*result), WTFMove(*elementBounds) }); } #endif // ENABLE(DATA_DETECTION) #if ENABLE(WIRELESS_PLAYBACK_TARGET) void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::MediaPlaybackTargetContext& target) { if (target.type() == WebCore::MediaPlaybackTargetContext::Type::AVOutputContext) { if ([PAL::getAVOutputContextClass() conformsToProtocol:@protocol(NSSecureCoding)]) encoder << target.outputContext(); } else if (target.type() == WebCore::MediaPlaybackTargetContext::Type::SerializedAVOutputContext) { encoder << target.serializedOutputContext(); encoder << target.hasActiveRoute(); } else ASSERT_NOT_REACHED(); } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::MediaPlaybackTargetContext::Type contextType, WebCore::MediaPlaybackTargetContext& target) { ASSERT(contextType != WebCore::MediaPlaybackTargetContext::Type::Mock); if (contextType == WebCore::MediaPlaybackTargetContext::Type::AVOutputContext) { if (![PAL::getAVOutputContextClass() conformsToProtocol:@protocol(NSSecureCoding)]) return false; auto outputContext = IPC::decode(decoder, PAL::getAVOutputContextClass()); if (!outputContext) return false; target = WebCore::MediaPlaybackTargetContext { WTFMove(*outputContext) }; return true; } if (contextType == WebCore::MediaPlaybackTargetContext::Type::SerializedAVOutputContext) { RetainPtr serializedOutputContext; if (!IPC::decode(decoder, serializedOutputContext) || !serializedOutputContext) return false; bool hasActiveRoute; if (!decoder.decode(hasActiveRoute)) return false; target = WebCore::MediaPlaybackTargetContext { WTFMove(serializedOutputContext), hasActiveRoute }; return true; } return false; } #endif #if ENABLE(IMAGE_ANALYSIS) && ENABLE(DATA_DETECTION) void ArgumentCoder::encodePlatformData(Encoder& encoder, const WebCore::TextRecognitionDataDetector& info) { encoder << info.result.get(); } bool ArgumentCoder::decodePlatformData(Decoder& decoder, WebCore::TextRecognitionDataDetector& result) { auto scannerResult = IPC::decode(decoder, @[ PAL::getDDScannerResultClass() ]); if (!scannerResult) return false; result.result = WTFMove(*scannerResult); return true; } #endif // ENABLE(IMAGE_ANALYSIS) && ENABLE(DATA_DETECTION) #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS) void ArgumentCoder>::encode(Encoder& encoder, const RetainPtr& data) { if (!PAL::isVisionKitCoreFrameworkAvailable()) return; encoder << data.get(); } std::optional> ArgumentCoder>::decode(Decoder& decoder) { if (!PAL::isVisionKitCoreFrameworkAvailable()) return nil; return IPC::decode(decoder, @[ PAL::getVKCImageAnalysisClass() ]); } #endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS) #if USE(AVFOUNDATION) void ArgumentCoder>::encode(Encoder& encoder, const RetainPtr& pixelBuffer) { // Use IOSurface as the means to transfer CVPixelBufferRef. MachSendRight sendRight; if (pixelBuffer) { if (auto surface = WebCore::CVPixelBufferGetIOSurface(pixelBuffer.get())) sendRight = MachSendRight::adopt(IOSurfaceCreateMachPort(surface)); } encoder << WTFMove(sendRight); } std::optional> ArgumentCoder>::decode(Decoder& decoder) { std::optional sendRight; decoder >> sendRight; if (!sendRight) return std::nullopt; RetainPtr pixelBuffer; if (!*sendRight) return pixelBuffer; { auto surface = adoptCF(IOSurfaceLookupFromMachPort(sendRight->sendRight())); if (!surface) return std::nullopt; CVPixelBufferRef rawBuffer = nullptr; auto status = WebCore::CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, surface.get(), nullptr, &rawBuffer); if (status != noErr || !rawBuffer) return std::nullopt; pixelBuffer = adoptCF(rawBuffer); } return pixelBuffer; } #endif } // namespace IPC