| /* |
| * Copyright (C) 2015 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 "IDBConnectionToServer.h" |
| |
| #include "IDBConnectionProxy.h" |
| #include "IDBDatabase.h" |
| #include "IDBDatabaseNameAndVersion.h" |
| #include "IDBGetRecordData.h" |
| #include "IDBKeyRangeData.h" |
| #include "IDBOpenDBRequest.h" |
| #include "IDBRequestData.h" |
| #include "IDBResultData.h" |
| #include "Logging.h" |
| #include "SecurityOrigin.h" |
| #include "TransactionOperation.h" |
| #include <wtf/IsoMallocInlines.h> |
| #include <wtf/MainThread.h> |
| |
| namespace WebCore { |
| namespace IDBClient { |
| |
| WTF_MAKE_ISO_ALLOCATED_IMPL(IDBConnectionToServer); |
| |
| Ref<IDBConnectionToServer> IDBConnectionToServer::create(IDBConnectionToServerDelegate& delegate) |
| { |
| return adoptRef(*new IDBConnectionToServer(delegate)); |
| } |
| |
| IDBConnectionToServer::IDBConnectionToServer(IDBConnectionToServerDelegate& delegate) |
| : m_delegate(delegate) |
| , m_proxy(makeUnique<IDBConnectionProxy>(*this)) |
| { |
| } |
| |
| IDBConnectionIdentifier IDBConnectionToServer::identifier() const |
| { |
| return m_delegate->identifier(); |
| } |
| |
| IDBConnectionProxy& IDBConnectionToServer::proxy() |
| { |
| ASSERT(m_proxy); |
| return *m_proxy; |
| } |
| |
| void IDBConnectionToServer::callResultFunctionWithErrorLater(ResultFunction function, const IDBResourceIdentifier& requestIdentifier) |
| { |
| callOnMainThread([this, protectedThis = Ref { *this }, function, requestIdentifier]() { |
| (this->*function)(IDBResultData::error(requestIdentifier, IDBError::serverConnectionLostError())); |
| }); |
| } |
| |
| void IDBConnectionToServer::deleteDatabase(const IDBRequestData& request) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::deleteDatabase - %s", request.databaseIdentifier().loggingString().utf8().data()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->deleteDatabase(request); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didDeleteDatabase, request.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didDeleteDatabase(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didDeleteDatabase"); |
| m_proxy->didDeleteDatabase(resultData); |
| } |
| |
| void IDBConnectionToServer::openDatabase(const IDBRequestData& request) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::openDatabase - %s (%s) (%" PRIu64 ")", request.databaseIdentifier().loggingString().utf8().data(), request.requestIdentifier().loggingString().utf8().data(), request.requestedVersion()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->openDatabase(request); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didOpenDatabase, request.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didOpenDatabase(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didOpenDatabase"); |
| m_proxy->didOpenDatabase(resultData); |
| } |
| |
| void IDBConnectionToServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::createObjectStore"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->createObjectStore(requestData, info); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didCreateObjectStore, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didCreateObjectStore(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didCreateObjectStore"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::deleteObjectStore"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->deleteObjectStore(requestData, objectStoreName); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didDeleteObjectStore, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didDeleteObjectStore(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didDeleteObjectStore"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::renameObjectStore"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->renameObjectStore(requestData, objectStoreIdentifier, newName); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didRenameObjectStore, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didRenameObjectStore(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didRenameObjectStore"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::clearObjectStore"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->clearObjectStore(requestData, objectStoreIdentifier); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didClearObjectStore, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didClearObjectStore(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didClearObjectStore"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::createIndex"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->createIndex(requestData, info); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didCreateIndex, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didCreateIndex(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didCreateIndex"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::deleteIndex"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->deleteIndex(requestData, objectStoreIdentifier, indexName); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didDeleteIndex, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didDeleteIndex(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didDeleteIndex"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::renameIndex"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->renameIndex(requestData, objectStoreIdentifier, indexIdentifier, newName); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didRenameIndex, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didRenameIndex(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didRenameIndex"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& key, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode overwriteMode) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::putOrAdd"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->putOrAdd(requestData, key, value, overwriteMode); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didPutOrAdd, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didPutOrAdd(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didPutOrAdd"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::getRecord"); |
| ASSERT(isMainThread()); |
| ASSERT(!getRecordData.keyRangeData.isNull); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->getRecord(requestData, getRecordData); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didGetRecord, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didGetRecord(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didGetRecord"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::getAllRecords"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->getAllRecords(requestData, getAllRecordsData); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didGetAllRecords, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didGetAllRecords(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didGetAllRecords"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::getCount"); |
| ASSERT(isMainThread()); |
| ASSERT(!keyRangeData.isNull); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->getCount(requestData, keyRangeData); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didGetCount, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didGetCount(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didGetCount"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::deleteRecord"); |
| ASSERT(isMainThread()); |
| ASSERT(!keyRangeData.isNull); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->deleteRecord(requestData, keyRangeData); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didDeleteRecord, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didDeleteRecord(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didDeleteRecord"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::openCursor"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->openCursor(requestData, info); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didOpenCursor, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didOpenCursor(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didOpenCursor"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::iterateCursor"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->iterateCursor(requestData, data); |
| else |
| callResultFunctionWithErrorLater(&IDBConnectionToServer::didIterateCursor, requestData.requestIdentifier()); |
| } |
| |
| void IDBConnectionToServer::didIterateCursor(const IDBResultData& resultData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didIterateCursor"); |
| m_proxy->completeOperation(resultData); |
| } |
| |
| void IDBConnectionToServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::establishTransaction"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->establishTransaction(databaseConnectionIdentifier, info); |
| } |
| |
| void IDBConnectionToServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier, uint64_t pendingRequestCount) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::commitTransaction"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->commitTransaction(transactionIdentifier, pendingRequestCount); |
| else { |
| callOnMainThread([this, protectedThis = Ref { *this }, transactionIdentifier] { |
| didCommitTransaction(transactionIdentifier, IDBError::serverConnectionLostError()); |
| }); |
| } |
| } |
| |
| void IDBConnectionToServer::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didCommitTransaction"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->didCommitTransaction(transactionIdentifier, error); |
| } |
| |
| void IDBConnectionToServer::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didFinishHandlingVersionChangeTransaction"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->didFinishHandlingVersionChangeTransaction(databaseConnectionIdentifier, transactionIdentifier); |
| } |
| |
| void IDBConnectionToServer::abortTransaction(const IDBResourceIdentifier& transactionIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::abortTransaction"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->abortTransaction(transactionIdentifier); |
| else { |
| callOnMainThread([this, protectedThis = Ref { *this }, transactionIdentifier] { |
| didAbortTransaction(transactionIdentifier, IDBError::serverConnectionLostError()); |
| }); |
| } |
| } |
| |
| void IDBConnectionToServer::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didAbortTransaction"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->didAbortTransaction(transactionIdentifier, error); |
| } |
| |
| void IDBConnectionToServer::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::fireVersionChangeEvent"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->fireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier, requestedVersion); |
| } |
| |
| void IDBConnectionToServer::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, const IndexedDB::ConnectionClosedOnBehalfOfServer connectionClosed) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didFireVersionChangeEvent"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->didFireVersionChangeEvent(databaseConnectionIdentifier, requestIdentifier, connectionClosed); |
| } |
| |
| void IDBConnectionToServer::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->didStartTransaction(transactionIdentifier, error); |
| } |
| |
| void IDBConnectionToServer::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didCloseFromServer"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->didCloseFromServer(databaseConnectionIdentifier, error); |
| } |
| |
| void IDBConnectionToServer::connectionToServerLost(const IDBError& error) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::connectionToServerLost"); |
| ASSERT(isMainThread()); |
| ASSERT(m_serverConnectionIsValid); |
| |
| m_serverConnectionIsValid = false; |
| m_proxy->connectionToServerLost(error); |
| } |
| |
| void IDBConnectionToServer::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didStartTransaction"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->notifyOpenDBRequestBlocked(requestIdentifier, oldVersion, newVersion); |
| } |
| |
| void IDBConnectionToServer::openDBRequestCancelled(const IDBRequestData& requestData) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::openDBRequestCancelled"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->openDBRequestCancelled(requestData); |
| } |
| |
| void IDBConnectionToServer::databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionPendingClose"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->databaseConnectionPendingClose(databaseConnectionIdentifier); |
| } |
| |
| void IDBConnectionToServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionClosed"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->databaseConnectionClosed(databaseConnectionIdentifier); |
| } |
| |
| void IDBConnectionToServer::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::abortOpenAndUpgradeNeeded"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) |
| m_delegate->abortOpenAndUpgradeNeeded(databaseConnectionIdentifier, transactionIdentifier); |
| } |
| |
| void IDBConnectionToServer::getAllDatabaseNamesAndVersions(const IDBResourceIdentifier& requestIdentifier, const ClientOrigin& origin) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::getAllDatabaseNamesAndVersions"); |
| ASSERT(isMainThread()); |
| |
| if (m_serverConnectionIsValid) { |
| m_delegate->getAllDatabaseNamesAndVersions(requestIdentifier, origin); |
| return; |
| } |
| |
| callOnMainThread([this, protectedThis = Ref { *this }, requestIdentifier] { |
| didGetAllDatabaseNamesAndVersions(requestIdentifier, { }); |
| }); |
| } |
| |
| void IDBConnectionToServer::didGetAllDatabaseNamesAndVersions(const IDBResourceIdentifier& requestIdentifier, Vector<IDBDatabaseNameAndVersion>&& databases) |
| { |
| LOG(IndexedDB, "IDBConnectionToServer::didGetAllDatabaseNamesAndVersions"); |
| ASSERT(isMainThread()); |
| |
| m_proxy->didGetAllDatabaseNamesAndVersions(requestIdentifier, WTFMove(databases)); |
| } |
| |
| } // namespace IDBClient |
| } // namespace WebCore |