diff --git a/browser_patches/webkit/BUILD_NUMBER b/browser_patches/webkit/BUILD_NUMBER index bd9b507079..cd2bf3dd87 100644 --- a/browser_patches/webkit/BUILD_NUMBER +++ b/browser_patches/webkit/BUILD_NUMBER @@ -1 +1 @@ -1242 +1243 diff --git a/browser_patches/webkit/patches/bootstrap.diff b/browser_patches/webkit/patches/bootstrap.diff index 2045c816d4..927e0894a9 100644 --- a/browser_patches/webkit/patches/bootstrap.diff +++ b/browser_patches/webkit/patches/bootstrap.diff @@ -1273,10 +1273,10 @@ index 0000000000000000000000000000000000000000..31806fde2a7df437ad9f604ad7df15f5 +} diff --git a/Source/JavaScriptCore/inspector/protocol/Screencast.json b/Source/JavaScriptCore/inspector/protocol/Screencast.json new file mode 100644 -index 0000000000000000000000000000000000000000..dd8bc8a94df9f3ffe5be0686c2a58eb412351f6d +index 0000000000000000000000000000000000000000..c29970d4e2f1c8b13d7d9716365eb5b6e65e080c --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Screencast.json -@@ -0,0 +1,38 @@ +@@ -0,0 +1,50 @@ +{ + "domain": "Screencast", + "availability": ["web"], @@ -1303,6 +1303,18 @@ index 0000000000000000000000000000000000000000..dd8bc8a94df9f3ffe5be0686c2a58eb4 + { + "name": "frameAck", + "description": "Sent by the client when a frame has been received." ++ }, ++ { ++ "name": "startVideoRecording", ++ "description": "Starts recoring video to speified file.", ++ "parameters": [ ++ { "name": "file", "type": "string", "description": "Output file location." } ++ ] ++ }, ++ { ++ "name": "stopVideoRecording", ++ "async": true, ++ "description": "Stops recoding video. Returns after the file has been closed." + } + ], + "events": [ @@ -4277,10 +4289,10 @@ index 6c75829502336b0806db2531e78186d2c559e44c..1ad6b8e863c56fd572910db6c6fb524d } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorScreencastAgent.cpp b/Source/WebCore/inspector/agents/InspectorScreencastAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..13ca5202e8e3ee5add01634037c2111798c58936 +index 0000000000000000000000000000000000000000..f534b449377965cce02feb91355f320f43cdcbed --- /dev/null +++ b/Source/WebCore/inspector/agents/InspectorScreencastAgent.cpp -@@ -0,0 +1,150 @@ +@@ -0,0 +1,160 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -4387,6 +4399,16 @@ index 0000000000000000000000000000000000000000..13ca5202e8e3ee5add01634037c21117 + --m_inflightFrames; +} + ++void InspectorScreencastAgent::startVideoRecording(Inspector::ErrorString& errorString, const String&) ++{ ++ errorString = "Not implemented."_s; ++} ++ ++void InspectorScreencastAgent::stopVideoRecording(Ref&& callback) ++{ ++ callback->sendFailure("Not implemented."_s); ++} ++ +bool InspectorScreencastAgent::isEnabled() const +{ + return m_instrumentingAgents.inspectorScreencastAgent(); @@ -4433,10 +4455,10 @@ index 0000000000000000000000000000000000000000..13ca5202e8e3ee5add01634037c21117 +#endif // PLATFORM(WPE) || PLATFORM(WIN) diff --git a/Source/WebCore/inspector/agents/InspectorScreencastAgent.h b/Source/WebCore/inspector/agents/InspectorScreencastAgent.h new file mode 100644 -index 0000000000000000000000000000000000000000..031911914c9fd89fb3ee8e42a95f97cdf1b9c4cd +index 0000000000000000000000000000000000000000..965437fd3cd0857e6a30bc99032ff6b450b2c833 --- /dev/null +++ b/Source/WebCore/inspector/agents/InspectorScreencastAgent.h -@@ -0,0 +1,79 @@ +@@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -4498,6 +4520,8 @@ index 0000000000000000000000000000000000000000..031911914c9fd89fb3ee8e42a95f97cd + void start(Inspector::ErrorString&, const String& format, const int* quality) override; + void stop(Inspector::ErrorString&) override; + void frameAck(Inspector::ErrorString&) override; ++ void startVideoRecording(Inspector::ErrorString&, const String& file) override; ++ void stopVideoRecording(Ref&&) override; + + void willDisplay(); + @@ -5304,6 +5328,27 @@ index 892d8de6d345d91fda80cfa5334c4aa68b757da3..a22497d801a349487be10b15139e9c76 #endif #if PLATFORM(IOS_FAMILY) +diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +index 9c197ed122c1d0f303a347dec0ce128e4d54942d..15b64635e6adf2965180d4cf4983a3f5190488e5 100644 +--- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp ++++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +@@ -38,6 +38,7 @@ + #include "Path.h" + #include "RefPtrCairo.h" + #include "Region.h" ++#include + #include + #include + #include +@@ -337,6 +338,8 @@ IntSize cairoSurfaceSize(cairo_surface_t* surface) + ASSERT(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE); + return IntSize(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface)); + #endif ++ case CAIRO_SURFACE_TYPE_XLIB: ++ return IntSize(cairo_xlib_surface_get_width(surface), cairo_xlib_surface_get_height(surface)); + default: + ASSERT_NOT_REACHED(); + return IntSize(); diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp index d79728555b7db9b59cb615c55a7a7a6851cb57c8..61d3cc4b488e35ef9e1afa1ce3ac5f5d60ebe9a7 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp @@ -6530,6 +6575,30 @@ index 407361f036e79891767d807fbb63c9044b260a70..24773d8f349d441e2b6b1981baa5af17 return makeUnique(channel, soupSession(), soupMessage.get(), protocol); } +diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake +index f829dc36172fd11514c00f4191d04a4545c64432..80316193cbbc3cd8501b6abd09292afe188601f0 100644 +--- a/Source/WebKit/PlatformGTK.cmake ++++ b/Source/WebKit/PlatformGTK.cmake +@@ -446,6 +446,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES + ${GSTREAMER_PBUTILS_INCLUDE_DIRS} + ${GTK_INCLUDE_DIRS} + ${LIBSOUP_INCLUDE_DIRS} ++# Playwright begin ++ ${LIBVPX_INCLUDE_DIRS} ++# Playwright end + ) + + if (USE_WPE_RENDERER) +@@ -499,6 +502,9 @@ if (USE_LIBWEBRTC) + list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/" + "${THIRDPARTY_DIR}/libwebrtc/Source/webrtc" ++# Playwright begin ++ "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" ++# Playwright end + ) + endif () + diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index 8320e310e6c466924a083ee46ae31f5486420fcd..33e1a5f6d846a490bb66848cfc1518a5b17104fd 100644 --- a/Source/WebKit/PlatformWPE.cmake @@ -6986,7 +7055,7 @@ index b72ac530c1d19d4803dd548186a4fbfbff899dd0..298205de7664a1c3cd4d330d7154999d UIProcess/Inspector/mac/WebInspectorProxyMac.mm UIProcess/Inspector/mac/WKInspectorViewController.mm diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt -index 76f1e08ca934a654edc48e199ce3eb120604c28c..4c2d98de146282d0be953bb2c1ddee856f4c60b7 100644 +index 76f1e08ca934a654edc48e199ce3eb120604c28c..197c27cc33b70dc62ad27776e7d0a185cc9321d0 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -136,6 +136,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify @@ -6997,7 +7066,15 @@ index 76f1e08ca934a654edc48e199ce3eb120604c28c..4c2d98de146282d0be953bb2c1ddee85 UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify -@@ -247,6 +248,7 @@ UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp +@@ -227,6 +228,7 @@ UIProcess/geoclue/GeoclueGeolocationProvider.cpp + + UIProcess/Inspector/glib/RemoteInspectorClient.cpp + ++UIProcess/Inspector/Agents/ScreencastEncoder.cpp + UIProcess/Inspector/gtk/RemoteWebInspectorProxyGtk.cpp + UIProcess/Inspector/gtk/WebInspectorProxyGtk.cpp + UIProcess/Inspector/gtk/WebKitInspectorWindow.cpp +@@ -247,6 +249,7 @@ UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp UIProcess/cairo/BackingStoreCairo.cpp @no-unify @@ -7005,7 +7082,7 @@ index 76f1e08ca934a654edc48e199ce3eb120604c28c..4c2d98de146282d0be953bb2c1ddee85 UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp UIProcess/glib/WebsiteDataStoreGLib.cpp @no-unify -@@ -262,6 +264,7 @@ UIProcess/gtk/ClipboardGtk3.cpp @no-unify +@@ -262,6 +265,7 @@ UIProcess/gtk/ClipboardGtk3.cpp @no-unify UIProcess/gtk/ClipboardGtk4.cpp @no-unify UIProcess/gtk/GestureController.cpp UIProcess/gtk/HardwareAccelerationManager.cpp @@ -7013,7 +7090,7 @@ index 76f1e08ca934a654edc48e199ce3eb120604c28c..4c2d98de146282d0be953bb2c1ddee85 UIProcess/gtk/KeyBindingTranslator.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify -@@ -272,6 +275,8 @@ UIProcess/gtk/WaylandCompositor.cpp @no-unify +@@ -272,6 +276,8 @@ UIProcess/gtk/WaylandCompositor.cpp @no-unify UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp @@ -8395,26 +8472,35 @@ index 6bbd1cabd27ae2847648a8c2edcf9acfcd556ff5..38d101b9a96986e40f6e9f0261fa429a { m_hasReceivedFirstUpdate = true; diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h -index d7695088e7cfc4f638f157338754f9f157489749..ba114d47ac079661702e44f19853398f5c1d6b55 100644 +index d7695088e7cfc4f638f157338754f9f157489749..2a5ebd52478027c65d66551b77becbfb006a95c4 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h -@@ -30,6 +30,7 @@ +@@ -30,6 +30,8 @@ #include "BackingStore.h" #include "DrawingAreaProxy.h" #include "LayerTreeContext.h" ++#include +#include #include namespace WebCore { -@@ -49,6 +50,7 @@ public: +@@ -49,6 +51,15 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; } + void waitForSizeUpdate(Function&&); ++ ++ using PaintCallback = Function; ++ void setPaintCallback(PaintCallback&& callback) { m_paintCallback = WTFMove(callback); } ++ void didPaint(cairo_surface_t* surface) ++ { ++ if (m_paintCallback) ++ m_paintCallback(surface); ++ } private: // DrawingAreaProxy -@@ -126,6 +128,8 @@ private: +@@ -126,12 +137,15 @@ private: // For a new Drawing Area don't draw anything until the WebProcess has sent over the first content. bool m_hasReceivedFirstUpdate { false }; @@ -8423,6 +8509,13 @@ index d7695088e7cfc4f638f157338754f9f157489749..ba114d47ac079661702e44f19853398f #if !PLATFORM(WPE) bool m_isBackingStoreDiscardable { true }; std::unique_ptr m_backingStore; + RunLoop::Timer m_discardBackingStoreTimer; + #endif + std::unique_ptr m_drawingMonitor; ++ PaintCallback m_paintCallback; + }; + + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp index 592fa4c4d9a45eb1e9b95e0cdabc8d404b40018d..e7889c60fffb8979ee3965295b3221989ea48e05 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp @@ -8525,10 +8618,10 @@ index 59cdfdafab1d85ea3a5aecb3cd2293e6dfb1eb8d..52fe7990b1c18b964ee3cfa9f324e3c2 // The timeout we use when waiting for a DidUpdateGeometry message. diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..f301bc4d2782a4ba1deca8bb59da46c00ae09896 +index 0000000000000000000000000000000000000000..abc002273f8cd4a92b31f37c901227657d8e1c88 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp -@@ -0,0 +1,206 @@ +@@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -8565,6 +8658,8 @@ index 0000000000000000000000000000000000000000..f301bc4d2782a4ba1deca8bb59da46c0 +#include + +#if PLATFORM(GTK) ++#include "DrawingAreaProxyCoordinatedGraphics.h" ++#include "ScreencastEncoder.h" +#include +#include +#include @@ -8653,6 +8748,49 @@ index 0000000000000000000000000000000000000000..f301bc4d2782a4ba1deca8bb59da46c0 +#endif +} + ++void InspectorScreencastAgent::startVideoRecording(Inspector::ErrorString& errorString, const String& file) ++{ ++#if PLATFORM(GTK) ++ if (m_encoder) { ++ errorString = "Already recording."_s; ++ return; ++ } ++ ++ m_encoder = makeUnique(); ++ if (auto* drawingArea = static_cast(m_page.drawingArea())) { ++ m_encoder->init(file, drawingArea->size().width(), drawingArea->size().height()); ++ drawingArea->setPaintCallback([encoder = m_encoder.get()] (cairo_surface_t* surface) { ++ encoder->encodeFrame(surface); ++ }); ++ } else { ++ m_encoder = nullptr; ++ errorString = "Cannot get drawing area."_s; ++ return; ++ } ++#else ++ errorString = "Not implemented."_s; ++#endif ++} ++ ++void InspectorScreencastAgent::stopVideoRecording(Ref&& callback) ++{ ++#if PLATFORM(GTK) ++ if (!m_encoder) { ++ callback->sendFailure("Not recording."_s); ++ return; ++ } ++ ++ if (auto* drawingArea = static_cast(m_page.drawingArea())) ++ drawingArea->setPaintCallback(nullptr); ++ ++ m_encoder->finish(); ++ m_encoder = nullptr; ++ callback->sendSuccess(); ++#else ++ callback->sendFailure("Not implemented."_s); ++#endif ++} ++ +void InspectorScreencastAgent::scheduleSnapshot() +{ + if (!m_enabled) @@ -8737,10 +8875,10 @@ index 0000000000000000000000000000000000000000..f301bc4d2782a4ba1deca8bb59da46c0 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h new file mode 100644 -index 0000000000000000000000000000000000000000..a1d8892da8bebd48346a4ccb9e9836dab9da7909 +index 0000000000000000000000000000000000000000..a957c3b2586d67caa78b96bb8644bab8d8919e14 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h -@@ -0,0 +1,78 @@ +@@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -8784,6 +8922,7 @@ index 0000000000000000000000000000000000000000..a1d8892da8bebd48346a4ccb9e9836da + +namespace WebKit { + ++class ScreencastEncoder; +class WebPageProxy; + +class InspectorScreencastAgent : public Inspector::InspectorAgentBase, public Inspector::ScreencastBackendDispatcherHandler, public CanMakeWeakPtr { @@ -8799,6 +8938,9 @@ index 0000000000000000000000000000000000000000..a1d8892da8bebd48346a4ccb9e9836da + void start(Inspector::ErrorString&, const String& format, const int* quality) override; + void stop(Inspector::ErrorString&) override; + void frameAck(Inspector::ErrorString&) override; ++ void startVideoRecording(Inspector::ErrorString&, const String& file) override; ++ void stopVideoRecording(Ref&&) override; ++ + +private: +#if PLATFORM(GTK) @@ -8816,6 +8958,413 @@ index 0000000000000000000000000000000000000000..a1d8892da8bebd48346a4ccb9e9836da + enum class ImageFormat { Jpeg, Png }; + ImageFormat m_format { ImageFormat::Jpeg }; + Optional m_quality; ++#if PLATFORM(GTK) ++ std::unique_ptr m_encoder; ++#endif ++}; ++ ++} // namespace WebKit +diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp +new file mode 100644 +index 0000000000000000000000000000000000000000..ba60958fd56bf1a648212ea6ca413cb17c2647a8 +--- /dev/null ++++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2020 Microsoft Corporation. ++ * ++ * 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 ++ * OWNER 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 "config.h" ++#include "ScreencastEncoder.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++using namespace WebCore; ++ ++namespace WebKit { ++ ++namespace { ++// Defines the dimension of a macro block. This is used to compute the active ++// map for the encoder. ++const int kMacroBlockSize = 16; ++ ++void createImage(IntSize size, ++ std::unique_ptr& out_image, ++ std::unique_ptr& out_image_buffer) { ++ std::unique_ptr image(new vpx_image_t()); ++ memset(image.get(), 0, sizeof(vpx_image_t)); ++ ++ // libvpx seems to require both to be assigned. ++ image->d_w = size.width(); ++ image->w = size.width(); ++ image->d_h = size.height(); ++ image->h = size.height(); ++ ++ // I420 ++ image->fmt = VPX_IMG_FMT_YV12; ++ image->x_chroma_shift = 1; ++ image->y_chroma_shift = 1; ++ ++ // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad ++ // the Y, U and V planes' strides to multiples of 16 bytes. ++ const int y_stride = ((image->w - 1) & ~15) + 16; ++ const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; ++ const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; ++ ++ // libvpx accesses the source image in macro blocks, and will over-read ++ // if the image is not padded out to the next macroblock: crbug.com/119633. ++ // Pad the Y, U and V planes' height out to compensate. ++ // Assuming macroblocks are 16x16, aligning the planes' strides above also ++ // macroblock aligned them. ++ static_assert(kMacroBlockSize == 16, "macroblock_size_not_16"); ++ const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; ++ const int uv_rows = y_rows >> image->y_chroma_shift; ++ ++ // Allocate a YUV buffer large enough for the aligned data & padding. ++ const int buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; ++ std::unique_ptr image_buffer(new uint8_t[buffer_size]); ++ ++ // Reset image value to 128 so we just need to fill in the y plane. ++ memset(image_buffer.get(), 128, buffer_size); ++ ++ // Fill in the information for |image_|. ++ unsigned char* uchar_buffer = ++ reinterpret_cast(image_buffer.get()); ++ image->planes[0] = uchar_buffer; ++ image->planes[1] = image->planes[0] + y_stride * y_rows; ++ image->planes[2] = image->planes[1] + uv_stride * uv_rows; ++ image->stride[0] = y_stride; ++ image->stride[1] = uv_stride; ++ image->stride[2] = uv_stride; ++ ++ out_image = std::move(image); ++ out_image_buffer = std::move(image_buffer); ++} ++ ++void mem_put_le16(void *vmem, int val) { ++ unsigned char *mem = (unsigned char *)vmem; ++ ++ mem[0] = (unsigned char)((val >> 0) & 0xff); ++ mem[1] = (unsigned char)((val >> 8) & 0xff); ++} ++ ++void mem_put_le32(void *vmem, int val) { ++ unsigned char *mem = (unsigned char *)vmem; ++ ++ mem[0] = (unsigned char)((val >> 0) & 0xff); ++ mem[1] = (unsigned char)((val >> 8) & 0xff); ++ mem[2] = (unsigned char)((val >> 16) & 0xff); ++ mem[3] = (unsigned char)((val >> 24) & 0xff); ++} ++ ++void ivf_write_file_header_with_video_info(FILE *outfile, unsigned int fourcc, ++ int frame_cnt, int frame_width, ++ int frame_height, ++ vpx_rational_t timebase) { ++ char header[32]; ++ ++ header[0] = 'D'; ++ header[1] = 'K'; ++ header[2] = 'I'; ++ header[3] = 'F'; ++ mem_put_le16(header + 4, 0); // version ++ mem_put_le16(header + 6, 32); // header size ++ mem_put_le32(header + 8, fourcc); // fourcc ++ mem_put_le16(header + 12, frame_width); // width ++ mem_put_le16(header + 14, frame_height); // height ++ mem_put_le32(header + 16, timebase.den); // rate ++ mem_put_le32(header + 20, timebase.num); // scale ++ mem_put_le32(header + 24, frame_cnt); // length ++ mem_put_le32(header + 28, 0); // unused ++ ++ fwrite(header, 1, 32, outfile); ++} ++ ++void ivf_write_file_header(FILE *outfile, const struct vpx_codec_enc_cfg *cfg, ++ unsigned int fourcc, int frame_cnt) { ++ ivf_write_file_header_with_video_info(outfile, fourcc, frame_cnt, cfg->g_w, ++ cfg->g_h, cfg->g_timebase); ++} ++ ++void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size) { ++ char header[12]; ++ ++ mem_put_le32(header, (int)frame_size); ++ mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF)); ++ mem_put_le32(header + 8, (int)(pts >> 32)); ++ fwrite(header, 1, 12, outfile); ++} ++ ++void ivf_write_frame_size(FILE *outfile, size_t frame_size) { ++ char header[4]; ++ ++ mem_put_le32(header, (int)frame_size); ++ fwrite(header, 1, 4, outfile); ++} ++ ++ ++int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img, ++ int frame_index, FILE* file) { ++ vpx_codec_iter_t iter = nullptr; ++ const vpx_codec_cx_pkt_t *pkt = nullptr; ++ int flags = 0; ++ const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, flags, VPX_DL_REALTIME); ++ if (res != VPX_CODEC_OK) { ++ fprintf(stderr, "Failed to encode frame: %d\n", res); ++ return 0; ++ } ++ ++ int got_pkts = 0; ++ while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != nullptr) { ++ got_pkts = 1; ++ ++ fprintf(stderr, " pkt->kind=%d\n", pkt->kind); ++ if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { ++ const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; ++ ivf_write_frame_header(file, pkt->data.frame.pts, pkt->data.frame.sz); ++ if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, file) != pkt->data.frame.sz) { ++ fprintf(stderr, "Failed to write compressed frame\n"); ++ return 0; ++ } ++ ++ fprintf(stderr, " writtend frame (key=%d)\n", keyframe); ++ } ++ } ++ ++ return got_pkts; ++} ++ ++} // namespace ++ ++ ++struct ScreencastEncoder::CodecInfo { ++ uint32_t fourcc = 0; ++ vpx_codec_ctx_t codec; ++ vpx_codec_enc_cfg_t cfg; ++ vpx_codec_iface_t* codec_interface = nullptr; ++ FILE* file = nullptr; ++}; ++ ++ScreencastEncoder::ScreencastEncoder() ++{ ++} ++ ++ScreencastEncoder::~ScreencastEncoder() ++{ ++ finish(); ++} ++ ++#define VP8_FOURCC 0x30385056 ++#define VP9_FOURCC 0x30395056 ++ ++void ScreencastEncoder::init(const String& filePath, int w, int h) ++{ ++ vpx_codec_ctx_t codec; ++ vpx_codec_enc_cfg_t cfg; ++ const int fps = 30; ++ ++ const uint32_t fourcc = VP8_FOURCC; ++ vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); ++ ++ if (!codec_interface) { ++ fprintf(stderr, "Unsupported codec.\n"); ++ return; ++ } ++ ++ if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0) { ++ fprintf(stderr, "Invalid frame size: %dx%d\n", w, h); ++ return; ++ } ++ ++ vpx_codec_err_t res = vpx_codec_enc_config_default(codec_interface, &cfg, 0); ++ if (res) { ++ fprintf(stderr, "Failed to get default codec config.\n"); ++ return; ++ } ++ ++ cfg.g_w = w; ++ cfg.g_h = h; ++ cfg.g_timebase.num = 1; ++ cfg.g_timebase.den = fps; ++ cfg.rc_target_bitrate = 200; ++ cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; ++ ++ if (vpx_codec_enc_init(&codec, codec_interface, &cfg, 0)) { ++ fprintf(stderr, "Failed to initialize encoder\n"); ++ return; ++ } ++ ++ FILE* file = fopen(filePath.utf8().data(), "wb"); ++ if (!file) { ++ fprintf(stderr, "%s can't be written to.\n", filePath.utf8().data()); ++ return; ++ } ++ ++ ivf_write_file_header(file, &cfg, fourcc, 0); ++ ++ m_codecInfo.reset(new CodecInfo()); ++ m_codecInfo->fourcc = fourcc; ++ m_codecInfo->codec = codec; ++ m_codecInfo->cfg = cfg; ++ m_codecInfo->codec_interface = codec_interface; ++ m_codecInfo->file = file; ++ ++ fprintf(stderr, "ScreencastEncoder initialized: %s\n", vpx_codec_iface_name(codec_interface)); ++} ++ ++void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface) ++{ ++ fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); ++ // fprintf(stderr, "cairo_surface_get_type(image)=%d CAIRO_SURFACE_TYPE_IMAGE=%d CAIRO_SURFACE_TYPE_XLIB=%d\n", cairo_surface_get_type(drawingAreaSurface), CAIRO_SURFACE_TYPE_IMAGE, CAIRO_SURFACE_TYPE_XLIB); ++ // fprintf(stderr, "cairo_image_surface_get_format(image)=%d CAIRO_FORMAT_ARGB32=%d\n", cairo_image_surface_get_format(drawingAreaSurface), CAIRO_FORMAT_ARGB32); ++ ++ IntSize size = cairoSurfaceSize(drawingAreaSurface); ++ if (size.isZero()) { ++ fprintf(stderr, "Cairo surface size is 0\n"); ++ return; ++ } ++ ++ // TODO: scale image if the size has changed. ++ // TODO: adjust device scale factor? ++ RefPtr newSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height())); ++ { ++ RefPtr cr = adoptRef(cairo_create(newSurface.get())); ++ cairo_set_source_surface(cr.get(), drawingAreaSurface, 0, 0); ++ cairo_paint(cr.get()); ++ } ++ cairo_surface_flush(newSurface.get()); ++ ++ std::unique_ptr image; ++ std::unique_ptr image_buffer; ++ createImage(size, image, image_buffer); ++ ++ ++ // Convert the updated region to YUV ready for encoding. ++ const uint8_t* rgba_data = cairo_image_surface_get_data(newSurface.get()); ++ int rgba_stride = cairo_image_surface_get_stride(newSurface.get()); ++ ++ const int y_stride = image->stride[0]; ++ ASSERT(image->stride[1] == image->stride[2]); ++ const int uv_stride = image->stride[1]; ++ uint8_t* y_data = image->planes[0]; ++ uint8_t* u_data = image->planes[1]; ++ uint8_t* v_data = image->planes[2]; ++ ++ // TODO: redraw only damaged regions? ++ libyuv::ARGBToI420(rgba_data, rgba_stride, ++ y_data, y_stride, ++ u_data, uv_stride, ++ v_data, uv_stride, ++ size.width(), size.height()); ++ if (encode_frame(&m_codecInfo->codec, image.get(), m_frameCount, m_codecInfo->file)) ++ ++m_frameCount; ++} ++ ++void ScreencastEncoder::finish() ++{ ++ if (!m_codecInfo) ++ return; ++ ++ // Flush encoder. ++ while (encode_frame(&m_codecInfo->codec, NULL, -1, m_codecInfo->file)) { ++ fprintf(stderr, "flushed frame\n"); ++ ++m_frameCount; ++ } ++ ++ ++ fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount); ++ rewind(m_codecInfo->file); ++ ivf_write_file_header(m_codecInfo->file, &m_codecInfo->cfg, m_codecInfo->fourcc, m_frameCount); ++ fclose(m_codecInfo->file); ++ ++ m_codecInfo = nullptr; ++ m_frameCount = 0; ++} ++ ++ ++} // namespace WebKit +diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..944d7166b9e6c74579eb43883c04042d2a7f86e3 +--- /dev/null ++++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (C) 2020 Microsoft Corporation. ++ * ++ * 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 ++ * OWNER 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. ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++ ++namespace WebKit { ++ ++class WebPageProxy; ++ ++class ScreencastEncoder { ++ WTF_MAKE_NONCOPYABLE(ScreencastEncoder); ++ WTF_MAKE_FAST_ALLOCATED; ++public: ++ ScreencastEncoder(); ++ ~ScreencastEncoder(); ++ ++ void init(const String& filePath, int width, int height); ++ void encodeFrame(cairo_surface_t*); ++ void finish(); ++ ++private: ++ struct CodecInfo; ++ std::unique_ptr m_codecInfo; ++ int m_frameCount { 0 }; +}; + +} // namespace WebKit @@ -12325,6 +12874,20 @@ index 0000000000000000000000000000000000000000..4cba2671042d3517e4b8f66e7b2bb780 +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) +diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.cpp +index be19b6007c9c0fbfffb859e40fd34751493fe7d1..bedd37fb70f878b9bf87beef0f9968c1ec24457e 100644 +--- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.cpp ++++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.cpp +@@ -256,6 +256,9 @@ bool AcceleratedBackingStoreX11::paint(cairo_t* cr, const IntRect& clipRect) + + cairo_restore(cr); + ++ if (auto* drawingArea = static_cast(m_webPage.drawingArea())) ++ drawingArea->didPaint(m_surface.get()); ++ + cairo_surface_flush(m_surface.get()); + + return true; diff --git a/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a86cc348bc210b71bb463dcb3057f575ad7c1d3 @@ -14239,8 +14802,39 @@ index ad9bfdd5321d17b108e414ac96e0222fdeae97cc..9fc34ccd13b6001b4b1c423dc48cadee // For backwards compatibility with the WebBackForwardList API, we honor both // a per-WebView and a per-preferences setting for whether to use the back/forward cache. +diff --git a/Source/cmake/FindLibVPX.cmake b/Source/cmake/FindLibVPX.cmake +new file mode 100644 +index 0000000000000000000000000000000000000000..dd6a53e2d57318489b7e49dd7373706d5d9dc387 +--- /dev/null ++++ b/Source/cmake/FindLibVPX.cmake +@@ -0,0 +1,25 @@ ++# Find LibVPX ++ ++find_package(PkgConfig QUIET) ++pkg_check_modules(PC_LIBVPX REQUIRED vpx) ++ ++find_path(LIBVPX_INCLUDE_DIRS ++ NAMES vpx/vp8.h ++ HINTS ${PC_LIBVPX_INCLUDEDIR} ++ ${PC_LIBVPX_INCLUDE_DIRS} ++) ++ ++find_library(LIBVPX_LIBRARIES ++ NAMES vpx ++ HINTS ${PC_LIBVPX_LIBDIR} ++ ${PC_LIBVPX_LIBRARY_DIRS} ++) ++ ++include(FindPackageHandleStandardArgs) ++FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVPX REQUIRED_VARS LIBVPX_INCLUDE_DIRS LIBVPX_LIBRARIES ++ VERSION_VAR PC_LIBVPX_VERSION) ++ ++mark_as_advanced( ++ LIBVPX_INCLUDE_DIRS ++ LIBVPX_LIBRARIES ++) diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake -index b1ac2660496e0e250a58063be5f970cf38c7ea7a..9aa2e9d07abeb3c3851fe731efbca2307152aa71 100644 +index b1ac2660496e0e250a58063be5f970cf38c7ea7a..ec51505cff30a16dc9da98a05e95de0f41cb8256 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake @@ -5,6 +5,7 @@ WEBKIT_OPTION_BEGIN() @@ -14251,7 +14845,18 @@ index b1ac2660496e0e250a58063be5f970cf38c7ea7a..9aa2e9d07abeb3c3851fe731efbca230 if (USE_GTK4) set(WEBKITGTK_API_VERSION 5.0) -@@ -197,6 +198,13 @@ if (USE_GTK4) +@@ -55,6 +56,10 @@ find_package(EGL) + find_package(OpenGL) + find_package(OpenGLES2) + ++# Playwright begin ++find_package(LibVPX REQUIRED) ++# Playwright end ++ + include(GStreamerDefinitions) + + SET_AND_EXPOSE_TO_BUILD(USE_ATK TRUE) +@@ -197,6 +202,13 @@ if (USE_GTK4) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NETSCAPE_PLUGIN_API PRIVATE OFF) endif ()