blob: 188b9ea7607bc6d1e222c296cfcb17c4392d526b [file] [log] [blame]
/*
* Copyright 2016 The Fuchsia Authors. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDERS OR 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 "WebView.h"
#include <WebCore/BackForwardController.h>
#include <WebCore/FocusController.h>
#include <WebCore/FrameLoadRequest.h>
#include <WebCore/GraphicsContext.h>
#include <WebCore/IntSize.h>
#include <WebCore/LogInitialization.h>
#include <WebCore/MainFrame.h>
#include <WebCore/Page.h>
#include <WebCore/PageConfiguration.h>
#include <WebCore/PlatformKeyboardEvent.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/Settings.h>
#include <WebKit/fuchsia/WebCoreSupport/WebChromeClient.h>
#include <WebKit/fuchsia/WebCoreSupport/WebEditorClient.h>
#include <WebKit/fuchsia/WebCoreSupport/WebFrameLoaderClient.h>
#include <WebKit/fuchsia/WebCoreSupport/WebPlatformStrategies.h>
#include <WebStorageNamespaceProvider.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <hid/hid.h>
#include <hid/usages.h>
#include <magenta/pixelformat.h>
using namespace std;
using namespace WebCore;
WebView::~WebView()
{
if (m_cairoSurface) {
cairo_surface_destroy(m_cairoSurface);
}
if (m_cairoContext) {
cairo_destroy(m_cairoContext);
}
delete m_frameLoaderClient;
delete m_chromeClient;
delete m_page;
}
bool WebView::setup(unsigned char* pixelBuffer, int pixelFormat, size_t targetWidth, size_t targetHeight, size_t rowbytes)
{
cairo_format_t format = CAIRO_FORMAT_INVALID;
switch (pixelFormat) {
case MX_PIXEL_FORMAT_RGB_565:
format = CAIRO_FORMAT_RGB16_565;
break;
case MX_PIXEL_FORMAT_RGB_x888:
format = CAIRO_FORMAT_RGB24;
break;
case MX_PIXEL_FORMAT_ARGB_8888:
format = CAIRO_FORMAT_ARGB32;
break;
case MX_PIXEL_FORMAT_MONO_1:
format = CAIRO_FORMAT_A1;
break;
case MX_PIXEL_FORMAT_MONO_8:
format = CAIRO_FORMAT_A8;
break;
default:
cout << "Unsupported pixel format " << pixelFormat << endl;
return false;
}
m_cairoSurface = cairo_image_surface_create_for_data(pixelBuffer,
format,
targetWidth,
targetHeight,
rowbytes);
cairo_status_t cairoStatus = cairo_surface_status(m_cairoSurface);
if (cairoStatus != CAIRO_STATUS_SUCCESS) {
cout << "cairo_image_surface_create_for_data failed: " << cairo_status_to_string(cairoStatus) << endl;
return false;
}
m_cairoContext = cairo_create(m_cairoSurface);
static std::once_flag initializeOnceFlag;
std::call_once(initializeOnceFlag, [] {
setenv("WEBKIT_DEBUG", "", 1);
setenv("FONTCONFIG_FILE", "/system/fonts/fonts.conf", 1);
setenv("FONTCONFIG_USE_MMAP", "0", 1);
FcInit();
#if !LOG_DISABLED || !RELEASE_LOG_DISABLED
WebCore::initializeLogChannelsIfNecessary();
#endif
WTF::initializeThreading();
WTF::initializeMainThread();
WTF::RunLoop::initializeMainRunLoop();
WebPlatformStrategies::initializeIfNecessary();
});
m_pageWidth = targetWidth;
m_pageHeight = targetHeight;
if (m_page == nullptr) {
IntSize targetSize(targetWidth, targetHeight);
PageConfiguration pageConfiguration(makeUniqueRef<WebKit::WebEditorClient>(), SocketProvider::create());
fillWithEmptyClients(pageConfiguration);
m_frameLoaderClient = new WebFrameLoaderClient(targetSize);
pageConfiguration.loaderClientForMainFrame = m_frameLoaderClient;
pageConfiguration.storageNamespaceProvider = WebStorageNamespaceProvider::create("/data");
m_chromeClient = new WebChromeClient(targetSize);
pageConfiguration.chromeClient = m_chromeClient;
m_page = new Page(WTFMove(pageConfiguration));
Settings& settings = m_page->settings();
settings.setScriptEnabled(true);
settings.setLoadsImagesAutomatically(true);
settings.setLocalStorageEnabled(true);
m_page->setIsInWindow(true);
m_page->setGroupName("fuchsia_group");
auto& mainFrame = m_page->mainFrame();
m_frameLoaderClient->m_coreFrame = &mainFrame;
mainFrame.tree().setName("fuchsia_group");
mainFrame.init();
}
return true;
}
void WebView::setFileURL(const std::string& urlString)
{
URL fileURL(URL::fileURLWithFileSystemPath(urlString.c_str()));
setURLInternal(fileURL);
}
void WebView::setURL(const std::string& urlString)
{
URL url(ParsedURLString, urlString.c_str());
setURLInternal(url);
}
void WebView::setURLInternal(const WebCore::URL& url)
{
ResourceRequest resourceRequest(url);
auto& mainFrame = m_page->mainFrame();
auto& loader = mainFrame.loader();
FrameLoadRequest loadRequest(&mainFrame, resourceRequest, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
loader.load(loadRequest);
}
void WebView::goBack()
{
if (m_page) {
m_page->backForward().goBack();
}
}
void WebView::goForward()
{
if (m_page) {
m_page->backForward().goForward();
}
}
void WebView::layoutAndPaint()
{
Frame* frame = m_frameLoaderClient->m_coreFrame;
if (frame) {
GraphicsContext gc(m_cairoContext);
FrameView* view = frame->view();
view->updateLayoutAndStyleIfNeededRecursive();
if (view->frame().contentRenderer()) {
IntRect fullRect(0, 0, m_pageWidth, m_pageHeight);
view->paint(gc, fullRect);
}
cairo_surface_flush(m_cairoSurface);
}
}
void WebView::setFocused(bool focused)
{
auto& mainFrame = m_page->mainFrame();
m_page->focusController().setFocusedFrame(&mainFrame);
m_page->focusController().setActive(focused);
m_page->focusController().setFocused(focused);
}
void WebView::setVisible(bool visible)
{
m_page->setIsVisible(visible);
}
void WebView::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
{
auto& mainFrame = m_page->mainFrame();
mainFrame.setPageAndTextZoomFactors(pageZoomFactor, textZoomFactor);
}
void WebView::handleMouseEvent(int x, int y, MouseEventKind eventType)
{
auto& mainFrame = m_page->mainFrame();
IntPoint mousePosition(x, y);
auto now = std::chrono::steady_clock::now().time_since_epoch();
auto timeSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
if (eventType == kMouseDown) {
WebCore::PlatformMouseEvent mouseEvent(mousePosition, mousePosition,
WebCore::MouseButton::LeftButton, PlatformEvent::MousePressed,
1, false, false, false, false, timeSinceEpoch, 0, SyntheticClickType::NoTap);
mainFrame.eventHandler().handleMousePressEvent(mouseEvent);
} else if (eventType == kMouseUp) {
WebCore::PlatformMouseEvent mouseEvent(mousePosition, mousePosition,
WebCore::MouseButton::LeftButton, PlatformEvent::MouseReleased,
1, false, false, false, false, timeSinceEpoch, 0, SyntheticClickType::NoTap);
mainFrame.eventHandler().handleMouseReleaseEvent(mouseEvent);
} else {
WebCore::PlatformMouseEvent mouseEvent(mousePosition, mousePosition,
WebCore::MouseButton::NoButton, PlatformEvent::MouseMoved,
0, false, false, false, false, timeSinceEpoch, 0, SyntheticClickType::NoTap);
mainFrame.eventHandler().mouseMoved(mouseEvent);
}
}
void WebView::handleKeyEvent(uint8_t keycode, uint8_t charValue, bool pressed)
{
string identifier;
if (keycode == HID_USAGE_KEY_LEFT_SHIFT || keycode == HID_USAGE_KEY_RIGHT_SHIFT) {
fShift = pressed;
} else if (keycode == HID_USAGE_KEY_LEFT_CTRL || keycode == HID_USAGE_KEY_RIGHT_CTRL) {
fControl = pressed;
}
int rawModifiers = 0;
if (fControl) {
rawModifiers |= PlatformEvent::Modifiers::CtrlKey;
}
if (fShift) {
rawModifiers |= PlatformEvent::Modifiers::ShiftKey;
}
if (charValue != 0) {
ostringstream oss;
oss << "U+" << hex << setw(4) << setfill('0') << (int)charValue;
identifier = oss.str();
} else if (keycode == HID_USAGE_KEY_BACKSPACE) {
identifier = "U+0008";
charValue = 9;
} else if (keycode == HID_USAGE_KEY_TAB) {
identifier = "U+0009";
charValue = 8;
}
char charStr[2] = { static_cast<char>(charValue), 0 };
auto now = std::chrono::steady_clock::now().time_since_epoch();
auto timeSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
WebCore::PlatformKeyboardEvent keyboardEvent(pressed ? WebCore::PlatformEvent::KeyDown : WebCore::PlatformEvent::KeyUp, charStr, charStr, identifier.c_str(),
0, keycode, 0, false, false, false, (PlatformEvent::Modifiers)rawModifiers, timeSinceEpoch);
auto& mainFrame = m_page->mainFrame();
mainFrame.eventHandler().keyEvent(keyboardEvent);
}
void WebView::iterateEventLoop()
{
RunLoop::iterate();
}