chromium/content/renderer/gpu_benchmarking_extension.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/gpu_benchmarking_extension.h"

#include <stddef.h>

#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>

#include "base/base64.h"
#include "base/command_line.h"
#include "base/debug/profiler.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "build/build_config.h"
#include "cc/layers/layer.h"
#include "cc/paint/skia_paint_canvas.h"
#include "cc/trees/layer_tree_host.h"
#include "content/common/input/actions_parser.h"
#include "content/common/input/input_injector.mojom.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
#include "content/common/input/synthetic_pointer_action_list_params.h"
#include "content/common/input/synthetic_pointer_action_params.h"
#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/chrome_object_extensions_utils.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/v8_value_converter.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/skia_benchmarking_extension.h"
#include "gin/arguments.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h"
#include "third_party/blink/public/platform/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/web/modules/canvas/canvas_test_utils.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_image_cache.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/skia/include/core/SkDocument.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/docs/SkMultiPictureDocument.h"
#include "third_party/skia/include/docs/SkXPSDocument.h"
#include "third_party/skia/include/encode/SkPngEncoder.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/geometry/size_f.h"
#include "v8/include/v8-context.h"
#include "v8/include/v8-exception.h"
#include "v8/include/v8-function.h"
#include "v8/include/v8-isolate.h"
#include "v8/include/v8-object.h"
#include "v8/include/v8-persistent-handle.h"
#include "v8/include/v8-primitive.h"

#if BUILDFLAG(IS_WIN) && !defined(NDEBUG)
// XpsObjectModel.h indirectly includes <wincrypt.h> which is
// incompatible with Chromium's OpenSSL. By including wincrypt_shim.h
// first, problems are avoided.
// clang-format off
#include "base/win/wincrypt_shim.h"
// clang-format on

#include <objbase.h>

#include <XpsObjectModel.h>
#include <wrl/client.h>
#endif

namespace blink {

// This class allows us to access the LayerTreeHost on WebFrameWidget. It is
// hidden from the public interface. It also extracts some commonly
// used objects from RenderFrameImpl.
class GpuBenchmarkingContext {};

}  // namespace blink

GpuBenchmarkingContext;
WebImageCache;
WebLocalFrame;
WebView;

namespace content {

namespace {

int GestureSourceTypeAsInt(content::mojom::GestureSourceType type) {}

class SkPictureSerializer {};

template <typename T>
bool GetArg(gin::Arguments* args, T* value) {}

template <>
bool GetArg(gin::Arguments* args, int* value) {}

template <typename T>
bool GetOptionalArg(gin::Arguments* args, T* value) {}

class CallbackAndContext : public base::RefCounted<CallbackAndContext> {};

void RunCallbackHelper(CallbackAndContext* callback_and_context,
                       std::optional<base::Value> value) {}

void OnMicroBenchmarkCompleted(CallbackAndContext* callback_and_context,
                               base::Value::Dict result) {}

#if BUILDFLAG(IS_MAC)
void OnSwapCompletedWithCoreAnimationErrorCode(
    CallbackAndContext* callback_and_context,
    gfx::CALayerResult error_code) {
  RunCallbackHelper(callback_and_context,
                    std::optional<base::Value>(base::Value(error_code)));
}
#endif

void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) {}

bool ThrowIfPointOutOfBounds(GpuBenchmarkingContext* context,
                             gin::Arguments* args,
                             const gfx::Point& point,
                             const std::string& message) {}

std::optional<gfx::Vector2dF> ToVector(const std::string& direction,
                                       float distance) {}

int ToKeyModifiers(std::string_view key) {}

int ToButtonModifiers(std::string_view button) {}

// BeginSmoothScroll takes pixels_to_scroll_x and pixels_to_scroll_y, positive
// pixels_to_scroll_y means scroll down, positive pixels_to_scroll_x means
// scroll right.
bool BeginSmoothScroll(GpuBenchmarkingContext* context,
                       gin::Arguments* args,
                       const mojo::Remote<mojom::InputInjector>& injector,
                       const gfx::Vector2dF& pixels_to_scroll,
                       v8::Local<v8::Function> callback,
                       int gesture_source_type,
                       float speed_in_pixels_s,
                       bool prevent_fling,
                       float start_x,
                       float start_y,
                       const gfx::Vector2dF& fling_velocity,
                       bool precise_scrolling_deltas,
                       bool scroll_by_page,
                       bool cursor_visible,
                       bool scroll_by_percentage,
                       int modifiers,
                       float vsync_offset_ms,
                       int input_event_pattern) {}

bool BeginSmoothDrag(GpuBenchmarkingContext* context,
                     gin::Arguments* args,
                     const mojo::Remote<mojom::InputInjector>& injector,
                     float start_x,
                     float start_y,
                     float end_x,
                     float end_y,
                     v8::Local<v8::Function> callback,
                     int gesture_source_type,
                     float speed_in_pixels_s,
                     float vsync_offset_ms,
                     int input_event_pattern) {}

static void PrintDocument(blink::WebLocalFrame* frame, SkDocument* doc) {}

static void PrintDocumentTofile(v8::Isolate* isolate,
                                const std::string& filename,
                                sk_sp<SkDocument> (*make_doc)(SkWStream*),
                                RenderFrameImpl* render_frame) {}

void OnSwapCompletedHelper(CallbackAndContext* callback_and_context,
                           const viz::FrameTimingDetails&) {}

// This function is only used for correctness testing of this experimental
// feature; no need for it in release builds.
// Also note:  You must execute Chrome with `--no-sandbox` and
// `--enable-gpu-benchmarking` for this to work.
#if BUILDFLAG(IS_WIN) && !defined(NDEBUG)
static sk_sp<SkDocument> MakeXPSDocument(SkWStream* s) {
  // I am not sure why this hasn't been initialized yet.
  std::ignore = CoInitializeEx(
      nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  // In non-sandboxed mode, we will need to create and hold on to the
  // factory before entering the sandbox.
  Microsoft::WRL::ComPtr<IXpsOMObjectFactory> factory;
  HRESULT hr = ::CoCreateInstance(CLSID_XpsOMObjectFactory, nullptr,
                                  CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
  if (FAILED(hr) || !factory) {
    LOG(ERROR) << "CoCreateInstance(CLSID_XpsOMObjectFactory, ...) failed:"
               << logging::SystemErrorCodeToString(hr);
  }
  return SkXPS::MakeDocument(s, factory.Get());
}
#endif
}  // namespace

gin::WrapperInfo GpuBenchmarking::kWrapperInfo =;

// static
void GpuBenchmarking::Install(base::WeakPtr<RenderFrameImpl> frame) {}

GpuBenchmarking::GpuBenchmarking(base::WeakPtr<RenderFrameImpl> frame)
    :{}

GpuBenchmarking::~GpuBenchmarking() = default;

void GpuBenchmarking::EnsureRemoteInterface() {}

gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
    v8::Isolate* isolate) {}

void GpuBenchmarking::SetNeedsDisplayOnAllLayers() {}

void GpuBenchmarking::SetRasterizeOnlyVisibleContent() {}

namespace {
sk_sp<SkDocument> make_multipicturedocument(SkWStream* stream) {}
}  // namespace
void GpuBenchmarking::PrintPagesToSkPictures(v8::Isolate* isolate,
                                             const std::string& filename) {}

void GpuBenchmarking::PrintPagesToXPS(v8::Isolate* isolate,
                                      const std::string& filename) {}

void GpuBenchmarking::PrintToSkPicture(v8::Isolate* isolate,
                                       const std::string& dirname) {}

bool GpuBenchmarking::GestureSourceTypeSupported(int gesture_source_type) {}

// TODO(lanwei): this is will be removed after this is replaced by
// SmoothScrollByXY in telemetry/internal/actions/scroll.js.
bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) {}

// SmoothScrollByXY does not take direction as one of the arguments, and
// instead we pass two scroll delta values for both x and y directions, when
// pixels_to_scroll_y is positive, it will scroll down, otherwise scroll up.
// When pixels_to_scroll_x is positive, it will scroll right, otherwise
// scroll left.
bool GpuBenchmarking::SmoothScrollByXY(gin::Arguments* args) {}

bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) {}

// TODO(lanwei): Swipe takes pixels_to_scroll and direction. When the
// pixels_to_scroll is positive and direction is up, it means the finger moves
// up, but the page scrolls down, which is opposite to SmoothScrollBy. We
// should change this to match with SmoothScrollBy or SmoothScrollByXY.
bool GpuBenchmarking::Swipe(gin::Arguments* args) {}

bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) {}

bool GpuBenchmarking::PinchBy(gin::Arguments* args) {}

float GpuBenchmarking::PageScaleFactor() {}

void GpuBenchmarking::SetPageScaleFactor(float scale) {}

void GpuBenchmarking::SetBrowserControlsShown(bool show) {}

float GpuBenchmarking::VisualViewportY() {}

float GpuBenchmarking::VisualViewportX() {}

float GpuBenchmarking::VisualViewportHeight() {}

float GpuBenchmarking::VisualViewportWidth() {}

bool GpuBenchmarking::Tap(gin::Arguments* args) {}

bool GpuBenchmarking::PointerActionSequence(gin::Arguments* args) {}

void GpuBenchmarking::ClearImageCache() {}

int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {}

bool GpuBenchmarking::SendMessageToMicroBenchmark(
    int id,
    v8::Local<v8::Object> message) {}

bool GpuBenchmarking::HasGpuChannel() {}

bool GpuBenchmarking::HasGpuProcess() {}

void GpuBenchmarking::CrashGpuProcess() {}

// Terminates the GPU process with an exit code of 0.
void GpuBenchmarking::TerminateGpuProcessNormally() {}

void GpuBenchmarking::GetGpuDriverBugWorkarounds(gin::Arguments* args) {}

void GpuBenchmarking::StartProfiling(gin::Arguments* args) {}

void GpuBenchmarking::StopProfiling() {}

void GpuBenchmarking::Freeze() {}

bool GpuBenchmarking::AddSwapCompletionEventListener(gin::Arguments* args) {}

#if BUILDFLAG(IS_MAC)
int GpuBenchmarking::AddCoreAnimationStatusEventListener(gin::Arguments* args) {
  v8::Local<v8::Function> callback;
  if (!GetArg(args, &callback))
    return false;
  GpuBenchmarkingContext context(render_frame_.get());

  auto callback_and_context = base::MakeRefCounted<CallbackAndContext>(
      args->isolate(), callback, context.web_frame()->MainWorldScriptContext());
  context.frame_widget()->NotifyCoreAnimationErrorCode(
      base::BindOnce(&OnSwapCompletedWithCoreAnimationErrorCode,
                     base::RetainedRef(callback_and_context)));
  // Request a begin frame explicitly, as the test-api expects a 'swap' to
  // happen for the above queued swap promise even if there is no actual update.
  context.layer_tree_host()->SetNeedsAnimateIfNotInsideMainFrame();

  return true;
}
#endif

bool GpuBenchmarking::IsAcceleratedCanvasImageSource(gin::Arguments* args) {}

}  // namespace content