| /* |
| * 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(); |
| } |