#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/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;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND);
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 request(inspectedMainFrame.document()->securityOrigin(), ResourceRequest(urlString), "_blank", LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ReplaceDocumentIfJavaScriptURL, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
Page* newPage = inspectedPage->chrome().createWindow(&inspectedMainFrame, request, WindowFeatures(), NavigationAction(request.resourceRequest(), NavigationType::LinkClicked));
if (!newPage)
return;
newPage->mainFrame().loader().load(request);
}
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)
{
#if ENABLE(INSPECTOR_SERVER)
if (m_remoteFrontendConnected)
WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SendMessageToRemoteFrontend(message), m_page->pageID());
else
#endif
m_frontendConnection->send(Messages::WebInspectorUI::SendMessageToFrontend(message), 0);
}
#if ENABLE(INSPECTOR_SERVER)
void WebInspector::remoteFrontendConnected()
{
if (m_page->corePage()) {
m_remoteFrontendConnected = true;
m_page->corePage()->inspectorController().connectFrontend(this);
}
}
void WebInspector::remoteFrontendDisconnected()
{
m_remoteFrontendConnected = false;
if (m_page->corePage())
m_page->corePage()->inspectorController().disconnectFrontend(this);
}
#endif
}