#include "config.h"
#include "WebKitWebPage.h"
#include "ImageOptions.h"
#include "ImmutableDictionary.h"
#include "InjectedBundle.h"
#include "WKBundleAPICast.h"
#include "WKBundleFrame.h"
#include "WebImage.h"
#include "WebKitDOMDocumentPrivate.h"
#include "WebKitFramePrivate.h"
#include "WebKitMarshal.h"
#include "WebKitPrivate.h"
#include "WebKitScriptWorldPrivate.h"
#include "WebKitURIRequestPrivate.h"
#include "WebKitURIResponsePrivate.h"
#include "WebKitWebPagePrivate.h"
#include "WebProcess.h"
#include <WebCore/Document.h>
#include <WebCore/DocumentLoader.h>
#include <WebCore/Frame.h>
#include <WebCore/FrameView.h>
#include <glib/gi18n-lib.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/text/CString.h>
using namespace WebKit;
using namespace WebCore;
enum {
DOCUMENT_LOADED,
SEND_REQUEST,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_URI
};
struct _WebKitWebPagePrivate {
WebPage* webPage;
CString uri;
};
static guint signals[LAST_SIGNAL] = { 0, };
WEBKIT_DEFINE_TYPE(WebKitWebPage, webkit_web_page, G_TYPE_OBJECT)
typedef HashMap<WebFrame*, GRefPtr<WebKitFrame>> WebFrameMap;
static WebFrameMap& webFrameMap()
{
static NeverDestroyed<WebFrameMap> map;
return map;
}
static WebKitFrame* webkitFrameGetOrCreate(WebFrame* webFrame)
{
GRefPtr<WebKitFrame> frame = webFrameMap().get(webFrame);
if (frame)
return frame.get();
frame = adoptGRef(webkitFrameCreate(webFrame));
webFrameMap().set(webFrame, frame);
return frame.get();
}
static CString getProvisionalURLForFrame(WebFrame* webFrame)
{
DocumentLoader* documentLoader = webFrame->coreFrame()->loader().provisionalDocumentLoader();
if (!documentLoader->unreachableURL().isEmpty())
return documentLoader->unreachableURL().string().utf8();
return documentLoader->url().string().utf8();
}
static void webkitWebPageSetURI(WebKitWebPage* webPage, const CString& uri)
{
if (webPage->priv->uri == uri)
return;
webPage->priv->uri = uri;
g_object_notify(G_OBJECT(webPage), "uri");
}
static void didStartProvisionalLoadForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
{
if (!WKBundleFrameIsMainFrame(frame))
return;
webkitWebPageSetURI(WEBKIT_WEB_PAGE(clientInfo), getProvisionalURLForFrame(toImpl(frame)));
}
static void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef* , const void *clientInfo)
{
if (!WKBundleFrameIsMainFrame(frame))
return;
webkitWebPageSetURI(WEBKIT_WEB_PAGE(clientInfo), getProvisionalURLForFrame(toImpl(frame)));
}
static void didSameDocumentNavigationForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKSameDocumentNavigationType, WKTypeRef* , const void *clientInfo)
{
if (!WKBundleFrameIsMainFrame(frame))
return;
webkitWebPageSetURI(WEBKIT_WEB_PAGE(clientInfo), toImpl(frame)->coreFrame()->document()->url().string().utf8());
}
static void didFinishDocumentLoadForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
{
if (!WKBundleFrameIsMainFrame(frame))
return;
g_signal_emit(WEBKIT_WEB_PAGE(clientInfo), signals[DOCUMENT_LOADED], 0);
}
static void willDestroyFrame(WKBundlePageRef, WKBundleFrameRef frame, const void* )
{
webFrameMap().remove(toImpl(frame));
}
static void didClearWindowObjectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKBundleScriptWorldRef wkWorld, const void* clientInfo)
{
if (WebKitScriptWorld* world = webkitScriptWorldGet(toImpl(wkWorld)))
webkitScriptWorldWindowObjectCleared(world, WEBKIT_WEB_PAGE(clientInfo), webkitFrameGetOrCreate(toImpl(frame)));
}
static void didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool , const void*)
{
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Frame"), toImpl(frame));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
message.set(String::fromUTF8("Request"), toImpl(request));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidInitiateLoadForResource"), ImmutableDictionary::create(WTF::move(message)).get());
}
static WKURLRequestRef willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef wkRequest, WKURLResponseRef wkRedirectResponse, const void* clientInfo)
{
GRefPtr<WebKitURIRequest> request = adoptGRef(webkitURIRequestCreateForResourceRequest(toImpl(wkRequest)->resourceRequest()));
const ResourceResponse& redirectResourceResponse = toImpl(wkRedirectResponse)->resourceResponse();
GRefPtr<WebKitURIResponse> redirectResponse = !redirectResourceResponse.isNull() ? adoptGRef(webkitURIResponseCreateForResourceResponse(redirectResourceResponse)) : nullptr;
gboolean returnValue;
g_signal_emit(WEBKIT_WEB_PAGE(clientInfo), signals[SEND_REQUEST], 0, request.get(), redirectResponse.get(), &returnValue);
if (returnValue)
return 0;
ResourceRequest resourceRequest;
webkitURIRequestGetResourceRequest(request.get(), resourceRequest);
resourceRequest.setInitiatingPageID(toImpl(page)->pageID());
RefPtr<API::URLRequest> newRequest = API::URLRequest::create(resourceRequest);
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
message.set(String::fromUTF8("Request"), newRequest.get());
if (!redirectResourceResponse.isNull())
message.set(String::fromUTF8("RedirectResponse"), toImpl(wkRedirectResponse));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidSendRequestForResource"), ImmutableDictionary::create(WTF::move(message)).get());
return toAPI(newRequest.release().leakRef());
}
static void didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef response, const void*)
{
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
message.set(String::fromUTF8("Response"), toImpl(response));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidReceiveResponseForResource"), ImmutableDictionary::create(WTF::move(message)).get());
}
static void didReceiveContentLengthForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, uint64_t length, const void*)
{
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
message.set(String::fromUTF8("ContentLength"), API::UInt64::create(length));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidReceiveContentLengthForResource"), ImmutableDictionary::create(WTF::move(message)).get());
}
static void didFinishLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, const void*)
{
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidFinishLoadForResource"), ImmutableDictionary::create(WTF::move(message)).get());
}
static void didFailLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKErrorRef error, const void*)
{
ImmutableDictionary::MapType message;
message.set(String::fromUTF8("Page"), toImpl(page));
message.set(String::fromUTF8("Identifier"), API::UInt64::create(identifier));
message.set(String::fromUTF8("Error"), toImpl(error));
WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidFailLoadForResource"), ImmutableDictionary::create(WTF::move(message)).get());
}
static void webkitWebPageGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
{
WebKitWebPage* webPage = WEBKIT_WEB_PAGE(object);
switch (propId) {
case PROP_URI:
g_value_set_string(value, webkit_web_page_get_uri(webPage));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
}
}
static void webkit_web_page_class_init(WebKitWebPageClass* klass)
{
GObjectClass* gObjectClass = G_OBJECT_CLASS(klass);
gObjectClass->get_property = webkitWebPageGetProperty;
g_object_class_install_property(
gObjectClass,
PROP_URI,
g_param_spec_string(
"uri",
_("URI"),
_("The current active URI of the web page"),
0,
WEBKIT_PARAM_READABLE));
signals[DOCUMENT_LOADED] = g_signal_new(
"document-loaded",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[SEND_REQUEST] = g_signal_new(
"send-request",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled, 0,
webkit_marshal_BOOLEAN__OBJECT_OBJECT,
G_TYPE_BOOLEAN, 2,
WEBKIT_TYPE_URI_REQUEST,
WEBKIT_TYPE_URI_RESPONSE);
}
WebKitWebPage* webkitWebPageCreate(WebPage* webPage)
{
WebKitWebPage* page = WEBKIT_WEB_PAGE(g_object_new(WEBKIT_TYPE_WEB_PAGE, NULL));
page->priv->webPage = webPage;
WKBundlePageLoaderClientV7 loaderClient = {
{
7, page, },
didStartProvisionalLoadForFrame,
didReceiveServerRedirectForProvisionalLoadForFrame,
0, 0, didFinishDocumentLoadForFrame,
0, 0, didSameDocumentNavigationForFrame,
0, 0, 0, 0, 0, 0, didClearWindowObjectForFrame,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, willDestroyFrame
};
WKBundlePageSetPageLoaderClient(toAPI(webPage), &loaderClient.base);
WKBundlePageResourceLoadClientV1 resourceLoadClient = {
{
1, page, },
didInitiateLoadForResource,
willSendRequestForFrame,
didReceiveResponseForResource,
didReceiveContentLengthForResource,
didFinishLoadForResource,
didFailLoadForResource,
0, 0 };
WKBundlePageSetResourceLoadClient(toAPI(webPage), &resourceLoadClient.base);
return page;
}
void webkitWebPageDidReceiveMessage(WebKitWebPage* page, const String& messageName, ImmutableDictionary& message)
{
if (messageName == String("GetSnapshot")) {
SnapshotOptions snapshotOptions = static_cast<SnapshotOptions>(static_cast<API::UInt64*>(message.get("SnapshotOptions"))->value());
uint64_t callbackID = static_cast<API::UInt64*>(message.get("CallbackID"))->value();
SnapshotRegion region = static_cast<SnapshotRegion>(static_cast<API::UInt64*>(message.get("SnapshotRegion"))->value());
RefPtr<WebImage> snapshotImage;
WebPage* webPage = page->priv->webPage;
if (WebCore::FrameView* frameView = webPage->mainFrameView()) {
WebCore::IntRect snapshotRect;
switch (region) {
case SnapshotRegionVisible:
snapshotRect = frameView->visibleContentRect();
break;
case SnapshotRegionFullDocument:
snapshotRect = WebCore::IntRect(WebCore::IntPoint(0, 0), frameView->contentsSize());
break;
default:
ASSERT_NOT_REACHED();
}
if (!snapshotRect.isEmpty())
snapshotImage = webPage->scaledSnapshotWithOptions(snapshotRect, 1, snapshotOptions | SnapshotOptionsShareable);
}
ImmutableDictionary::MapType messageReply;
messageReply.set("Page", webPage);
messageReply.set("CallbackID", API::UInt64::create(callbackID));
messageReply.set("Snapshot", snapshotImage);
WebProcess::shared().injectedBundle()->postMessage("WebPage.DidGetSnapshot", ImmutableDictionary::create(WTF::move(messageReply)).get());
} else
ASSERT_NOT_REACHED();
}
WebKitDOMDocument* webkit_web_page_get_dom_document(WebKitWebPage* webPage)
{
g_return_val_if_fail(WEBKIT_IS_WEB_PAGE(webPage), 0);
Frame* coreFrame = webPage->priv->webPage->mainFrame();
if (!coreFrame)
return 0;
return kit(coreFrame->document());
}
guint64 webkit_web_page_get_id(WebKitWebPage* webPage)
{
g_return_val_if_fail(WEBKIT_IS_WEB_PAGE(webPage), 0);
return webPage->priv->webPage->pageID();
}
const gchar* webkit_web_page_get_uri(WebKitWebPage* webPage)
{
g_return_val_if_fail(WEBKIT_IS_WEB_PAGE(webPage), 0);
return webPage->priv->uri.data();
}
WebKitFrame* webkit_web_page_get_main_frame(WebKitWebPage* webPage)
{
g_return_val_if_fail(WEBKIT_IS_WEB_PAGE(webPage), 0);
return webkitFrameGetOrCreate(webPage->priv->webPage->mainWebFrame());
}