#include "config.h"
#include "WebInspector.h"
#include "WebFrame.h"
#include "WebInspectorMessages.h"
#include "WebInspectorProxyMessages.h"
#include "WebInspectorUIMessages.h"
#include "WebPage.h"
#include "WebProcess.h"
#include <WebCore/Chrome.h>
#include <WebCore/Document.h>
#include <WebCore/FrameLoadRequest.h>
#include <WebCore/FrameLoader.h>
#include <WebCore/FrameView.h>
#include <WebCore/InspectorController.h>
#include <WebCore/InspectorFrontendClient.h>
#include <WebCore/InspectorPageAgent.h>
#include <WebCore/MainFrame.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/Page.h>
#include <WebCore/ScriptController.h>
#include <WebCore/WindowFeatures.h>
using namespace WebCore;
static const float minimumAttachedHeight = 250;
static const float maximumAttachedHeightRatio = 0.75;
static const float minimumAttachedWidth = 500;
namespace WebKit {
Ref<WebInspector> WebInspector::create(WebPage* page)
{
return adoptRef(*new WebInspector(page));
}
WebInspector::WebInspector(WebPage* page)
: m_page(page)
{
}
WebInspector::~WebInspector()
{
if (m_frontendConnection)
m_frontendConnection->invalidate();
}
void WebInspector::openFrontendConnection(bool underTest)
{
#if USE(UNIX_DOMAIN_SOCKETS)
IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
IPC::Connection::Identifier connectionIdentifier(socketPair.server);
IPC::Attachment connectionClientPort(socketPair.client);
#elif OS(DARWIN)
mach_port_t listeningPort;
if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort) != KERN_SUCCESS)
CRASH();
if (mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
CRASH();
IPC::Connection::Identifier connectionIdentifier(listeningPort);
IPC::Attachment connectionClientPort(listeningPort, MACH_MSG_TYPE_MOVE_SEND);
#else
notImplemented();
return;
#endif
m_frontendConnection = IPC::Connection::createServerConnection(connectionIdentifier, *this);
m_frontendConnection->open();
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::CreateInspectorPage(connectionClientPort, canAttachWindow(), underTest), m_page->pageID());
}
void WebInspector::closeFrontendConnection()
{
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::DidClose(), m_page->pageID());
if (m_frontendConnection) {
m_frontendConnection->invalidate();
m_frontendConnection = nullptr;
}
m_attached = false;
m_previousCanAttach = false;
}
void WebInspector::bringToFront()
{
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::BringToFront(), m_page->pageID());
}
void WebInspector::show()
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().show();
}
void WebInspector::close()
{
if (!m_page->corePage())
return;
if (!m_frontendConnection)
return;
m_page->corePage()->inspectorController().disconnectFrontend(this);
closeFrontendConnection();
}
void WebInspector::openInNewTab(const String& urlString)
{
Page* inspectedPage = m_page->corePage();
if (!inspectedPage)
return;
Frame& inspectedMainFrame = inspectedPage->mainFrame();
FrameLoadRequest frameLoadRequest { *inspectedMainFrame.document(), inspectedMainFrame.document()->securityOrigin(), { urlString }, ASCIILiteral("_blank"), LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown };
NavigationAction action { *inspectedMainFrame.document(), frameLoadRequest.resourceRequest(), frameLoadRequest.initiatedByMainFrame(), NavigationType::LinkClicked };
Page* newPage = inspectedPage->chrome().createWindow(inspectedMainFrame, frameLoadRequest, { }, action);
if (!newPage)
return;
newPage->mainFrame().loader().load(WTFMove(frameLoadRequest));
}
void WebInspector::evaluateScriptForTest(const String& script)
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().evaluateForTestInFrontend(script);
}
void WebInspector::showConsole()
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().show();
m_frontendConnection->send(Messages::WebInspectorUI::ShowConsole(), 0);
}
void WebInspector::showResources()
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().show();
m_frontendConnection->send(Messages::WebInspectorUI::ShowResources(), 0);
}
void WebInspector::showTimelines()
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().show();
m_frontendConnection->send(Messages::WebInspectorUI::ShowTimelines(), 0);
}
void WebInspector::showMainResourceForFrame(uint64_t frameIdentifier)
{
WebFrame* frame = WebProcess::singleton().webFrame(frameIdentifier);
if (!frame)
return;
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().show();
String inspectorFrameIdentifier = m_page->corePage()->inspectorController().pageAgent()->frameId(frame->coreFrame());
m_frontendConnection->send(Messages::WebInspectorUI::ShowMainResourceForFrame(inspectorFrameIdentifier), 0);
}
void WebInspector::startPageProfiling()
{
if (!m_page->corePage())
return;
m_frontendConnection->send(Messages::WebInspectorUI::StartPageProfiling(), 0);
}
void WebInspector::stopPageProfiling()
{
if (!m_page->corePage())
return;
m_frontendConnection->send(Messages::WebInspectorUI::StopPageProfiling(), 0);
}
void WebInspector::startElementSelection()
{
if (!m_page->corePage())
return;
m_frontendConnection->send(Messages::WebInspectorUI::StartElementSelection(), 0);
}
void WebInspector::stopElementSelection()
{
if (!m_page->corePage())
return;
m_frontendConnection->send(Messages::WebInspectorUI::StopElementSelection(), 0);
}
void WebInspector::elementSelectionChanged(bool active)
{
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::ElementSelectionChanged(active), m_page->pageID());
}
bool WebInspector::canAttachWindow()
{
if (!m_page->corePage())
return false;
if (m_page->isInspectorPage())
return false;
if (m_attached)
return true;
unsigned inspectedPageHeight = m_page->corePage()->mainFrame().view()->visibleHeight();
unsigned inspectedPageWidth = m_page->corePage()->mainFrame().view()->visibleWidth();
unsigned maximumAttachedHeight = inspectedPageHeight * maximumAttachedHeightRatio;
return minimumAttachedHeight <= maximumAttachedHeight && minimumAttachedWidth <= inspectedPageWidth;
}
void WebInspector::updateDockingAvailability()
{
if (m_attached)
return;
bool canAttachWindow = this->canAttachWindow();
if (m_previousCanAttach == canAttachWindow)
return;
m_previousCanAttach = canAttachWindow;
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::AttachAvailabilityChanged(canAttachWindow), m_page->pageID());
}
void WebInspector::sendMessageToBackend(const String& message)
{
if (!m_page->corePage())
return;
m_page->corePage()->inspectorController().dispatchMessageFromFrontend(message);
}
void WebInspector::sendMessageToFrontend(const String& message)
{
m_frontendConnection->send(Messages::WebInspectorUI::SendMessageToFrontend(message), 0);
}
}