/*
 * Copyright (C) 2011-2022 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.
 */

#include "config.h"
#include "WebCoreArgumentCoders.h"

#include "ShareableBitmap.h"
#include "ShareableResource.h"
#include "StreamConnectionEncoder.h"
#include <JavaScriptCore/GenericTypedArrayViewInlines.h>
#include <JavaScriptCore/JSGenericTypedArrayViewInlines.h>
#include <WebCore/ARKitBadgeSystemImage.h>
#include <WebCore/ApplePayButtonSystemImage.h>
#include <WebCore/ApplePayLogoSystemImage.h>
#include <WebCore/AuthenticationChallenge.h>
#include <WebCore/AuthenticationChallenge.h>
#include <WebCore/BlobPart.h>
#include <WebCore/CacheQueryOptions.h>
#include <WebCore/CacheStorageConnection.h>
#include <WebCore/CompositionUnderline.h>
#include <WebCore/Credential.h>
#include <WebCore/Cursor.h>
#include <WebCore/DOMCacheEngine.h>
#include <WebCore/DatabaseDetails.h>
#include <WebCore/DecomposedGlyphs.h>
#include <WebCore/DictationAlternative.h>
#include <WebCore/DictionaryPopupInfo.h>
#include <WebCore/DisplayListItems.h>
#include <WebCore/DragData.h>
#include <WebCore/EventTrackingRegions.h>
#include <WebCore/FetchOptions.h>
#include <WebCore/File.h>
#include <WebCore/FileChooser.h>
#include <WebCore/FilterOperation.h>
#include <WebCore/FilterOperations.h>
#include <WebCore/FloatQuad.h>
#include <WebCore/Font.h>
#include <WebCore/FontAttributes.h>
#include <WebCore/GraphicsContext.h>
#include <WebCore/GraphicsLayer.h>
#include <WebCore/IDBGetResult.h>
#include <WebCore/Image.h>
#include <WebCore/JSDOMExceptionHandling.h>
#include <WebCore/Length.h>
#include <WebCore/LengthBox.h>
#include <WebCore/MediaSelectionOption.h>
#include <WebCore/Pasteboard.h>
#include <WebCore/PluginData.h>
#include <WebCore/PromisedAttachmentInfo.h>
#include <WebCore/ProtectionSpace.h>
#include <WebCore/RectEdges.h>
#include <WebCore/Region.h>
#include <WebCore/RegistrableDomain.h>
#include <WebCore/ResourceError.h>
#include <WebCore/ResourceLoadStatistics.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/ResourceResponse.h>
#include <WebCore/ScriptBuffer.h>
#include <WebCore/ScriptExecutionContextIdentifier.h>
#include <WebCore/ScrollingConstraints.h>
#include <WebCore/ScrollingCoordinator.h>
#include <WebCore/SearchPopupMenu.h>
#include <WebCore/SecurityOrigin.h>
#include <WebCore/SerializedAttachmentData.h>
#include <WebCore/SerializedPlatformDataCueValue.h>
#include <WebCore/ServiceWorkerClientData.h>
#include <WebCore/ServiceWorkerData.h>
#include <WebCore/ShareData.h>
#include <WebCore/SharedBuffer.h>
#include <WebCore/SystemImage.h>
#include <WebCore/TextCheckerClient.h>
#include <WebCore/TextIndicator.h>
#include <WebCore/TimingFunction.h>
#include <WebCore/TransformationMatrix.h>
#include <WebCore/UserStyleSheet.h>
#include <WebCore/VelocityData.h>
#include <WebCore/ViewportArguments.h>
#include <WebCore/WindowFeatures.h>
#include <wtf/URL.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringHash.h>

#if PLATFORM(COCOA)
#include "ArgumentCodersCF.h"
#endif

#if PLATFORM(IOS_FAMILY)
#include <WebCore/SelectionGeometry.h>
#endif // PLATFORM(IOS_FAMILY)

#if ENABLE(WIRELESS_PLAYBACK_TARGET)
#include <WebCore/MediaPlaybackTargetContext.h>
#endif

#if ENABLE(MEDIA_STREAM)
#include <WebCore/CaptureDevice.h>
#include <WebCore/MediaConstraints.h>
#endif

#if ENABLE(IMAGE_ANALYSIS)
#include <WebCore/TextRecognitionResult.h>
#endif

// FIXME: Seems like we could use std::tuple to cut down the code below a lot!

namespace IPC {
using namespace WebCore;
using namespace WebKit;

#define DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(Type) \
    template<typename Encoder> \
    void ArgumentCoder<Type>::encode(Encoder& encoder, const Type& value) { SimpleArgumentCoder<Type>::encode(encoder, value); } \
    bool ArgumentCoder<Type>::decode(Decoder& decoder, Type& value) { return SimpleArgumentCoder<Type>::decode(decoder, value); } \
    std::optional<Type> ArgumentCoder<Type>::decode(Decoder& decoder) \
    { \
        Type value; \
        if (!decode(decoder, value)) \
            return std::nullopt; \
        return value; \
    } \
    template void ArgumentCoder<Type>::encode<Encoder>(Encoder&, const Type&); \
    template void ArgumentCoder<Type>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, const Type&);

DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(AffineTransform)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatBoxExtent)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatPoint)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatPoint3D)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatRect)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatRoundedRect)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(FloatSize)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(IntPoint)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(IntRect)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(IntSize)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(LayoutPoint)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(LayoutSize)

#if USE(CG)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(CGRect)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(CGSize)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(CGPoint)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(CGAffineTransform)
#endif

DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(DisplayList::SetInlineFillColor)
DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE(DisplayList::SetInlineStrokeColor)

#undef DEFINE_SIMPLE_ARGUMENT_CODER_FOR_SOURCE

void ArgumentCoder<CacheQueryOptions>::encode(Encoder& encoder, const CacheQueryOptions& options)
{
    encoder << options.ignoreSearch;
    encoder << options.ignoreMethod;
    encoder << options.ignoreVary;
    encoder << options.cacheName;
}

bool ArgumentCoder<CacheQueryOptions>::decode(Decoder& decoder, CacheQueryOptions& options)
{
    bool ignoreSearch;
    if (!decoder.decode(ignoreSearch))
        return false;
    bool ignoreMethod;
    if (!decoder.decode(ignoreMethod))
        return false;
    bool ignoreVary;
    if (!decoder.decode(ignoreVary))
        return false;
    String cacheName;
    if (!decoder.decode(cacheName))
        return false;

    options.ignoreSearch = ignoreSearch;
    options.ignoreMethod = ignoreMethod;
    options.ignoreVary = ignoreVary;
    options.cacheName = WTFMove(cacheName);
    return true;
}

void ArgumentCoder<CharacterRange>::encode(Encoder& encoder, const CharacterRange& range)
{
    encoder << static_cast<uint64_t>(range.location);
    encoder << static_cast<uint64_t>(range.length);
}

std::optional<CharacterRange> ArgumentCoder<CharacterRange>::decode(Decoder& decoder)
{
    std::optional<uint64_t> location;
    decoder >> location;
    if (!location)
        return std::nullopt;

    std::optional<uint64_t> length;
    decoder >> length;
    if (!length)
        return std::nullopt;

    return { { *location, *length } };
}

void ArgumentCoder<DOMCacheEngine::CacheInfo>::encode(Encoder& encoder, const DOMCacheEngine::CacheInfo& info)
{
    encoder << info.identifier;
    encoder << info.name;
}

auto ArgumentCoder<DOMCacheEngine::CacheInfo>::decode(Decoder& decoder) -> std::optional<DOMCacheEngine::CacheInfo>
{
    std::optional<uint64_t> identifier;
    decoder >> identifier;
    if (!identifier)
        return std::nullopt;
    
    std::optional<String> name;
    decoder >> name;
    if (!name)
        return std::nullopt;
    
    return {{ WTFMove(*identifier), WTFMove(*name) }};
}

void ArgumentCoder<DOMCacheEngine::Record>::encode(Encoder& encoder, const DOMCacheEngine::Record& record)
{
    encoder << record.identifier;

    encoder << record.requestHeadersGuard;
    encoder << record.request;
    encoder << record.options;
    encoder << record.referrer;

    encoder << record.responseHeadersGuard;
    encoder << record.response;
    encoder << record.updateResponseCounter;
    encoder << record.responseBodySize;

    WTF::switchOn(record.responseBody, [&](const Ref<SharedBuffer>& buffer) {
        encoder << true;
        encoder << buffer;
    }, [&](const Ref<FormData>& formData) {
        encoder << false;
        encoder << true;
        formData->encode(encoder);
    }, [&](const std::nullptr_t&) {
        encoder << false;
        encoder << false;
    });
}

std::optional<DOMCacheEngine::Record> ArgumentCoder<DOMCacheEngine::Record>::decode(Decoder& decoder)
{
    uint64_t identifier;
    if (!decoder.decode(identifier))
        return std::nullopt;

    FetchHeaders::Guard requestHeadersGuard;
    if (!decoder.decode(requestHeadersGuard))
        return std::nullopt;

    WebCore::ResourceRequest request;
    if (!decoder.decode(request))
        return std::nullopt;

    std::optional<WebCore::FetchOptions> options;
    decoder >> options;
    if (!options)
        return std::nullopt;

    String referrer;
    if (!decoder.decode(referrer))
        return std::nullopt;

    FetchHeaders::Guard responseHeadersGuard;
    if (!decoder.decode(responseHeadersGuard))
        return std::nullopt;

    WebCore::ResourceResponse response;
    if (!decoder.decode(response))
        return std::nullopt;

    uint64_t updateResponseCounter;
    if (!decoder.decode(updateResponseCounter))
        return std::nullopt;

    uint64_t responseBodySize;
    if (!decoder.decode(responseBodySize))
        return std::nullopt;

    WebCore::DOMCacheEngine::ResponseBody responseBody;
    bool hasSharedBufferBody;
    if (!decoder.decode(hasSharedBufferBody))
        return std::nullopt;

    if (hasSharedBufferBody) {
        auto buffer = decoder.decode<Ref<SharedBuffer>>();
        if (!buffer)
            return std::nullopt;
        responseBody = WTFMove(*buffer);
    } else {
        bool hasFormDataBody;
        if (!decoder.decode(hasFormDataBody))
            return std::nullopt;
        if (hasFormDataBody) {
            auto formData = FormData::decode(decoder);
            if (!formData)
                return std::nullopt;
            responseBody = formData.releaseNonNull();
        }
    }

    return {{ WTFMove(identifier), WTFMove(updateResponseCounter), WTFMove(requestHeadersGuard), WTFMove(request), WTFMove(options.value()), WTFMove(referrer), WTFMove(responseHeadersGuard), WTFMove(response), WTFMove(responseBody), responseBodySize }};
}

void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTrackingRegions& eventTrackingRegions)
{
    encoder << eventTrackingRegions.asynchronousDispatchRegion;
    encoder << eventTrackingRegions.eventSpecificSynchronousDispatchRegions;
}

bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTrackingRegions& eventTrackingRegions)
{
    std::optional<Region> asynchronousDispatchRegion;
    decoder >> asynchronousDispatchRegion;
    if (!asynchronousDispatchRegion)
        return false;
    EventTrackingRegions::EventSpecificSynchronousDispatchRegions eventSpecificSynchronousDispatchRegions;
    if (!decoder.decode(eventSpecificSynchronousDispatchRegions))
        return false;
    eventTrackingRegions.asynchronousDispatchRegion = WTFMove(*asynchronousDispatchRegion);
    eventTrackingRegions.eventSpecificSynchronousDispatchRegions = WTFMove(eventSpecificSynchronousDispatchRegions);
    return true;
}

template<typename Encoder>
void ArgumentCoder<TransformationMatrix>::encode(Encoder& encoder, const TransformationMatrix& transformationMatrix)
{
    encoder << transformationMatrix.m11();
    encoder << transformationMatrix.m12();
    encoder << transformationMatrix.m13();
    encoder << transformationMatrix.m14();

    encoder << transformationMatrix.m21();
    encoder << transformationMatrix.m22();
    encoder << transformationMatrix.m23();
    encoder << transformationMatrix.m24();

    encoder << transformationMatrix.m31();
    encoder << transformationMatrix.m32();
    encoder << transformationMatrix.m33();
    encoder << transformationMatrix.m34();

    encoder << transformationMatrix.m41();
    encoder << transformationMatrix.m42();
    encoder << transformationMatrix.m43();
    encoder << transformationMatrix.m44();
}

bool ArgumentCoder<TransformationMatrix>::decode(Decoder& decoder, TransformationMatrix& transformationMatrix)
{
    double m11;
    if (!decoder.decode(m11))
        return false;
    double m12;
    if (!decoder.decode(m12))
        return false;
    double m13;
    if (!decoder.decode(m13))
        return false;
    double m14;
    if (!decoder.decode(m14))
        return false;

    double m21;
    if (!decoder.decode(m21))
        return false;
    double m22;
    if (!decoder.decode(m22))
        return false;
    double m23;
    if (!decoder.decode(m23))
        return false;
    double m24;
    if (!decoder.decode(m24))
        return false;

    double m31;
    if (!decoder.decode(m31))
        return false;
    double m32;
    if (!decoder.decode(m32))
        return false;
    double m33;
    if (!decoder.decode(m33))
        return false;
    double m34;
    if (!decoder.decode(m34))
        return false;

    double m41;
    if (!decoder.decode(m41))
        return false;
    double m42;
    if (!decoder.decode(m42))
        return false;
    double m43;
    if (!decoder.decode(m43))
        return false;
    double m44;
    if (!decoder.decode(m44))
        return false;

    transformationMatrix.setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
    return true;
}

template void ArgumentCoder<TransformationMatrix>::encode<Encoder>(Encoder&, const TransformationMatrix&);
template void ArgumentCoder<TransformationMatrix>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, const TransformationMatrix&);

void ArgumentCoder<LinearTimingFunction>::encode(Encoder& encoder, const LinearTimingFunction& timingFunction)
{
    encoder << timingFunction.type();
}

bool ArgumentCoder<LinearTimingFunction>::decode(Decoder&, LinearTimingFunction&)
{
    // Type is decoded by the caller. Nothing else to decode.
    return true;
}

void ArgumentCoder<CubicBezierTimingFunction>::encode(Encoder& encoder, const CubicBezierTimingFunction& timingFunction)
{
    encoder << timingFunction.type();
    
    encoder << timingFunction.x1();
    encoder << timingFunction.y1();
    encoder << timingFunction.x2();
    encoder << timingFunction.y2();
    
    encoder << timingFunction.timingFunctionPreset();
}

bool ArgumentCoder<CubicBezierTimingFunction>::decode(Decoder& decoder, CubicBezierTimingFunction& timingFunction)
{
    // Type is decoded by the caller.
    double x1;
    if (!decoder.decode(x1))
        return false;

    double y1;
    if (!decoder.decode(y1))
        return false;

    double x2;
    if (!decoder.decode(x2))
        return false;

    double y2;
    if (!decoder.decode(y2))
        return false;

    CubicBezierTimingFunction::TimingFunctionPreset preset;
    if (!decoder.decode(preset))
        return false;

    timingFunction.setValues(x1, y1, x2, y2);
    timingFunction.setTimingFunctionPreset(preset);

    return true;
}

void ArgumentCoder<StepsTimingFunction>::encode(Encoder& encoder, const StepsTimingFunction& timingFunction)
{
    encoder << timingFunction.type();
    
    encoder << timingFunction.numberOfSteps();
    encoder << timingFunction.stepPosition();
}

bool ArgumentCoder<StepsTimingFunction>::decode(Decoder& decoder, StepsTimingFunction& timingFunction)
{
    // Type is decoded by the caller.
    int numSteps;
    if (!decoder.decode(numSteps))
        return false;

    std::optional<StepsTimingFunction::StepPosition> stepPosition;
    if (!decoder.decode(stepPosition))
        return false;

    timingFunction.setNumberOfSteps(numSteps);
    timingFunction.setStepPosition(stepPosition);

    return true;
}

void ArgumentCoder<SpringTimingFunction>::encode(Encoder& encoder, const SpringTimingFunction& timingFunction)
{
    encoder << timingFunction.type();
    
    encoder << timingFunction.mass();
    encoder << timingFunction.stiffness();
    encoder << timingFunction.damping();
    encoder << timingFunction.initialVelocity();
}

bool ArgumentCoder<SpringTimingFunction>::decode(Decoder& decoder, SpringTimingFunction& timingFunction)
{
    // Type is decoded by the caller.
    double mass;
    if (!decoder.decode(mass))
        return false;

    double stiffness;
    if (!decoder.decode(stiffness))
        return false;

    double damping;
    if (!decoder.decode(damping))
        return false;

    double initialVelocity;
    if (!decoder.decode(initialVelocity))
        return false;

    timingFunction.setValues(mass, stiffness, damping, initialVelocity);

    return true;
}

void ArgumentCoder<RectEdges<bool>>::encode(Encoder& encoder, const RectEdges<bool>& boxEdges)
{
    SimpleArgumentCoder<RectEdges<bool>>::encode(encoder, boxEdges);
}
    
bool ArgumentCoder<RectEdges<bool>>::decode(Decoder& decoder, RectEdges<bool>& boxEdges)
{
    return SimpleArgumentCoder<RectEdges<bool>>::decode(decoder, boxEdges);
}

#if ENABLE(META_VIEWPORT)
void ArgumentCoder<ViewportArguments>::encode(Encoder& encoder, const ViewportArguments& viewportArguments)
{
    SimpleArgumentCoder<ViewportArguments>::encode(encoder, viewportArguments);
}

bool ArgumentCoder<ViewportArguments>::decode(Decoder& decoder, ViewportArguments& viewportArguments)
{
    return SimpleArgumentCoder<ViewportArguments>::decode(decoder, viewportArguments);
}

std::optional<ViewportArguments> ArgumentCoder<ViewportArguments>::decode(Decoder& decoder)
{
    ViewportArguments viewportArguments;
    if (!SimpleArgumentCoder<ViewportArguments>::decode(decoder, viewportArguments))
        return std::nullopt;
    return viewportArguments;
}

#endif // ENABLE(META_VIEWPORT)

void ArgumentCoder<ViewportAttributes>::encode(Encoder& encoder, const ViewportAttributes& viewportAttributes)
{
    SimpleArgumentCoder<ViewportAttributes>::encode(encoder, viewportAttributes);
}

bool ArgumentCoder<ViewportAttributes>::decode(Decoder& decoder, ViewportAttributes& viewportAttributes)
{
    return SimpleArgumentCoder<ViewportAttributes>::decode(decoder, viewportAttributes);
}

void ArgumentCoder<RecentSearch>::encode(Encoder& encoder, const RecentSearch& recentSearch)
{
    encoder << recentSearch.string << recentSearch.time;
}

std::optional<RecentSearch> ArgumentCoder<RecentSearch>::decode(Decoder& decoder)
{
    std::optional<String> string;
    decoder >> string;
    if (!string)
        return std::nullopt;
    
    std::optional<WallTime> time;
    decoder >> time;
    if (!time)
        return std::nullopt;
    
    return {{ WTFMove(*string), WTFMove(*time) }};
}

void ArgumentCoder<Length>::encode(Encoder& encoder, const Length& length)
{
    encoder << length.type() << length.hasQuirk();

    switch (length.type()) {
    case LengthType::Auto:
    case LengthType::Content:
    case LengthType::Undefined:
        break;
    case LengthType::Fixed:
    case LengthType::Relative:
    case LengthType::Intrinsic:
    case LengthType::MinIntrinsic:
    case LengthType::MinContent:
    case LengthType::MaxContent:
    case LengthType::FillAvailable:
    case LengthType::FitContent:
    case LengthType::Percent:
        encoder << length.isFloat();
        if (length.isFloat())
            encoder << length.value();
        else
            encoder << length.intValue();
        break;
    case LengthType::Calculated:
        ASSERT_NOT_REACHED();
        break;
    }
}

bool ArgumentCoder<Length>::decode(Decoder& decoder, Length& length)
{
    LengthType type;
    if (!decoder.decode(type))
        return false;

    bool hasQuirk;
    if (!decoder.decode(hasQuirk))
        return false;

    switch (type) {
    case LengthType::Auto:
    case LengthType::Content:
    case LengthType::Undefined:
        length = Length(type);
        return true;
    case LengthType::Fixed:
    case LengthType::Relative:
    case LengthType::Intrinsic:
    case LengthType::MinIntrinsic:
    case LengthType::MinContent:
    case LengthType::MaxContent:
    case LengthType::FillAvailable:
    case LengthType::FitContent:
    case LengthType::Percent: {
        bool isFloat;
        if (!decoder.decode(isFloat))
            return false;

        if (isFloat) {
            float value;
            if (!decoder.decode(value))
                return false;

            length = Length(value, type, hasQuirk);
        } else {
            int value;
            if (!decoder.decode(value))
                return false;

            length = Length(value, type, hasQuirk);
        }
        return true;
    }
    case LengthType::Calculated:
        ASSERT_NOT_REACHED();
        return false;
    }

    return false;
}

void ArgumentCoder<VelocityData>::encode(Encoder& encoder, const VelocityData& velocityData)
{
    encoder << velocityData.horizontalVelocity << velocityData.verticalVelocity << velocityData.scaleChangeRate << velocityData.lastUpdateTime;
}

bool ArgumentCoder<VelocityData>::decode(Decoder& decoder, VelocityData& velocityData)
{
    float horizontalVelocity;
    if (!decoder.decode(horizontalVelocity))
        return false;

    float verticalVelocity;
    if (!decoder.decode(verticalVelocity))
        return false;

    float scaleChangeRate;
    if (!decoder.decode(scaleChangeRate))
        return false;

    MonotonicTime lastUpdateTime;
    if (!decoder.decode(lastUpdateTime))
        return false;

    velocityData.horizontalVelocity = horizontalVelocity;
    velocityData.verticalVelocity = verticalVelocity;
    velocityData.scaleChangeRate = scaleChangeRate;
    velocityData.lastUpdateTime = lastUpdateTime;

    return true;
}

void ArgumentCoder<MimeClassInfo>::encode(Encoder& encoder, const MimeClassInfo& mimeClassInfo)
{
    encoder << mimeClassInfo.type << mimeClassInfo.desc << mimeClassInfo.extensions;
}

std::optional<MimeClassInfo> ArgumentCoder<MimeClassInfo>::decode(Decoder& decoder)
{
    MimeClassInfo mimeClassInfo;
    if (!decoder.decode(mimeClassInfo.type))
        return std::nullopt;
    if (!decoder.decode(mimeClassInfo.desc))
        return std::nullopt;
    if (!decoder.decode(mimeClassInfo.extensions))
        return std::nullopt;

    return mimeClassInfo;
}


void ArgumentCoder<PluginInfo>::encode(Encoder& encoder, const PluginInfo& pluginInfo)
{
    encoder << pluginInfo.name;
    encoder << pluginInfo.file;
    encoder << pluginInfo.desc;
    encoder << pluginInfo.mimes;
    encoder << pluginInfo.isApplicationPlugin;
    encoder << pluginInfo.clientLoadPolicy;
    encoder << pluginInfo.bundleIdentifier;
#if PLATFORM(MAC)
    encoder << pluginInfo.versionString;
#endif
}

std::optional<WebCore::PluginInfo> ArgumentCoder<PluginInfo>::decode(Decoder& decoder)
{
    PluginInfo pluginInfo;
    if (!decoder.decode(pluginInfo.name))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.file))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.desc))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.mimes))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.isApplicationPlugin))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.clientLoadPolicy))
        return std::nullopt;
    if (!decoder.decode(pluginInfo.bundleIdentifier))
        return std::nullopt;
#if PLATFORM(MAC)
    if (!decoder.decode(pluginInfo.versionString))
        return std::nullopt;
#endif

    return pluginInfo;
}

void ArgumentCoder<AuthenticationChallenge>::encode(Encoder& encoder, const AuthenticationChallenge& challenge)
{
    encoder << challenge.protectionSpace() << challenge.proposedCredential() << challenge.previousFailureCount() << challenge.failureResponse() << challenge.error();
#if USE(SOUP)
    encoder << challenge.tlsPasswordFlags();
#endif
}

bool ArgumentCoder<AuthenticationChallenge>::decode(Decoder& decoder, AuthenticationChallenge& challenge)
{    
    ProtectionSpace protectionSpace;
    if (!decoder.decode(protectionSpace))
        return false;

    Credential proposedCredential;
    if (!decoder.decode(proposedCredential))
        return false;

    unsigned previousFailureCount;    
    if (!decoder.decode(previousFailureCount))
        return false;

    ResourceResponse failureResponse;
    if (!decoder.decode(failureResponse))
        return false;

    ResourceError error;
    if (!decoder.decode(error))
        return false;

#if USE(SOUP)
    uint32_t tlsPasswordFlags;
    if (!decoder.decode(tlsPasswordFlags))
        return false;
#endif

    challenge = AuthenticationChallenge(protectionSpace, proposedCredential, previousFailureCount, failureResponse, error);

#if USE(SOUP)
    challenge.setTLSPasswordFlags(tlsPasswordFlags);
#endif
    return true;
}


void ArgumentCoder<ProtectionSpace>::encode(Encoder& encoder, const ProtectionSpace& space)
{
    if (space.encodingRequiresPlatformData()) {
        encoder << true;
        encodePlatformData(encoder, space);
        return;
    }

    encoder << false;
    encoder << space.host() << space.port() << space.realm();
    encoder << space.authenticationScheme();
    encoder << space.serverType();
}

bool ArgumentCoder<ProtectionSpace>::decode(Decoder& decoder, ProtectionSpace& space)
{
    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return false;

    if (hasPlatformData)
        return decodePlatformData(decoder, space);

    String host;
    if (!decoder.decode(host))
        return false;

    int port;
    if (!decoder.decode(port))
        return false;

    String realm;
    if (!decoder.decode(realm))
        return false;
    
    ProtectionSpace::AuthenticationScheme authenticationScheme;
    if (!decoder.decode(authenticationScheme))
        return false;

    ProtectionSpace::ServerType serverType;
    if (!decoder.decode(serverType))
        return false;

    space = ProtectionSpace(host, port, serverType, realm, authenticationScheme);
    return true;
}

void ArgumentCoder<Credential>::encode(Encoder& encoder, const Credential& credential)
{
    if (credential.encodingRequiresPlatformData()) {
        encoder << true;
        encodePlatformData(encoder, credential);
        return;
    }

    encoder << false;
    encoder << credential.user() << credential.password();
    encoder << credential.persistence();
}

bool ArgumentCoder<Credential>::decode(Decoder& decoder, Credential& credential)
{
    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return false;

    if (hasPlatformData)
        return decodePlatformData(decoder, credential);

    String user;
    if (!decoder.decode(user))
        return false;

    String password;
    if (!decoder.decode(password))
        return false;

    CredentialPersistence persistence;
    if (!decoder.decode(persistence))
        return false;
    
    credential = Credential(user, password, persistence);
    return true;
}

static void encodeImage(Encoder& encoder, Image& image)
{
    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(IntSize(image.size()), { });
    auto graphicsContext = bitmap->createGraphicsContext();
    encoder << !!graphicsContext;
    if (!graphicsContext)
        return;

    graphicsContext->drawImage(image, IntPoint());

    ShareableBitmap::Handle handle;
    bitmap->createHandle(handle);

    encoder << handle;
}

static WARN_UNUSED_RETURN bool decodeImage(Decoder& decoder, RefPtr<Image>& image)
{
    std::optional<bool> didCreateGraphicsContext;
    decoder >> didCreateGraphicsContext;
    if (!didCreateGraphicsContext || !*didCreateGraphicsContext)
        return false;

    ShareableBitmap::Handle handle;
    if (!decoder.decode(handle))
        return false;
    
    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(handle);
    if (!bitmap)
        return false;
    image = bitmap->createImage();
    if (!image)
        return false;
    return true;
}

static void encodeOptionalImage(Encoder& encoder, Image* image)
{
    bool hasImage = !!image;
    encoder << hasImage;

    if (hasImage)
        encodeImage(encoder, *image);
}

static WARN_UNUSED_RETURN bool decodeOptionalImage(Decoder& decoder, RefPtr<Image>& image)
{
    image = nullptr;

    bool hasImage;
    if (!decoder.decode(hasImage))
        return false;

    if (!hasImage)
        return true;

    return decodeImage(decoder, image);
}

void ArgumentCoder<WebCore::Font>::encode(Encoder& encoder, const WebCore::Font& font)
{
    encoder << font.origin();
    encoder << (font.isInterstitial() ? Font::Interstitial::Yes : Font::Interstitial::No);
    encoder << font.visibility();
    encoder << (font.isTextOrientationFallback() ? Font::OrientationFallback::Yes : Font::OrientationFallback::No);
    encoder << font.renderingResourceIdentifier();
    // Intentionally don't encode m_isBrokenIdeographFallback because it doesn't affect drawGlyphs().

    encodePlatformData(encoder, font);
}

std::optional<Ref<Font>> ArgumentCoder<Font>::decode(Decoder& decoder)
{
    std::optional<Font::Origin> origin;
    decoder >> origin;
    if (!origin)
        return std::nullopt;

    std::optional<Font::Interstitial> isInterstitial;
    decoder >> isInterstitial;
    if (!isInterstitial)
        return std::nullopt;

    std::optional<Font::Visibility> visibility;
    decoder >> visibility;
    if (!visibility)
        return std::nullopt;

    std::optional<Font::OrientationFallback> isTextOrientationFallback;
    decoder >> isTextOrientationFallback;
    if (!isTextOrientationFallback)
        return std::nullopt;

    std::optional<RenderingResourceIdentifier> renderingResourceIdentifier;
    decoder >> renderingResourceIdentifier;
    if (!renderingResourceIdentifier)
        return std::nullopt;

    auto platformData = decodePlatformData(decoder);
    if (!platformData)
        return std::nullopt;

    return Font::create(platformData.value(), origin.value(), isInterstitial.value(), visibility.value(), isTextOrientationFallback.value(), renderingResourceIdentifier);
}

void ArgumentCoder<DecomposedGlyphs>::encode(Encoder& encoder, const DecomposedGlyphs& decomposedGlyphs)
{
    encoder << decomposedGlyphs.positionedGlyphs();
    encoder << decomposedGlyphs.bounds();
    encoder << decomposedGlyphs.renderingResourceIdentifier();
}

std::optional<Ref<DecomposedGlyphs>> ArgumentCoder<DecomposedGlyphs>::decode(Decoder& decoder)
{
    std::optional<PositionedGlyphs> positionedGlyphs;
    decoder >> positionedGlyphs;
    if (!positionedGlyphs)
        return std::nullopt;

    std::optional<FloatRect> bounds;
    decoder >> bounds;
    if (!bounds)
        return std::nullopt;

    std::optional<RenderingResourceIdentifier> renderingResourceIdentifier;
    decoder >> renderingResourceIdentifier;
    if (!renderingResourceIdentifier)
        return std::nullopt;

    return DecomposedGlyphs::create(WTFMove(*positionedGlyphs), *bounds, *renderingResourceIdentifier);
}

void ArgumentCoder<Cursor>::encode(Encoder& encoder, const Cursor& cursor)
{
    encoder << cursor.type();
        
    if (cursor.type() != Cursor::Custom)
        return;

    if (cursor.image()->isNull()) {
        encoder << false; // There is no valid image being encoded.
        return;
    }

    encoder << true;
    encodeImage(encoder, *cursor.image());
    encoder << cursor.hotSpot();
#if ENABLE(MOUSE_CURSOR_SCALE)
    encoder << cursor.imageScaleFactor();
#endif
}

bool ArgumentCoder<Cursor>::decode(Decoder& decoder, Cursor& cursor)
{
    Cursor::Type type;
    if (!decoder.decode(type))
        return false;

    if (type > Cursor::Custom)
        return false;

    if (type != Cursor::Custom) {
        const Cursor& cursorReference = Cursor::fromType(type);
        // Calling platformCursor here will eagerly create the platform cursor for the cursor singletons inside WebCore.
        // This will avoid having to re-create the platform cursors over and over.
        (void)cursorReference.platformCursor();

        cursor = cursorReference;
        return true;
    }

    bool isValidImagePresent;
    if (!decoder.decode(isValidImagePresent))
        return false;

    if (!isValidImagePresent) {
        cursor = Cursor(&Image::nullImage(), IntPoint());
        return true;
    }

    RefPtr<Image> image;
    if (!decodeImage(decoder, image))
        return false;

    IntPoint hotSpot;
    if (!decoder.decode(hotSpot))
        return false;

    if (!image->rect().contains(hotSpot))
        return false;

#if ENABLE(MOUSE_CURSOR_SCALE)
    float scale;
    if (!decoder.decode(scale))
        return false;

    cursor = Cursor(image.get(), hotSpot, scale);
#else
    cursor = Cursor(image.get(), hotSpot);
#endif
    return true;
}

void ArgumentCoder<ResourceRequest>::encode(Encoder& encoder, const ResourceRequest& resourceRequest)
{
    if (resourceRequest.encodingRequiresPlatformData()) {
        encoder << true;
        encodePlatformData(encoder, resourceRequest);
    } else {
        encoder << false;
        resourceRequest.encodeWithoutPlatformData(encoder);
    }

    encoder << resourceRequest.cachePartition();
    encoder << resourceRequest.hiddenFromInspector();

#if USE(SYSTEM_PREVIEW)
    if (resourceRequest.isSystemPreview()) {
        encoder << true;
        encoder << resourceRequest.systemPreviewInfo();
    } else
        encoder << false;
#endif
}

bool ArgumentCoder<ResourceRequest>::decode(Decoder& decoder, ResourceRequest& resourceRequest)
{
    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return false;

    bool decodeSuccess = hasPlatformData ? decodePlatformData(decoder, resourceRequest) : resourceRequest.decodeWithoutPlatformData(decoder);
    if (!decodeSuccess)
        return false;

    String cachePartition;
    if (!decoder.decode(cachePartition))
        return false;
    resourceRequest.setCachePartition(cachePartition);

    bool isHiddenFromInspector;
    if (!decoder.decode(isHiddenFromInspector))
        return false;
    resourceRequest.setHiddenFromInspector(isHiddenFromInspector);

#if USE(SYSTEM_PREVIEW)
    bool isSystemPreview;
    if (!decoder.decode(isSystemPreview))
        return false;

    if (isSystemPreview) {
        SystemPreviewInfo systemPreviewInfo;
        if (!decoder.decode(systemPreviewInfo))
            return false;
        resourceRequest.setSystemPreviewInfo(systemPreviewInfo);
    }
#endif

    return true;
}

void ArgumentCoder<ResourceError>::encode(Encoder& encoder, const ResourceError& resourceError)
{
    encoder << resourceError.type();
    if (resourceError.type() == ResourceError::Type::Null)
        return;
    encodePlatformData(encoder, resourceError);
    encoder << resourceError.isSanitized();
}

bool ArgumentCoder<ResourceError>::decode(Decoder& decoder, ResourceError& resourceError)
{
    ResourceError::Type type;
    if (!decoder.decode(type))
        return false;

    if (type == ResourceError::Type::Null) {
        resourceError = { };
        return true;
    }

    if (!decodePlatformData(decoder, resourceError))
        return false;

    bool isSanitized;
    if (!decoder.decode(isSanitized))
        return false;

    resourceError.setType(type);
    if (isSanitized)
        resourceError.setAsSanitized();

    return true;
}

#if PLATFORM(IOS_FAMILY)

void ArgumentCoder<SelectionGeometry>::encode(Encoder& encoder, const SelectionGeometry& selectionGeometry)
{
    encoder << selectionGeometry.quad();
    encoder << selectionGeometry.behavior();
    encoder << static_cast<uint32_t>(selectionGeometry.direction());
    encoder << selectionGeometry.minX();
    encoder << selectionGeometry.maxX();
    encoder << selectionGeometry.maxY();
    encoder << selectionGeometry.lineNumber();
    encoder << selectionGeometry.isLineBreak();
    encoder << selectionGeometry.isFirstOnLine();
    encoder << selectionGeometry.isLastOnLine();
    encoder << selectionGeometry.containsStart();
    encoder << selectionGeometry.containsEnd();
    encoder << selectionGeometry.isHorizontal();
}

std::optional<SelectionGeometry> ArgumentCoder<SelectionGeometry>::decode(Decoder& decoder)
{
    SelectionGeometry selectionGeometry;
    FloatQuad quad;
    if (!decoder.decode(quad))
        return std::nullopt;
    selectionGeometry.setQuad(quad);

    std::optional<SelectionRenderingBehavior> behavior;
    decoder >> behavior;
    if (!behavior)
        return std::nullopt;
    selectionGeometry.setBehavior(*behavior);

    uint32_t direction;
    if (!decoder.decode(direction))
        return std::nullopt;
    selectionGeometry.setDirection((TextDirection)direction);

    int intValue;
    if (!decoder.decode(intValue))
        return std::nullopt;
    selectionGeometry.setMinX(intValue);

    if (!decoder.decode(intValue))
        return std::nullopt;
    selectionGeometry.setMaxX(intValue);

    if (!decoder.decode(intValue))
        return std::nullopt;
    selectionGeometry.setMaxY(intValue);

    if (!decoder.decode(intValue))
        return std::nullopt;
    selectionGeometry.setLineNumber(intValue);

    bool boolValue;
    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setIsLineBreak(boolValue);

    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setIsFirstOnLine(boolValue);

    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setIsLastOnLine(boolValue);

    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setContainsStart(boolValue);

    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setContainsEnd(boolValue);

    if (!decoder.decode(boolValue))
        return std::nullopt;
    selectionGeometry.setIsHorizontal(boolValue);

    return selectionGeometry;
}

#endif

void ArgumentCoder<WindowFeatures>::encode(Encoder& encoder, const WindowFeatures& windowFeatures)
{
    encoder << windowFeatures.x;
    encoder << windowFeatures.y;
    encoder << windowFeatures.width;
    encoder << windowFeatures.height;
    encoder << windowFeatures.menuBarVisible;
    encoder << windowFeatures.statusBarVisible;
    encoder << windowFeatures.toolBarVisible;
    encoder << windowFeatures.locationBarVisible;
    encoder << windowFeatures.scrollbarsVisible;
    encoder << windowFeatures.resizable;
    encoder << windowFeatures.fullscreen;
    encoder << windowFeatures.dialog;
}

bool ArgumentCoder<WindowFeatures>::decode(Decoder& decoder, WindowFeatures& windowFeatures)
{
    if (!decoder.decode(windowFeatures.x))
        return false;
    if (!decoder.decode(windowFeatures.y))
        return false;
    if (!decoder.decode(windowFeatures.width))
        return false;
    if (!decoder.decode(windowFeatures.height))
        return false;
    if (!decoder.decode(windowFeatures.menuBarVisible))
        return false;
    if (!decoder.decode(windowFeatures.statusBarVisible))
        return false;
    if (!decoder.decode(windowFeatures.toolBarVisible))
        return false;
    if (!decoder.decode(windowFeatures.locationBarVisible))
        return false;
    if (!decoder.decode(windowFeatures.scrollbarsVisible))
        return false;
    if (!decoder.decode(windowFeatures.resizable))
        return false;
    if (!decoder.decode(windowFeatures.fullscreen))
        return false;
    if (!decoder.decode(windowFeatures.dialog))
        return false;
    return true;
}

#if ENABLE(DRAG_SUPPORT)
void ArgumentCoder<DragData>::encode(Encoder& encoder, const DragData& dragData)
{
    encoder << dragData.clientPosition();
    encoder << dragData.globalPosition();
    encoder << dragData.draggingSourceOperationMask();
    encoder << dragData.flags();
#if PLATFORM(COCOA)
    encoder << dragData.pasteboardName();
    encoder << dragData.fileNames();
#endif
    encoder << dragData.dragDestinationActionMask();
    encoder << dragData.pageID();
}

bool ArgumentCoder<DragData>::decode(Decoder& decoder, DragData& dragData)
{
    IntPoint clientPosition;
    if (!decoder.decode(clientPosition))
        return false;

    IntPoint globalPosition;
    if (!decoder.decode(globalPosition))
        return false;

    OptionSet<DragOperation> draggingSourceOperationMask;
    if (!decoder.decode(draggingSourceOperationMask))
        return false;

    OptionSet<DragApplicationFlags> applicationFlags;
    if (!decoder.decode(applicationFlags))
        return false;

    String pasteboardName;
    Vector<String> fileNames;
#if PLATFORM(COCOA)
    if (!decoder.decode(pasteboardName))
        return false;

    if (!decoder.decode(fileNames))
        return false;
#endif

    OptionSet<DragDestinationAction> dragDestinationActionMask;
    if (!decoder.decode(dragDestinationActionMask))
        return false;

    std::optional<PageIdentifier> pageID;
    if (!decoder.decode(pageID))
        return false;

    dragData = DragData(pasteboardName, clientPosition, globalPosition, draggingSourceOperationMask, applicationFlags, dragDestinationActionMask, pageID);
    dragData.setFileNames(fileNames);

    return true;
}
#endif

void ArgumentCoder<CompositionUnderline>::encode(Encoder& encoder, const CompositionUnderline& underline)
{
    encoder << underline.startOffset;
    encoder << underline.endOffset;
    encoder << underline.thick;
    encoder << underline.compositionUnderlineColor;
    encoder << underline.color;
}

std::optional<CompositionUnderline> ArgumentCoder<CompositionUnderline>::decode(Decoder& decoder)
{
    CompositionUnderline underline;

    if (!decoder.decode(underline.startOffset))
        return std::nullopt;
    if (!decoder.decode(underline.endOffset))
        return std::nullopt;
    if (!decoder.decode(underline.thick))
        return std::nullopt;
    if (!decoder.decode(underline.compositionUnderlineColor))
        return std::nullopt;
    if (!decoder.decode(underline.color))
        return std::nullopt;

    return underline;
}

void ArgumentCoder<DatabaseDetails>::encode(Encoder& encoder, const DatabaseDetails& details)
{
    encoder << details.name();
    encoder << details.displayName();
    encoder << details.expectedUsage();
    encoder << details.currentUsage();
    encoder << details.creationTime();
    encoder << details.modificationTime();
}
    
bool ArgumentCoder<DatabaseDetails>::decode(Decoder& decoder, DatabaseDetails& details)
{
    String name;
    if (!decoder.decode(name))
        return false;

    String displayName;
    if (!decoder.decode(displayName))
        return false;

    uint64_t expectedUsage;
    if (!decoder.decode(expectedUsage))
        return false;

    uint64_t currentUsage;
    if (!decoder.decode(currentUsage))
        return false;

    std::optional<WallTime> creationTime;
    if (!decoder.decode(creationTime))
        return false;

    std::optional<WallTime> modificationTime;
    if (!decoder.decode(modificationTime))
        return false;

    details = DatabaseDetails(name, displayName, expectedUsage, currentUsage, creationTime, modificationTime);
    return true;
}

template<> struct ArgumentCoder<PasteboardCustomData::Entry> {
    static void encode(Encoder&, const PasteboardCustomData::Entry&);
    static WARN_UNUSED_RETURN bool decode(Decoder&, PasteboardCustomData::Entry&);
};

void ArgumentCoder<PasteboardCustomData::Entry>::encode(Encoder& encoder, const PasteboardCustomData::Entry& data)
{
    encoder << data.type << data.customData << data.platformData;
}

bool ArgumentCoder<PasteboardCustomData::Entry>::decode(Decoder& decoder, PasteboardCustomData::Entry& data)
{
    return decoder.decode(data.type) && decoder.decode(data.customData) && decoder.decode(data.platformData);
}

void ArgumentCoder<PasteboardCustomData>::encode(Encoder& encoder, const PasteboardCustomData& data)
{
    encoder << data.origin();
    encoder << data.data();
}

bool ArgumentCoder<PasteboardCustomData>::decode(Decoder& decoder, PasteboardCustomData& data)
{
    String origin;
    if (!decoder.decode(origin))
        return false;

    Vector<PasteboardCustomData::Entry> items;
    if (!decoder.decode(items))
        return false;

    data = PasteboardCustomData(WTFMove(origin), WTFMove(items));
    return true;
}

void ArgumentCoder<PasteboardURL>::encode(Encoder& encoder, const PasteboardURL& content)
{
    encoder << content.url;
    encoder << content.title;
#if PLATFORM(MAC)
    encoder << content.userVisibleForm;
#endif
#if PLATFORM(GTK)
    encoder << content.markup;
#endif
}

bool ArgumentCoder<PasteboardURL>::decode(Decoder& decoder, PasteboardURL& content)
{
    if (!decoder.decode(content.url))
        return false;

    if (!decoder.decode(content.title))
        return false;

#if PLATFORM(MAC)
    if (!decoder.decode(content.userVisibleForm))
        return false;
#endif
#if PLATFORM(GTK)
    if (!decoder.decode(content.markup))
        return false;
#endif

    return true;
}

#if PLATFORM(IOS_FAMILY)

void ArgumentCoder<InspectorOverlay::Highlight>::encode(Encoder& encoder, const InspectorOverlay::Highlight& highlight)
{
    encoder << static_cast<uint32_t>(highlight.type);
    encoder << highlight.usePageCoordinates;
    encoder << highlight.contentColor;
    encoder << highlight.contentOutlineColor;
    encoder << highlight.paddingColor;
    encoder << highlight.borderColor;
    encoder << highlight.marginColor;
    encoder << highlight.quads;
    encoder << highlight.gridHighlightOverlays;
    encoder << highlight.flexHighlightOverlays;
}

bool ArgumentCoder<InspectorOverlay::Highlight>::decode(Decoder& decoder, InspectorOverlay::Highlight& highlight)
{
    uint32_t type;
    if (!decoder.decode(type))
        return false;
    highlight.type = (InspectorOverlay::Highlight::Type)type;

    if (!decoder.decode(highlight.usePageCoordinates))
        return false;
    if (!decoder.decode(highlight.contentColor))
        return false;
    if (!decoder.decode(highlight.contentOutlineColor))
        return false;
    if (!decoder.decode(highlight.paddingColor))
        return false;
    if (!decoder.decode(highlight.borderColor))
        return false;
    if (!decoder.decode(highlight.marginColor))
        return false;
    if (!decoder.decode(highlight.quads))
        return false;
    if (!decoder.decode(highlight.gridHighlightOverlays))
        return false;
    if (!decoder.decode(highlight.flexHighlightOverlays))
        return false;
    return true;
}

void ArgumentCoder<PasteboardWebContent>::encode(Encoder& encoder, const PasteboardWebContent& content)
{
    encoder << content.contentOrigin;
    encoder << content.canSmartCopyOrDelete;
    encoder << content.dataInStringFormat;
    encoder << content.dataInHTMLFormat;

    encoder << content.dataInWebArchiveFormat;
    encoder << content.dataInRTFDFormat;
    encoder << content.dataInRTFFormat;
    encoder << content.dataInAttributedStringFormat;

    encoder << content.clientTypes;
    encoder << content.clientData;
}

bool ArgumentCoder<PasteboardWebContent>::decode(Decoder& decoder, PasteboardWebContent& content)
{
    if (!decoder.decode(content.contentOrigin))
        return false;
    if (!decoder.decode(content.canSmartCopyOrDelete))
        return false;
    if (!decoder.decode(content.dataInStringFormat))
        return false;
    if (!decoder.decode(content.dataInHTMLFormat))
        return false;

    if (!decoder.decode(content.dataInWebArchiveFormat))
        return false;
    if (!decoder.decode(content.dataInRTFDFormat))
        return false;
    if (!decoder.decode(content.dataInRTFFormat))
        return false;
    if (!decoder.decode(content.dataInAttributedStringFormat))
        return false;
    if (!decoder.decode(content.clientTypes))
        return false;
    if (!decoder.decode(content.clientData))
        return false;

    return true;
}

void ArgumentCoder<PasteboardImage>::encode(Encoder& encoder, const PasteboardImage& pasteboardImage)
{
    encodeOptionalImage(encoder, pasteboardImage.image.get());
    encoder << pasteboardImage.url.url;
    encoder << pasteboardImage.url.title;
    encoder << pasteboardImage.resourceMIMEType;
    encoder << pasteboardImage.suggestedName;
    encoder << pasteboardImage.imageSize;
    encoder << pasteboardImage.resourceData;
    encoder << pasteboardImage.clientTypes;
    encoder << pasteboardImage.clientData;
}

bool ArgumentCoder<PasteboardImage>::decode(Decoder& decoder, PasteboardImage& pasteboardImage)
{
    if (!decodeOptionalImage(decoder, pasteboardImage.image))
        return false;
    if (!decoder.decode(pasteboardImage.url.url))
        return false;
    if (!decoder.decode(pasteboardImage.url.title))
        return false;
    if (!decoder.decode(pasteboardImage.resourceMIMEType))
        return false;
    if (!decoder.decode(pasteboardImage.suggestedName))
        return false;
    if (!decoder.decode(pasteboardImage.imageSize))
        return false;
    if (!decoder.decode(pasteboardImage.resourceData))
        return false;
    if (!decoder.decode(pasteboardImage.clientTypes))
        return false;
    if (!decoder.decode(pasteboardImage.clientData))
        return false;

    return true;
}

#endif

#if USE(LIBWPE)
void ArgumentCoder<PasteboardWebContent>::encode(Encoder& encoder, const PasteboardWebContent& content)
{
    encoder << content.text;
    encoder << content.markup;
}

bool ArgumentCoder<PasteboardWebContent>::decode(Decoder& decoder, PasteboardWebContent& content)
{
    if (!decoder.decode(content.text))
        return false;
    if (!decoder.decode(content.markup))
        return false;
    return true;
}
#endif // USE(LIBWPE)

void ArgumentCoder<DictationAlternative>::encode(Encoder& encoder, const DictationAlternative& alternative)
{
    encoder << alternative.range << alternative.context;
}

std::optional<DictationAlternative> ArgumentCoder<DictationAlternative>::decode(Decoder& decoder)
{
    std::optional<CharacterRange> range;
    decoder >> range;
    if (!range)
        return std::nullopt;

    std::optional<DictationContext> context;
    decoder >> context;
    if (!context)
        return std::nullopt;

    return {{ *range, *context }};
}

void ArgumentCoder<FileChooserSettings>::encode(Encoder& encoder, const FileChooserSettings& settings)
{
    encoder << settings.allowsDirectories;
    encoder << settings.allowsMultipleFiles;
    encoder << settings.acceptMIMETypes;
    encoder << settings.acceptFileExtensions;
    encoder << settings.selectedFiles;
#if ENABLE(MEDIA_CAPTURE)
    encoder << settings.mediaCaptureType;
#endif
}

bool ArgumentCoder<FileChooserSettings>::decode(Decoder& decoder, FileChooserSettings& settings)
{
    if (!decoder.decode(settings.allowsDirectories))
        return false;
    if (!decoder.decode(settings.allowsMultipleFiles))
        return false;
    if (!decoder.decode(settings.acceptMIMETypes))
        return false;
    if (!decoder.decode(settings.acceptFileExtensions))
        return false;
    if (!decoder.decode(settings.selectedFiles))
        return false;
#if ENABLE(MEDIA_CAPTURE)
    if (!decoder.decode(settings.mediaCaptureType))
        return false;
#endif

    return true;
}

void ArgumentCoder<RawFile>::encode(Encoder& encoder, const RawFile& file)
{
    encoder << file.fileName;
    encoder << file.fileData;
}

bool ArgumentCoder<RawFile>::decode(Decoder& decoder, RawFile& file)
{
    if (!decoder.decode(file.fileName))
        return false;
    if (!decoder.decode(file.fileData))
        return false;
    return true;
}
    
void ArgumentCoder<ShareData>::encode(Encoder& encoder, const ShareData& settings)
{
    encoder << settings.title;
    encoder << settings.text;
    encoder << settings.url;
}

bool ArgumentCoder<ShareData>::decode(Decoder& decoder, ShareData& settings)
{
    if (!decoder.decode(settings.title))
        return false;
    if (!decoder.decode(settings.text))
        return false;
    if (!decoder.decode(settings.url))
        return false;
    return true;
}
    
void ArgumentCoder<ShareDataWithParsedURL>::encode(Encoder& encoder, const ShareDataWithParsedURL& settings)
{
    encoder << settings.shareData;
    encoder << settings.url;
    encoder << settings.files;
}

bool ArgumentCoder<ShareDataWithParsedURL>::decode(Decoder& decoder, ShareDataWithParsedURL& settings)
{
    if (!decoder.decode(settings.shareData))
        return false;
    if (!decoder.decode(settings.url))
        return false;
    if (!decoder.decode(settings.files))
        return false;
    return true;
}

void ArgumentCoder<GrammarDetail>::encode(Encoder& encoder, const GrammarDetail& detail)
{
    encoder << detail.range;
    encoder << detail.guesses;
    encoder << detail.userDescription;
}

std::optional<GrammarDetail> ArgumentCoder<GrammarDetail>::decode(Decoder& decoder)
{
    std::optional<CharacterRange> range;
    decoder >> range;
    if (!range)
        return std::nullopt;

    std::optional<Vector<String>> guesses;
    decoder >> guesses;
    if (!guesses)
        return std::nullopt;

    std::optional<String> userDescription;
    decoder >> userDescription;
    if (!userDescription)
        return std::nullopt;

    return { { *range, WTFMove(*guesses), WTFMove(*userDescription) } };
}

void ArgumentCoder<TextCheckingRequestData>::encode(Encoder& encoder, const TextCheckingRequestData& request)
{
    encoder << request.identifier();
    encoder << request.text();
    encoder << request.checkingTypes();
    encoder << request.processType();
}

bool ArgumentCoder<TextCheckingRequestData>::decode(Decoder& decoder, TextCheckingRequestData& request)
{
    std::optional<TextCheckingRequestIdentifier> identifier;
    if (!decoder.decode(identifier))
        return false;

    String text;
    if (!decoder.decode(text))
        return false;

    OptionSet<TextCheckingType> checkingTypes;
    if (!decoder.decode(checkingTypes))
        return false;

    TextCheckingProcessType processType;
    if (!decoder.decode(processType))
        return false;

    request = TextCheckingRequestData { identifier, text, checkingTypes, processType };
    return true;
}

void ArgumentCoder<TextCheckingResult>::encode(Encoder& encoder, const TextCheckingResult& result)
{
    encoder << result.type;
    encoder << result.range;
    encoder << result.details;
    encoder << result.replacement;
}

std::optional<TextCheckingResult> ArgumentCoder<TextCheckingResult>::decode(Decoder& decoder)
{
    TextCheckingType type;
    if (!decoder.decode(type))
        return std::nullopt;
    
    std::optional<CharacterRange> range;
    decoder >> range;
    if (!range)
        return std::nullopt;

    std::optional<Vector<GrammarDetail>> details;
    decoder >> details;
    if (!details)
        return std::nullopt;

    std::optional<String> replacement;
    decoder >> replacement;
    if (!replacement)
        return std::nullopt;

    return { { type, *range, WTFMove(*details), WTFMove(*replacement) } };
}

void ArgumentCoder<UserStyleSheet>::encode(Encoder& encoder, const UserStyleSheet& userStyleSheet)
{
    encoder << userStyleSheet.source();
    encoder << userStyleSheet.url();
    encoder << userStyleSheet.allowlist();
    encoder << userStyleSheet.blocklist();
    encoder << userStyleSheet.injectedFrames();
    encoder << userStyleSheet.level();
    encoder << userStyleSheet.pageID();
}

bool ArgumentCoder<UserStyleSheet>::decode(Decoder& decoder, UserStyleSheet& userStyleSheet)
{
    String source;
    if (!decoder.decode(source))
        return false;

    URL url;
    if (!decoder.decode(url))
        return false;

    Vector<String> allowlist;
    if (!decoder.decode(allowlist))
        return false;

    Vector<String> blocklist;
    if (!decoder.decode(blocklist))
        return false;

    UserContentInjectedFrames injectedFrames;
    if (!decoder.decode(injectedFrames))
        return false;

    UserStyleLevel level;
    if (!decoder.decode(level))
        return false;

    std::optional<std::optional<PageIdentifier>> pageID;
    decoder >> pageID;
    if (!pageID)
        return false;

    userStyleSheet = UserStyleSheet(source, url, WTFMove(allowlist), WTFMove(blocklist), injectedFrames, level, WTFMove(*pageID));
    return true;
}

void ArgumentCoder<ScrollableAreaParameters>::encode(Encoder& encoder, const ScrollableAreaParameters& parameters)
{
    encoder << parameters.horizontalScrollElasticity;
    encoder << parameters.verticalScrollElasticity;

    encoder << parameters.horizontalScrollbarMode;
    encoder << parameters.verticalScrollbarMode;
    
    encoder << parameters.horizontalOverscrollBehavior;
    encoder << parameters.verticalOverscrollBehavior;

    encoder << parameters.allowsHorizontalScrolling;
    encoder << parameters.allowsVerticalScrolling;

    encoder << parameters.horizontalScrollbarHiddenByStyle;
    encoder << parameters.verticalScrollbarHiddenByStyle;

    encoder << parameters.useDarkAppearanceForScrollbars;
}

bool ArgumentCoder<ScrollableAreaParameters>::decode(Decoder& decoder, ScrollableAreaParameters& params)
{
    if (!decoder.decode(params.horizontalScrollElasticity))
        return false;
    if (!decoder.decode(params.verticalScrollElasticity))
        return false;

    if (!decoder.decode(params.horizontalScrollbarMode))
        return false;
    if (!decoder.decode(params.verticalScrollbarMode))
        return false;
    
    if (!decoder.decode(params.horizontalOverscrollBehavior))
        return false;
    if (!decoder.decode(params.verticalOverscrollBehavior))
        return false;

    if (!decoder.decode(params.allowsHorizontalScrolling))
        return false;
    if (!decoder.decode(params.allowsVerticalScrolling))
        return false;

    if (!decoder.decode(params.horizontalScrollbarHiddenByStyle))
        return false;
    if (!decoder.decode(params.verticalScrollbarHiddenByStyle))
        return false;

    if (!decoder.decode(params.useDarkAppearanceForScrollbars))
        return false;

    return true;
}

void ArgumentCoder<FixedPositionViewportConstraints>::encode(Encoder& encoder, const FixedPositionViewportConstraints& viewportConstraints)
{
    encoder << viewportConstraints.alignmentOffset();
    encoder << viewportConstraints.anchorEdges();

    encoder << viewportConstraints.viewportRectAtLastLayout();
    encoder << viewportConstraints.layerPositionAtLastLayout();
}

bool ArgumentCoder<FixedPositionViewportConstraints>::decode(Decoder& decoder, FixedPositionViewportConstraints& viewportConstraints)
{
    FloatSize alignmentOffset;
    if (!decoder.decode(alignmentOffset))
        return false;
    
    ViewportConstraints::AnchorEdges anchorEdges;
    if (!decoder.decode(anchorEdges))
        return false;

    FloatRect viewportRectAtLastLayout;
    if (!decoder.decode(viewportRectAtLastLayout))
        return false;

    FloatPoint layerPositionAtLastLayout;
    if (!decoder.decode(layerPositionAtLastLayout))
        return false;

    viewportConstraints = FixedPositionViewportConstraints();
    viewportConstraints.setAlignmentOffset(alignmentOffset);
    viewportConstraints.setAnchorEdges(anchorEdges);

    viewportConstraints.setViewportRectAtLastLayout(viewportRectAtLastLayout);
    viewportConstraints.setLayerPositionAtLastLayout(layerPositionAtLastLayout);
    
    return true;
}

void ArgumentCoder<AbsolutePositionConstraints>::encode(Encoder& encoder, const AbsolutePositionConstraints& layoutConstraints)
{
    encoder << layoutConstraints.alignmentOffset();
    encoder << layoutConstraints.layerPositionAtLastLayout();
}

bool ArgumentCoder<AbsolutePositionConstraints>::decode(Decoder& decoder, AbsolutePositionConstraints& layoutConstraints)
{
    FloatSize alignmentOffset;
    if (!decoder.decode(alignmentOffset))
        return false;

    FloatPoint layerPosition;
    if (!decoder.decode(layerPosition))
        return false;

    layoutConstraints = { };
    layoutConstraints.setAlignmentOffset(alignmentOffset);
    layoutConstraints.setLayerPositionAtLastLayout(layerPosition);
    return true;
}

void ArgumentCoder<StickyPositionViewportConstraints>::encode(Encoder& encoder, const StickyPositionViewportConstraints& viewportConstraints)
{
    encoder << viewportConstraints.alignmentOffset();
    encoder << viewportConstraints.anchorEdges();

    encoder << viewportConstraints.leftOffset();
    encoder << viewportConstraints.rightOffset();
    encoder << viewportConstraints.topOffset();
    encoder << viewportConstraints.bottomOffset();

    encoder << viewportConstraints.constrainingRectAtLastLayout();
    encoder << viewportConstraints.containingBlockRect();
    encoder << viewportConstraints.stickyBoxRect();

    encoder << viewportConstraints.stickyOffsetAtLastLayout();
    encoder << viewportConstraints.layerPositionAtLastLayout();
}

bool ArgumentCoder<StickyPositionViewportConstraints>::decode(Decoder& decoder, StickyPositionViewportConstraints& viewportConstraints)
{
    FloatSize alignmentOffset;
    if (!decoder.decode(alignmentOffset))
        return false;
    
    ViewportConstraints::AnchorEdges anchorEdges;
    if (!decoder.decode(anchorEdges))
        return false;
    
    float leftOffset;
    if (!decoder.decode(leftOffset))
        return false;

    float rightOffset;
    if (!decoder.decode(rightOffset))
        return false;

    float topOffset;
    if (!decoder.decode(topOffset))
        return false;

    float bottomOffset;
    if (!decoder.decode(bottomOffset))
        return false;
    
    FloatRect constrainingRectAtLastLayout;
    if (!decoder.decode(constrainingRectAtLastLayout))
        return false;

    FloatRect containingBlockRect;
    if (!decoder.decode(containingBlockRect))
        return false;

    FloatRect stickyBoxRect;
    if (!decoder.decode(stickyBoxRect))
        return false;

    FloatSize stickyOffsetAtLastLayout;
    if (!decoder.decode(stickyOffsetAtLastLayout))
        return false;
    
    FloatPoint layerPositionAtLastLayout;
    if (!decoder.decode(layerPositionAtLastLayout))
        return false;

    viewportConstraints = StickyPositionViewportConstraints();
    viewportConstraints.setAlignmentOffset(alignmentOffset);
    viewportConstraints.setAnchorEdges(anchorEdges);

    viewportConstraints.setLeftOffset(leftOffset);
    viewportConstraints.setRightOffset(rightOffset);
    viewportConstraints.setTopOffset(topOffset);
    viewportConstraints.setBottomOffset(bottomOffset);
    
    viewportConstraints.setConstrainingRectAtLastLayout(constrainingRectAtLastLayout);
    viewportConstraints.setContainingBlockRect(containingBlockRect);
    viewportConstraints.setStickyBoxRect(stickyBoxRect);

    viewportConstraints.setStickyOffsetAtLastLayout(stickyOffsetAtLastLayout);
    viewportConstraints.setLayerPositionAtLastLayout(layerPositionAtLastLayout);

    return true;
}

#if !USE(COORDINATED_GRAPHICS)
void ArgumentCoder<FilterOperation>::encode(Encoder& encoder, const FilterOperation& filter)
{
    encoder << filter.type();

    switch (filter.type()) {
    case FilterOperation::NONE:
    case FilterOperation::REFERENCE:
        ASSERT_NOT_REACHED();
        return;
    case FilterOperation::GRAYSCALE:
    case FilterOperation::SEPIA:
    case FilterOperation::SATURATE:
    case FilterOperation::HUE_ROTATE:
        encoder << downcast<BasicColorMatrixFilterOperation>(filter).amount();
        return;
    case FilterOperation::INVERT:
    case FilterOperation::OPACITY:
    case FilterOperation::BRIGHTNESS:
    case FilterOperation::CONTRAST:
        encoder << downcast<BasicComponentTransferFilterOperation>(filter).amount();
        return;
    case FilterOperation::APPLE_INVERT_LIGHTNESS:
        ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
        return;
    case FilterOperation::BLUR:
        encoder << downcast<BlurFilterOperation>(filter).stdDeviation();
        return;
    case FilterOperation::DROP_SHADOW: {
        const auto& dropShadowFilter = downcast<DropShadowFilterOperation>(filter);
        encoder << dropShadowFilter.location();
        encoder << dropShadowFilter.stdDeviation();
        encoder << dropShadowFilter.color();
        return;
    }
    case FilterOperation::DEFAULT:
        encoder << downcast<DefaultFilterOperation>(filter).representedType();
        return;
    case FilterOperation::PASSTHROUGH:
        return;
    }

    ASSERT_NOT_REACHED();
}

bool decodeFilterOperation(Decoder& decoder, RefPtr<FilterOperation>& filter)
{
    FilterOperation::OperationType type;
    if (!decoder.decode(type))
        return false;

    switch (type) {
    case FilterOperation::NONE:
    case FilterOperation::REFERENCE:
        ASSERT_NOT_REACHED();
        return false;
    case FilterOperation::GRAYSCALE:
    case FilterOperation::SEPIA:
    case FilterOperation::SATURATE:
    case FilterOperation::HUE_ROTATE: {
        double amount;
        if (!decoder.decode(amount))
            return false;
        filter = BasicColorMatrixFilterOperation::create(amount, type);
        return true;
    }
    case FilterOperation::INVERT:
    case FilterOperation::OPACITY:
    case FilterOperation::BRIGHTNESS:
    case FilterOperation::CONTRAST: {
        double amount;
        if (!decoder.decode(amount))
            return false;
        filter = BasicComponentTransferFilterOperation::create(amount, type);
        return true;
    }
    case FilterOperation::APPLE_INVERT_LIGHTNESS:
        ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
        return false;
    case FilterOperation::BLUR: {
        Length stdDeviation;
        if (!decoder.decode(stdDeviation))
            return false;
        filter = BlurFilterOperation::create(stdDeviation);
        return true;
    }
    case FilterOperation::DROP_SHADOW: {
        IntPoint location;
        int stdDeviation;
        Color color;
        if (!decoder.decode(location))
            return false;
        if (!decoder.decode(stdDeviation))
            return false;
        if (!decoder.decode(color))
            return false;
        filter = DropShadowFilterOperation::create(location, stdDeviation, color);
        return true;
    }
    case FilterOperation::DEFAULT: {
        FilterOperation::OperationType representedType;
        if (!decoder.decode(representedType))
            return false;
        filter = DefaultFilterOperation::create(representedType);
        return true;
    }
    case FilterOperation::PASSTHROUGH:
        filter = PassthroughFilterOperation::create();
        return true;
    }
            
    ASSERT_NOT_REACHED();
    return false;
}


void ArgumentCoder<FilterOperations>::encode(Encoder& encoder, const FilterOperations& filters)
{
    encoder << static_cast<uint64_t>(filters.size());

    for (const auto& filter : filters.operations())
        encoder << *filter;
}

bool ArgumentCoder<FilterOperations>::decode(Decoder& decoder, FilterOperations& filters)
{
    uint64_t filterCount;
    if (!decoder.decode(filterCount))
        return false;

    for (uint64_t i = 0; i < filterCount; ++i) {
        RefPtr<FilterOperation> filter;
        if (!decodeFilterOperation(decoder, filter))
            return false;
        filters.operations().append(WTFMove(filter));
    }

    return true;
}

void ArgumentCoder<RefPtr<WebCore::FilterOperation>>::encode(Encoder& encoder, const RefPtr<WebCore::FilterOperation>& operation)
{
    encoder << !!operation;
    if (operation)
        encoder << *operation;
}

WARN_UNUSED_RETURN bool ArgumentCoder<RefPtr<WebCore::FilterOperation>>::decode(Decoder& decoder, RefPtr<WebCore::FilterOperation>& value)
{
    std::optional<bool> isNull;
    decoder >> isNull;
    if (!isNull)
        return false;
    
    if (!decodeFilterOperation(decoder, value)) {
        value = nullptr;
        return false;
    }
    return true;
}

#endif // !USE(COORDINATED_GRAPHICS)

void ArgumentCoder<BlobPart>::encode(Encoder& encoder, const BlobPart& blobPart)
{
    encoder << blobPart.type();
    switch (blobPart.type()) {
    case BlobPart::Type::Data:
        encoder << blobPart.data();
        return;
    case BlobPart::Type::Blob:
        encoder << blobPart.url();
        return;
    }
    ASSERT_NOT_REACHED();
}

std::optional<BlobPart> ArgumentCoder<BlobPart>::decode(Decoder& decoder)
{
    std::optional<BlobPart::Type> type;
    decoder >> type;
    if (!type)
        return std::nullopt;

    switch (*type) {
    case BlobPart::Type::Data: {
        std::optional<Vector<uint8_t>> data;
        decoder >> data;
        if (!data)
            return std::nullopt;
        return BlobPart(WTFMove(*data));
    }
    case BlobPart::Type::Blob: {
        URL url;
        if (!decoder.decode(url))
            return std::nullopt;
        return BlobPart(url);
    }
    }

    ASSERT_NOT_REACHED();
    return std::nullopt;
}

void ArgumentCoder<TextIndicatorData>::encode(Encoder& encoder, const TextIndicatorData& textIndicatorData)
{
    encoder << textIndicatorData.selectionRectInRootViewCoordinates;
    encoder << textIndicatorData.textBoundingRectInRootViewCoordinates;
    encoder << textIndicatorData.textRectsInBoundingRectCoordinates;
    encoder << textIndicatorData.contentImageWithoutSelectionRectInRootViewCoordinates;
    encoder << textIndicatorData.contentImageScaleFactor;
    encoder << textIndicatorData.estimatedBackgroundColor;
    encoder << textIndicatorData.presentationTransition;
    encoder << textIndicatorData.options;

    encodeOptionalImage(encoder, textIndicatorData.contentImage.get());
    encodeOptionalImage(encoder, textIndicatorData.contentImageWithHighlight.get());
    encodeOptionalImage(encoder, textIndicatorData.contentImageWithoutSelection.get());
}

std::optional<TextIndicatorData> ArgumentCoder<TextIndicatorData>::decode(Decoder& decoder)
{
    TextIndicatorData textIndicatorData;
    if (!decoder.decode(textIndicatorData.selectionRectInRootViewCoordinates))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.textBoundingRectInRootViewCoordinates))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.textRectsInBoundingRectCoordinates))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.contentImageWithoutSelectionRectInRootViewCoordinates))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.contentImageScaleFactor))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.estimatedBackgroundColor))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.presentationTransition))
        return std::nullopt;

    if (!decoder.decode(textIndicatorData.options))
        return std::nullopt;

    if (!decodeOptionalImage(decoder, textIndicatorData.contentImage))
        return std::nullopt;

    if (!decodeOptionalImage(decoder, textIndicatorData.contentImageWithHighlight))
        return std::nullopt;

    if (!decodeOptionalImage(decoder, textIndicatorData.contentImageWithoutSelection))
        return std::nullopt;

    return textIndicatorData;
}

#if ENABLE(WIRELESS_PLAYBACK_TARGET)
void ArgumentCoder<MediaPlaybackTargetContext>::encode(Encoder& encoder, const MediaPlaybackTargetContext& target)
{
    bool hasPlatformData = target.encodingRequiresPlatformData();
    encoder << hasPlatformData;

    MediaPlaybackTargetContext::Type contextType = target.type();
    encoder << contextType;

    if (target.encodingRequiresPlatformData()) {
        encodePlatformData(encoder, target);
        return;
    }

    ASSERT(contextType == MediaPlaybackTargetContext::Type::Mock);
    encoder << target.deviceName();
    encoder << target.mockState();
}

bool ArgumentCoder<MediaPlaybackTargetContext>::decode(Decoder& decoder, MediaPlaybackTargetContext& target)
{
    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return false;

    MediaPlaybackTargetContext::Type contextType;
    if (!decoder.decode(contextType))
        return false;

    if (hasPlatformData)
        return decodePlatformData(decoder, contextType, target);

    ASSERT(contextType == MediaPlaybackTargetContext::Type::Mock);
    String deviceName;
    if (!decoder.decode(deviceName))
        return false;

    MediaPlaybackTargetContext::MockState mockState;
    if (!decoder.decode(mockState))
        return false;

    target = MediaPlaybackTargetContext(deviceName, mockState);

    return true;
}
#endif

void ArgumentCoder<DictionaryPopupInfo>::encode(IPC::Encoder& encoder, const DictionaryPopupInfo& info)
{
    encoder << info.origin;
    encoder << info.textIndicator;

    if (info.encodingRequiresPlatformData()) {
        encoder << true;
        encodePlatformData(encoder, info);
        return;
    }

    encoder << false;
}

bool ArgumentCoder<DictionaryPopupInfo>::decode(IPC::Decoder& decoder, DictionaryPopupInfo& result)
{
    if (!decoder.decode(result.origin))
        return false;

    std::optional<TextIndicatorData> textIndicator;
    decoder >> textIndicator;
    if (!textIndicator)
        return false;
    result.textIndicator = WTFMove(*textIndicator);

    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return false;
    if (hasPlatformData)
        return decodePlatformData(decoder, result);
    return true;
}

void ArgumentCoder<ExceptionDetails>::encode(IPC::Encoder& encoder, const ExceptionDetails& info)
{
    encoder << info.message;
    encoder << info.lineNumber;
    encoder << info.columnNumber;
    encoder << info.type;
    encoder << info.sourceURL;
}

bool ArgumentCoder<ExceptionDetails>::decode(IPC::Decoder& decoder, ExceptionDetails& result)
{
    if (!decoder.decode(result.message))
        return false;

    if (!decoder.decode(result.lineNumber))
        return false;

    if (!decoder.decode(result.columnNumber))
        return false;

    if (!decoder.decode(result.type))
        return false;

    if (!decoder.decode(result.sourceURL))
        return false;

    return true;
}

void ArgumentCoder<ResourceLoadStatistics>::encode(Encoder& encoder, const WebCore::ResourceLoadStatistics& statistics)
{
    encoder << statistics.registrableDomain;
    
    encoder << statistics.lastSeen.secondsSinceEpoch().value();
    
    // User interaction
    encoder << statistics.hadUserInteraction;
    encoder << statistics.mostRecentUserInteractionTime.secondsSinceEpoch().value();
    encoder << statistics.grandfathered;

    // Storage access
    encoder << statistics.storageAccessUnderTopFrameDomains;

    // Top frame stats
    encoder << statistics.topFrameUniqueRedirectsTo;
    encoder << statistics.topFrameUniqueRedirectsFrom;
    encoder << statistics.topFrameLoadedThirdPartyScripts;

    // Subframe stats
    encoder << statistics.subframeUnderTopFrameDomains;
    
    // Subresource stats
    encoder << statistics.subresourceUnderTopFrameDomains;
    encoder << statistics.subresourceUniqueRedirectsTo;
    encoder << statistics.subresourceUniqueRedirectsFrom;

    // Prevalent Resource
    encoder << statistics.isPrevalentResource;
    encoder << statistics.isVeryPrevalentResource;
    encoder << statistics.dataRecordsRemoved;

#if ENABLE(WEB_API_STATISTICS)
    encoder << statistics.fontsFailedToLoad;
    encoder << statistics.fontsSuccessfullyLoaded;
    encoder << statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs;
    
    encoder << statistics.canvasActivityRecord;
    
    encoder << statistics.navigatorFunctionsAccessed;
    encoder << statistics.screenFunctionsAccessed;
#endif
}

std::optional<ResourceLoadStatistics> ArgumentCoder<ResourceLoadStatistics>::decode(Decoder& decoder)
{
    ResourceLoadStatistics statistics;
    std::optional<RegistrableDomain> registrableDomain;
    decoder >> registrableDomain;
    if (!registrableDomain)
        return std::nullopt;
    statistics.registrableDomain = WTFMove(*registrableDomain);

    double lastSeenTimeAsDouble;
    if (!decoder.decode(lastSeenTimeAsDouble))
        return std::nullopt;
    statistics.lastSeen = WallTime::fromRawSeconds(lastSeenTimeAsDouble);
    
    // User interaction
    if (!decoder.decode(statistics.hadUserInteraction))
        return std::nullopt;

    double mostRecentUserInteractionTimeAsDouble;
    if (!decoder.decode(mostRecentUserInteractionTimeAsDouble))
        return std::nullopt;
    statistics.mostRecentUserInteractionTime = WallTime::fromRawSeconds(mostRecentUserInteractionTimeAsDouble);

    if (!decoder.decode(statistics.grandfathered))
        return std::nullopt;

    // Storage access
    std::optional<HashSet<RegistrableDomain>> storageAccessUnderTopFrameDomains;
    decoder >> storageAccessUnderTopFrameDomains;
    if (!storageAccessUnderTopFrameDomains)
        return std::nullopt;
    statistics.storageAccessUnderTopFrameDomains = WTFMove(*storageAccessUnderTopFrameDomains);

    // Top frame stats
    std::optional<HashSet<RegistrableDomain>> topFrameUniqueRedirectsTo;
    decoder >> topFrameUniqueRedirectsTo;
    if (!topFrameUniqueRedirectsTo)
        return std::nullopt;
    statistics.topFrameUniqueRedirectsTo = WTFMove(*topFrameUniqueRedirectsTo);

    std::optional<HashSet<RegistrableDomain>> topFrameUniqueRedirectsFrom;
    decoder >> topFrameUniqueRedirectsFrom;
    if (!topFrameUniqueRedirectsFrom)
        return std::nullopt;
    statistics.topFrameUniqueRedirectsFrom = WTFMove(*topFrameUniqueRedirectsFrom);

    std::optional<HashSet<RegistrableDomain>> topFrameLoadedThirdPartyScripts;
    decoder >> topFrameLoadedThirdPartyScripts;
    if (!topFrameLoadedThirdPartyScripts)
        return std::nullopt;
    statistics.topFrameLoadedThirdPartyScripts = WTFMove(*topFrameLoadedThirdPartyScripts);

    // Subframe stats
    std::optional<HashSet<RegistrableDomain>> subframeUnderTopFrameDomains;
    decoder >> subframeUnderTopFrameDomains;
    if (!subframeUnderTopFrameDomains)
        return std::nullopt;
    statistics.subframeUnderTopFrameDomains = WTFMove(*subframeUnderTopFrameDomains);

    // Subresource stats
    std::optional<HashSet<RegistrableDomain>> subresourceUnderTopFrameDomains;
    decoder >> subresourceUnderTopFrameDomains;
    if (!subresourceUnderTopFrameDomains)
        return std::nullopt;
    statistics.subresourceUnderTopFrameDomains = WTFMove(*subresourceUnderTopFrameDomains);

    std::optional<HashSet<RegistrableDomain>> subresourceUniqueRedirectsTo;
    decoder >> subresourceUniqueRedirectsTo;
    if (!subresourceUniqueRedirectsTo)
        return std::nullopt;
    statistics.subresourceUniqueRedirectsTo = WTFMove(*subresourceUniqueRedirectsTo);

    std::optional<HashSet<RegistrableDomain>> subresourceUniqueRedirectsFrom;
    decoder >> subresourceUniqueRedirectsFrom;
    if (!subresourceUniqueRedirectsFrom)
        return std::nullopt;
    statistics.subresourceUniqueRedirectsFrom = WTFMove(*subresourceUniqueRedirectsFrom);

    // Prevalent Resource
    if (!decoder.decode(statistics.isPrevalentResource))
        return std::nullopt;

    if (!decoder.decode(statistics.isVeryPrevalentResource))
        return std::nullopt;
    
    if (!decoder.decode(statistics.dataRecordsRemoved))
        return std::nullopt;
    
#if ENABLE(WEB_API_STATISTICS)
    if (!decoder.decode(statistics.fontsFailedToLoad))
        return std::nullopt;
    
    if (!decoder.decode(statistics.fontsSuccessfullyLoaded))
        return std::nullopt;
    
    if (!decoder.decode(statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs))
        return std::nullopt;
    
    if (!decoder.decode(statistics.canvasActivityRecord))
        return std::nullopt;
    
    if (!decoder.decode(statistics.navigatorFunctionsAccessed))
        return std::nullopt;
    
    if (!decoder.decode(statistics.screenFunctionsAccessed))
        return std::nullopt;
#endif

    return statistics;
}

#if ENABLE(MEDIA_STREAM)
void ArgumentCoder<MediaConstraints>::encode(Encoder& encoder, const WebCore::MediaConstraints& constraint)
{
    encoder << constraint.mandatoryConstraints
        << constraint.advancedConstraints
        << constraint.isValid;
}

bool ArgumentCoder<MediaConstraints>::decode(Decoder& decoder, WebCore::MediaConstraints& constraints)
{
    std::optional<WebCore::MediaTrackConstraintSetMap> mandatoryConstraints;
    decoder >> mandatoryConstraints;
    if (!mandatoryConstraints)
        return false;
    constraints.mandatoryConstraints = WTFMove(*mandatoryConstraints);
    return decoder.decode(constraints.advancedConstraints)
        && decoder.decode(constraints.isValid);
}
#endif

void ArgumentCoder<IDBKeyPath>::encode(Encoder& encoder, const IDBKeyPath& keyPath)
{
    bool isString = std::holds_alternative<String>(keyPath);
    encoder << isString;
    if (isString)
        encoder << std::get<String>(keyPath);
    else
        encoder << std::get<Vector<String>>(keyPath);
}

bool ArgumentCoder<IDBKeyPath>::decode(Decoder& decoder, IDBKeyPath& keyPath)
{
    bool isString;
    if (!decoder.decode(isString))
        return false;
    if (isString) {
        String string;
        if (!decoder.decode(string))
            return false;
        keyPath = string;
    } else {
        Vector<String> vector;
        if (!decoder.decode(vector))
            return false;
        keyPath = vector;
    }
    return true;
}

#if ENABLE(SERVICE_WORKER)
void ArgumentCoder<ServiceWorkerOrClientData>::encode(Encoder& encoder, const ServiceWorkerOrClientData& data)
{
    bool isServiceWorkerData = std::holds_alternative<ServiceWorkerData>(data);
    encoder << isServiceWorkerData;
    if (isServiceWorkerData)
        encoder << std::get<ServiceWorkerData>(data);
    else
        encoder << std::get<ServiceWorkerClientData>(data);
}

bool ArgumentCoder<ServiceWorkerOrClientData>::decode(Decoder& decoder, ServiceWorkerOrClientData& data)
{
    bool isServiceWorkerData;
    if (!decoder.decode(isServiceWorkerData))
        return false;
    if (isServiceWorkerData) {
        std::optional<ServiceWorkerData> workerData;
        decoder >> workerData;
        if (!workerData)
            return false;

        data = WTFMove(*workerData);
    } else {
        std::optional<ServiceWorkerClientData> clientData;
        decoder >> clientData;
        if (!clientData)
            return false;

        data = WTFMove(*clientData);
    }
    return true;
}

void ArgumentCoder<ServiceWorkerOrClientIdentifier>::encode(Encoder& encoder, const ServiceWorkerOrClientIdentifier& identifier)
{
    bool isServiceWorkerIdentifier = std::holds_alternative<ServiceWorkerIdentifier>(identifier);
    encoder << isServiceWorkerIdentifier;
    if (isServiceWorkerIdentifier)
        encoder << std::get<ServiceWorkerIdentifier>(identifier);
    else
        encoder << std::get<ScriptExecutionContextIdentifier>(identifier);
}

bool ArgumentCoder<ServiceWorkerOrClientIdentifier>::decode(Decoder& decoder, ServiceWorkerOrClientIdentifier& identifier)
{
    bool isServiceWorkerIdentifier;
    if (!decoder.decode(isServiceWorkerIdentifier))
        return false;
    if (isServiceWorkerIdentifier) {
        std::optional<ServiceWorkerIdentifier> workerIdentifier;
        decoder >> workerIdentifier;
        if (!workerIdentifier)
            return false;

        identifier = WTFMove(*workerIdentifier);
    } else {
        std::optional<ScriptExecutionContextIdentifier> clientIdentifier;
        decoder >> clientIdentifier;
        if (!clientIdentifier)
            return false;

        identifier = WTFMove(*clientIdentifier);
    }
    return true;
}

#endif

void ArgumentCoder<PromisedAttachmentInfo>::encode(Encoder& encoder, const PromisedAttachmentInfo& info)
{
#if ENABLE(ATTACHMENT_ELEMENT)
    encoder << info.attachmentIdentifier;
#endif
    encoder << info.additionalTypes;
    encoder << info.additionalData;
}

bool ArgumentCoder<PromisedAttachmentInfo>::decode(Decoder& decoder, PromisedAttachmentInfo& info)
{
#if ENABLE(ATTACHMENT_ELEMENT)
    if (!decoder.decode(info.attachmentIdentifier))
        return false;
#endif

    if (!decoder.decode(info.additionalTypes))
        return false;
    if (!decoder.decode(info.additionalData))
        return false;

    return true;
}

void ArgumentCoder<RefPtr<SecurityOrigin>>::encode(Encoder& encoder, const RefPtr<SecurityOrigin>& origin)
{
    encoder << *origin;
}
    
std::optional<RefPtr<SecurityOrigin>> ArgumentCoder<RefPtr<SecurityOrigin>>::decode(Decoder& decoder)
{
    auto origin = SecurityOrigin::decode(decoder);
    if (!origin)
        return std::nullopt;
    return origin;
}

void ArgumentCoder<FontAttributes>::encode(Encoder& encoder, const FontAttributes& attributes)
{
    encoder << attributes.backgroundColor;
    encoder << attributes.foregroundColor;
    encoder << attributes.fontShadow;
    encoder << attributes.hasUnderline;
    encoder << attributes.hasStrikeThrough;
    encoder << attributes.hasMultipleFonts;
    encoder << attributes.textLists;
    encoder << attributes.horizontalAlignment;
    encoder << attributes.subscriptOrSuperscript;
    encoder << attributes.font;
}

std::optional<FontAttributes> ArgumentCoder<FontAttributes>::decode(Decoder& decoder)
{
    std::optional<Color> backgroundColor;
    decoder >> backgroundColor;
    if (!backgroundColor)
        return std::nullopt;

    std::optional<Color> foregroundColor;
    decoder >> foregroundColor;
    if (!foregroundColor)
        return std::nullopt;

    std::optional<FontShadow> fontShadow;
    decoder >> fontShadow;
    if (!fontShadow)
        return std::nullopt;

    std::optional<bool> hasUnderline;
    decoder >> hasUnderline;
    if (!hasUnderline)
        return std::nullopt;

    std::optional<bool> hasStrikeThrough;
    decoder >> hasStrikeThrough;
    if (!hasStrikeThrough)
        return std::nullopt;

    std::optional<bool> hasMultipleFonts;
    decoder >> hasMultipleFonts;
    if (!hasMultipleFonts)
        return std::nullopt;

    std::optional<Vector<TextList>> textLists;
    decoder >> textLists;
    if (!textLists)
        return std::nullopt;

    std::optional<FontAttributes::HorizontalAlignment> horizontalAlignment;
    decoder >> horizontalAlignment;
    if (!horizontalAlignment)
        return std::nullopt;

    std::optional<FontAttributes::SubscriptOrSuperscript> subscriptOrSuperscript;
    decoder >> subscriptOrSuperscript;
    if (!subscriptOrSuperscript)
        return std::nullopt;

    std::optional<RefPtr<Font>> font;
    decoder >> font;
    if (!font)
        return std::nullopt;

    return { { WTFMove(*font), WTFMove(*backgroundColor), WTFMove(*foregroundColor), WTFMove(*fontShadow), *subscriptOrSuperscript, *horizontalAlignment, WTFMove(*textLists), *hasUnderline, *hasStrikeThrough, *hasMultipleFonts } };
}

#if ENABLE(ATTACHMENT_ELEMENT)

void ArgumentCoder<SerializedAttachmentData>::encode(IPC::Encoder& encoder, const WebCore::SerializedAttachmentData& data)
{
    encoder << data.identifier << data.mimeType << data.data;
}

std::optional<SerializedAttachmentData> ArgumentCoder<WebCore::SerializedAttachmentData>::decode(IPC::Decoder& decoder)
{
    auto identifier = decoder.decode<String>();
    auto mimeType = decoder.decode<String>();
    auto data = decoder.decode<Ref<SharedBuffer>>();

    if (UNLIKELY(!decoder.isValid()))
        return std::nullopt;

    return { { WTFMove(*identifier), WTFMove(*mimeType), WTFMove(*data) } };
}

#endif // ENABLE(ATTACHMENT_ELEMENT)

#if ENABLE(VIDEO)
void ArgumentCoder<WebCore::SerializedPlatformDataCueValue>::encode(Encoder& encoder, const SerializedPlatformDataCueValue& value)
{
    bool hasPlatformData = value.encodingRequiresPlatformData();
    encoder << hasPlatformData;

    encoder << value.platformType();
    if (hasPlatformData)
        encodePlatformData(encoder, value);
}

std::optional<SerializedPlatformDataCueValue> ArgumentCoder<WebCore::SerializedPlatformDataCueValue>::decode(IPC::Decoder& decoder)
{
    bool hasPlatformData;
    if (!decoder.decode(hasPlatformData))
        return std::nullopt;

    WebCore::SerializedPlatformDataCueValue::PlatformType type;
    if (!decoder.decode(type))
        return std::nullopt;

    if (hasPlatformData)
        return decodePlatformData(decoder, type);

    return { SerializedPlatformDataCueValue() };

}
#endif

void ArgumentCoder<WebCore::FragmentedSharedBuffer>::encode(Encoder& encoder, const WebCore::FragmentedSharedBuffer& buffer)
{
    uint64_t bufferSize = buffer.size();
    encoder << bufferSize;
    if (!bufferSize)
        return;

#if USE(UNIX_DOMAIN_SOCKETS)
    // Do not use shared memory for FragmentedSharedBuffer encoding in Unix, because it's easy to reach the
    // maximum number of file descriptors open per process when sending large data in small chunks
    // over the IPC. ConnectionUnix.cpp already uses shared memory to send any IPC message that is
    // too large. See https://bugs.webkit.org/show_bug.cgi?id=208571.
    for (const auto& element : buffer)
        encoder.encodeFixedLengthData(element.segment->data(), element.segment->size(), 1);
#else
    SharedMemory::Handle handle;
    {
        auto sharedMemoryBuffer = SharedMemory::copyBuffer(buffer);
        sharedMemoryBuffer->createHandle(handle, SharedMemory::Protection::ReadOnly);
    }
    encoder << SharedMemory::IPCHandle { WTFMove(handle), bufferSize };
#endif
}

std::optional<Ref<WebCore::FragmentedSharedBuffer>> ArgumentCoder<WebCore::FragmentedSharedBuffer>::decode(Decoder& decoder)
{
    uint64_t bufferSize = 0;
    if (!decoder.decode(bufferSize))
        return std::nullopt;

    if (!bufferSize)
        return SharedBuffer::create();

#if USE(UNIX_DOMAIN_SOCKETS)
    if (!decoder.bufferIsLargeEnoughToContain<uint8_t>(bufferSize))
        return std::nullopt;

    Vector<uint8_t> data;
    data.grow(bufferSize);
    if (!decoder.decodeFixedLengthData(data.data(), data.size(), 1))
        return std::nullopt;

    return SharedBuffer::create(WTFMove(data));
#else
    SharedMemory::IPCHandle ipcHandle;
    if (!decoder.decode(ipcHandle))
        return std::nullopt;

    auto sharedMemoryBuffer = SharedMemory::map(ipcHandle.handle, SharedMemory::Protection::ReadOnly);
    if (!sharedMemoryBuffer)
        return std::nullopt;

    if (sharedMemoryBuffer->size() < bufferSize)
        return std::nullopt;

    return SharedBuffer::create(static_cast<unsigned char*>(sharedMemoryBuffer->data()), bufferSize);
#endif
}

void ArgumentCoder<WebCore::SharedBuffer>::encode(Encoder& encoder, const WebCore::SharedBuffer& buffer)
{
    encoder << static_cast<const WebCore::FragmentedSharedBuffer&>(buffer);
}

std::optional<Ref<WebCore::SharedBuffer>> ArgumentCoder<WebCore::SharedBuffer>::decode(Decoder& decoder)
{
    if (auto buffer = decoder.decode<Ref<FragmentedSharedBuffer>>())
        return (*buffer)->makeContiguous();
    return std::nullopt;
}

#if ENABLE(SHAREABLE_RESOURCE) && PLATFORM(COCOA)
static ShareableResource::Handle tryConvertToShareableResourceHandle(const ScriptBuffer& script)
{
    if (!script.containsSingleFileMappedSegment())
        return ShareableResource::Handle { };

    auto& segment = script.buffer()->begin()->segment;
    auto sharedMemory = SharedMemory::wrapMap(const_cast<uint8_t*>(segment->data()), segment->size(), SharedMemory::Protection::ReadOnly);
    if (!sharedMemory)
        return ShareableResource::Handle { };

    auto shareableResource = ShareableResource::create(sharedMemory.releaseNonNull(), 0, segment->size());
    if (!shareableResource)
        return ShareableResource::Handle { };

    ShareableResource::Handle shareableResourceHandle;
    shareableResource->createHandle(shareableResourceHandle);
    return shareableResourceHandle;
}

static std::optional<WebCore::ScriptBuffer> decodeScriptBufferAsShareableResourceHandle(Decoder& decoder)
{
    ShareableResource::Handle handle;
    if (!decoder.decode(handle) || handle.isNull())
        return std::nullopt;
    auto buffer = handle.tryWrapInSharedBuffer();
    if (!buffer)
        return std::nullopt;
    return WebCore::ScriptBuffer { WTFMove(buffer) };
}
#endif

void ArgumentCoder<WebCore::ScriptBuffer>::encode(Encoder& encoder, const WebCore::ScriptBuffer& script)
{
#if ENABLE(SHAREABLE_RESOURCE) && PLATFORM(COCOA)
    auto handle = tryConvertToShareableResourceHandle(script);
    bool isShareableResourceHandle = !handle.isNull();
    encoder << isShareableResourceHandle;
    if (isShareableResourceHandle) {
        encoder << handle;
        return;
    }
#endif
    encoder << RefPtr { script.buffer() };
}

std::optional<WebCore::ScriptBuffer> ArgumentCoder<WebCore::ScriptBuffer>::decode(Decoder& decoder)
{
#if ENABLE(SHAREABLE_RESOURCE) && PLATFORM(COCOA)
    std::optional<bool> isShareableResourceHandle;
    decoder >> isShareableResourceHandle;
    if (!isShareableResourceHandle)
        return std::nullopt;
    if (*isShareableResourceHandle)
        return decodeScriptBufferAsShareableResourceHandle(decoder);
#endif

    if (auto buffer = decoder.decode<RefPtr<FragmentedSharedBuffer>>())
        return WebCore::ScriptBuffer { WTFMove(*buffer) };
    return std::nullopt;
}

template<typename Encoder>
void ArgumentCoder<SystemImage>::encode(Encoder& encoder, const SystemImage& systemImage)
{
    encoder << systemImage.systemImageType();

    switch (systemImage.systemImageType()) {
#if ENABLE(APPLE_PAY)
    case SystemImageType::ApplePayButton:
        downcast<ApplePayButtonSystemImage>(systemImage).encode(encoder);
        return;

    case SystemImageType::ApplePayLogo:
        downcast<ApplePayLogoSystemImage>(systemImage).encode(encoder);
        return;
#endif
#if USE(SYSTEM_PREVIEW)
    case SystemImageType::ARKitBadge:
        downcast<ARKitBadgeSystemImage>(systemImage).encode(encoder);
        return;
#endif
    }

    ASSERT_NOT_REACHED();
}

template
void ArgumentCoder<SystemImage>::encode<Encoder>(Encoder&, const SystemImage&);
template
void ArgumentCoder<SystemImage>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, const SystemImage&);

std::optional<Ref<SystemImage>> ArgumentCoder<SystemImage>::decode(Decoder& decoder)
{
    std::optional<SystemImageType> systemImageType;
    decoder >> systemImageType;
    if (!systemImageType)
        return std::nullopt;

    switch (*systemImageType) {
#if ENABLE(APPLE_PAY)
    case SystemImageType::ApplePayButton:
        return ApplePayButtonSystemImage::decode(decoder);

    case SystemImageType::ApplePayLogo:
        return ApplePayLogoSystemImage::decode(decoder);
#endif
#if USE(SYSTEM_PREVIEW)
    case SystemImageType::ARKitBadge:
        return ARKitBadgeSystemImage::decode(decoder);
#endif
    }

    ASSERT_NOT_REACHED();
    return std::nullopt;
}

#if ENABLE(ENCRYPTED_MEDIA)
void ArgumentCoder<WebCore::CDMInstanceSession::Message>::encode(Encoder& encoder, const WebCore::CDMInstanceSession::Message& message)
{
    encoder << message.first;
    encoder << message.second;
}

std::optional<WebCore::CDMInstanceSession::Message>  ArgumentCoder<WebCore::CDMInstanceSession::Message>::decode(Decoder& decoder)
{
    WebCore::CDMInstanceSession::MessageType type;
    if (!decoder.decode(type))
        return std::nullopt;

    auto buffer = decoder.decode<Ref<SharedBuffer>>();
    if (UNLIKELY(!buffer))
        return std::nullopt;

    return std::make_optional<WebCore::CDMInstanceSession::Message>({ type, WTFMove(*buffer) });
}
#endif // ENABLE(ENCRYPTED_MEDIA)

#if ENABLE(GPU_PROCESS) && ENABLE(WEBGL)

template<typename Encoder>
void ArgumentCoder<WebCore::GraphicsContextGL::ActiveInfo>::encode(Encoder& encoder, const WebCore::GraphicsContextGL::ActiveInfo& activeInfo)
{
    encoder << activeInfo.name;
    encoder << activeInfo.type;
    encoder << activeInfo.size;
}

template
void ArgumentCoder<WebCore::GraphicsContextGL::ActiveInfo>::encode<Encoder>(Encoder&, const WebCore::GraphicsContextGL::ActiveInfo&);
template
void ArgumentCoder<WebCore::GraphicsContextGL::ActiveInfo>::encode<StreamConnectionEncoder>(StreamConnectionEncoder&, const WebCore::GraphicsContextGL::ActiveInfo&);

std::optional<WebCore::GraphicsContextGL::ActiveInfo> ArgumentCoder<WebCore::GraphicsContextGL::ActiveInfo>::decode(Decoder& decoder)
{
    WebCore::GraphicsContextGL::ActiveInfo activeInfo;
    if (!decoder.decode(activeInfo.name))
        return std::nullopt;
    if (!decoder.decode(activeInfo.type))
        return std::nullopt;
    if (!decoder.decode(activeInfo.size))
        return std::nullopt;
    return activeInfo;
}

#endif

#if ENABLE(IMAGE_ANALYSIS) && ENABLE(DATA_DETECTION)

void ArgumentCoder<TextRecognitionDataDetector>::encode(Encoder& encoder, const TextRecognitionDataDetector& info)
{
    encodePlatformData(encoder, info);
    encoder << info.normalizedQuads;
}

std::optional<TextRecognitionDataDetector> ArgumentCoder<TextRecognitionDataDetector>::decode(Decoder& decoder)
{
    TextRecognitionDataDetector result;
    if (!decodePlatformData(decoder, result))
        return std::nullopt;

    std::optional<Vector<FloatQuad>> normalizedQuads;
    decoder >> normalizedQuads;
    if (!normalizedQuads)
        return std::nullopt;

    result.normalizedQuads = WTFMove(*normalizedQuads);
    return WTFMove(result);
}

#endif // ENABLE(IMAGE_ANALYSIS) && ENABLE(DATA_DETECTION)

#if USE(UNIX_DOMAIN_SOCKETS)

void ArgumentCoder<UnixFileDescriptor>::encode(Encoder& encoder, const UnixFileDescriptor& fd)
{
    encoder.addAttachment(Attachment(fd.duplicate()));
}

void ArgumentCoder<UnixFileDescriptor>::encode(Encoder& encoder, UnixFileDescriptor&& fd)
{
    encoder.addAttachment(Attachment(WTFMove(fd)));
}

std::optional<UnixFileDescriptor> ArgumentCoder<UnixFileDescriptor>::decode(Decoder& decoder)
{
    auto attachment = decoder.takeLastAttachment();
    if (!attachment)
        return std::nullopt;
    return std::optional<UnixFileDescriptor> { std::in_place, attachment->release() };
}

#endif

} // namespace IPC
