chromium/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h"

#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/typed_macros.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/fileapi/blob.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
#include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/image-encoders/image_encoder_utils.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_skia.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"

#include "third_party/skia/include/core/SkSurface.h"

namespace blink {

namespace {

// small slack period between deadline and current time for safety
constexpr base::TimeDelta kCreateBlobSlackBeforeDeadline =;
constexpr base::TimeDelta kEncodeRowSlackBeforeDeadline =;

/* The value is based on user statistics on Nov 2017. */
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_WIN))
const double kIdleTaskStartTimeoutDelayMs =;
#else
const double kIdleTaskStartTimeoutDelayMs = 4000.0;  // For ChromeOS, Mobile
#endif

/* The value is based on user statistics on May 2018. */
// We should be more lenient on completion timeout delay to ensure that the
// switch from idle to main thread only happens to a minority of toBlob calls
#if !BUILDFLAG(IS_ANDROID)
// Png image encoding on 4k by 4k canvas on Mac HDD takes 5.7+ seconds
// We see that 99% users require less than 5 seconds.
const double kIdleTaskCompleteTimeoutDelayMs =;
#else
// Png image encoding on 4k by 4k canvas on Android One takes 9.0+ seconds
// We see that 99% users require less than 9 seconds.
const double kIdleTaskCompleteTimeoutDelayMs = 9000.0;
#endif

bool IsCreateBlobDeadlineNearOrPassed(base::TimeTicks deadline) {}

bool IsEncodeRowDeadlineNearOrPassed(base::TimeTicks deadline,
                                     size_t image_width) {}

void RecordIdleTaskStatusHistogram(
    CanvasAsyncBlobCreator::IdleTaskStatus status) {}

void RecordInitiateEncodingTimeHistogram(ImageEncodingMimeType mime_type,
                                         base::TimeDelta elapsed_time) {}

void RecordCompleteEncodingTimeHistogram(ImageEncodingMimeType mime_type,
                                         base::TimeDelta elapsed_time) {}

void RecordScaledDurationHistogram(ImageEncodingMimeType mime_type,
                                   base::TimeDelta elapsed_time,
                                   float width,
                                   float height) {}

}  // anonymous namespace

CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
    scoped_refptr<StaticBitmapImage> image,
    const ImageEncodeOptions* options,
    ToBlobFunctionType function_type,
    base::TimeTicks start_time,
    ExecutionContext* context,
    const IdentifiableToken& input_digest,
    ScriptPromiseResolver<Blob>* resolver)
    :{}

CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
    scoped_refptr<StaticBitmapImage> image,
    const ImageEncodeOptions* options,
    ToBlobFunctionType function_type,
    V8BlobCallback* callback,
    base::TimeTicks start_time,
    ExecutionContext* context,
    const IdentifiableToken& input_digest,
    ScriptPromiseResolver<Blob>* resolver)
    :{}

CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() = default;

void CanvasAsyncBlobCreator::Dispose() {}

ImageEncodeOptions* CanvasAsyncBlobCreator::GetImageEncodeOptionsForMimeType(
    ImageEncodingMimeType mime_type) {}

bool CanvasAsyncBlobCreator::EncodeImage(
    std::unique_ptr<ImageDataBuffer> buffer,
    ImageEncodingMimeType mime_type,
    const double& quality,
    Vector<unsigned char>* encoded_image) {}

// Before the blob itself is created, we need to encode the image.
// This happens in one of the following ways:
//
//  1.   If progressive encoding is supported, then we use idle tasks
//       to gradually encode the image. This happens entirely on
//       the current thread.
//  2.   If progressive encoding is NOT supported, and
//    a. the current thread is the main thread, then we use a worker thread to
//       encode the image, otherwise:
//    b. if the current thread is not the main thread, then we encode the image
//       directly in the current thread.
//
// This function acquires SkImage and SkPixmap objects representing the
// to-be-encoded image, and at the end stores those objects as follows:
//
//  - For the progressive encoding case (1), stored to members on `this`,
//    which are then accessed from the various encoding stages. (All from the
//    same thread).
//  - For the off-thread case (2a), sent to that thread via CrossThreadBindOnce.
//  - For the in-thread case (2b), not stored anywhere, because encoding happens
//    within this function.
void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) {}

void CanvasAsyncBlobCreator::ScheduleInitiateEncoding(double quality) {}

void CanvasAsyncBlobCreator::InitiateEncoding(double quality,
                                              base::TimeTicks deadline) {}

void CanvasAsyncBlobCreator::IdleEncodeRows(base::TimeTicks deadline) {}

void CanvasAsyncBlobCreator::ForceEncodeRows() {}

void CanvasAsyncBlobCreator::CreateBlobAndReturnResult(
    Vector<unsigned char> encoded_image) {}

void CanvasAsyncBlobCreator::RecordIdentifiabilityMetric() {}

void CanvasAsyncBlobCreator::TraceCanvasContent(
    Vector<unsigned char>* encoded_image) {}

void CanvasAsyncBlobCreator::CreateNullAndReturnResult() {}

// Note that we keep `skia_image` around just to ensure that `data_buffer`
// (which contains a raw pointer to `skia_image`'s pixels') stays valid.
void CanvasAsyncBlobCreator::EncodeImageOnEncoderThread(
    CrossThreadHandle<CanvasAsyncBlobCreator> cross_thread_handle,
    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
    sk_sp<SkImage> skia_image,
    std::unique_ptr<ImageDataBuffer> data_buffer,
    ImageEncodingMimeType mime_type,
    double quality) {}

bool CanvasAsyncBlobCreator::InitializeEncoder(double quality) {}

void CanvasAsyncBlobCreator::IdleTaskStartTimeoutEvent(double quality) {}

void CanvasAsyncBlobCreator::IdleTaskCompleteTimeoutEvent() {}

void CanvasAsyncBlobCreator::PostDelayedTaskToCurrentThread(
    const base::Location& location,
    base::OnceClosure task,
    double delay_ms) {}

void CanvasAsyncBlobCreator::Trace(Visitor* visitor) const {}

}  // namespace blink