Commit f620bc08 authored by cfredric's avatar cfredric Committed by Commit Bot

Plumb proper input digest to CanvasAsyncBlobCreator.

This CL also removes one UKM collection point, since it is redundant
with the UKM collection done by CanvasAsyncBlobCreator.

Change-Id: If985fd00bb4d24a7064e8f1252a0131cf1890fbb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2481445
Commit-Queue: Chris Fredrickson <cfredric@google.com>
Reviewed-by: default avatarFernando Serboncini <fserb@chromium.org>
Reviewed-by: default avatarCaleb Raitto <caraitto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820811}
parent 464e6747
......@@ -155,7 +155,7 @@ IN_PROC_BROWSER_TEST_F(PrivacyBudgetBrowserTest, CallsCanvasToBlob) {
// adjust this test to deal.
ASSERT_EQ(1u, merged_entries.size());
constexpr uint64_t input_digest = 0;
constexpr uint64_t input_digest = 9;
EXPECT_THAT(merged_entries.begin()->second->metrics,
IsSupersetOf({
Key(blink::IdentifiableSurface::FromTypeAndToken(
......
......@@ -151,6 +151,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
base::TimeTicks start_time,
ExecutionContext* context,
UkmParameters ukm_params,
const IdentifiableToken& input_digest,
ScriptPromiseResolver* resolver)
: CanvasAsyncBlobCreator(image,
options,
......@@ -159,6 +160,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
start_time,
context,
ukm_params,
input_digest,
resolver) {}
CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
......@@ -169,6 +171,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
base::TimeTicks start_time,
ExecutionContext* context,
UkmParameters ukm_params,
const IdentifiableToken& input_digest,
ScriptPromiseResolver* resolver)
: fail_encoder_initialization_for_test_(false),
enforce_idle_encoding_for_test_(false),
......@@ -180,6 +183,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
static_bitmap_image_loaded_(false),
callback_(callback),
ukm_params_(ukm_params),
input_digest_(input_digest),
script_promise_resolver_(resolver) {
DCHECK(image);
DCHECK(context);
......@@ -500,7 +504,8 @@ void CanvasAsyncBlobCreator::RecordIdentifiabilityMetric() {
->PostTask(
FROM_HERE,
WTF::Bind(
[](scoped_refptr<StaticBitmapImage> image,
[](IdentifiableToken input_digest,
scoped_refptr<StaticBitmapImage> image,
UkmParameters ukm_params) {
std::unique_ptr<ImageDataBuffer> data_buffer =
ImageDataBuffer::Create(image);
......@@ -509,13 +514,13 @@ void CanvasAsyncBlobCreator::RecordIdentifiabilityMetric() {
blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
.Set(blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::kCanvasReadback,
0),
input_digest),
blink::IdentifiabilityDigestOfBytes(
base::make_span(data_buffer->Pixels(),
data_buffer->ComputeByteSize())))
.Record(ukm_params.ukm_recorder);
},
image_, ukm_params_));
input_digest_, image_, ukm_params_));
}
void CanvasAsyncBlobCreator::CreateNullAndReturnResult() {
......
......@@ -10,6 +10,7 @@
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_blob_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_image_encode_options.h"
......@@ -63,6 +64,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator
base::TimeTicks start_time,
ExecutionContext*,
UkmParameters ukm_params,
const IdentifiableToken& input_digest,
ScriptPromiseResolver*);
CanvasAsyncBlobCreator(scoped_refptr<StaticBitmapImage>,
const ImageEncodeOptions*,
......@@ -71,6 +73,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator
base::TimeTicks start_time,
ExecutionContext*,
UkmParameters ukm_params,
const IdentifiableToken& input_digest,
ScriptPromiseResolver* = nullptr);
virtual ~CanvasAsyncBlobCreator();
......@@ -137,6 +140,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator
Member<V8BlobCallback> callback_;
UkmParameters ukm_params_;
IdentifiableToken input_digest_;
// Used for OffscreenCanvas only
Member<ScriptPromiseResolver> script_promise_resolver_;
......
......@@ -37,6 +37,7 @@ class MockCanvasAsyncBlobCreator : public CanvasAsyncBlobCreator {
base::TimeTicks(),
document->GetExecutionContext(),
UkmParameters{document->UkmRecorder(), document->UkmSourceID()},
0,
nullptr) {
if (fail_encoder_initialization)
fail_encoder_initialization_for_test_ = true;
......@@ -300,7 +301,7 @@ TEST_F(CanvasAsyncBlobCreatorTest, ColorManagedConvertToBlob) {
CanvasAsyncBlobCreator::ToBlobFunctionType::
kHTMLCanvasConvertToBlobPromise,
base::TimeTicks(), GetFrame().DomWindow(),
UkmParameters{UkmRecorder(), 0}, nullptr);
UkmParameters{UkmRecorder(), 0}, 0, nullptr);
ASSERT_TRUE(async_blob_creator->EncodeImageForConvertToBlobTest());
sk_sp<SkData> sk_data = SkData::MakeWithCopy(
......
......@@ -8,6 +8,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/common/features.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/renderer/bindings/core/v8/v8_image_encode_options.h"
#include "third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h"
......@@ -287,7 +288,8 @@ CanvasColorParams CanvasRenderingContextHost::ColorParams() const {
ScriptPromise CanvasRenderingContextHost::convertToBlob(
ScriptState* script_state,
const ImageEncodeOptions* options,
ExceptionState& exception_state) {
ExceptionState& exception_state,
const CanvasRenderingContext* const context) {
WTF::String object_name = "Canvas";
if (this->IsOffscreenCanvas())
object_name = "OffscreenCanvas";
......@@ -338,7 +340,12 @@ ScriptPromise CanvasRenderingContextHost::convertToBlob(
}
auto* async_creator = MakeGarbageCollected<CanvasAsyncBlobCreator>(
image_bitmap, options, function_type, start_time,
ExecutionContext::From(script_state), ukm_params_, resolver);
ExecutionContext::From(script_state), ukm_params_,
IdentifiabilityStudySettings::Get()->IsTypeAllowed(
IdentifiableSurface::Type::kCanvasReadback)
? IdentifiabilityInputDigest(context)
: 0,
resolver);
async_creator->ScheduleAsyncBlobCreation(options->quality());
return resolver->Promise();
}
......@@ -351,4 +358,42 @@ bool CanvasRenderingContextHost::IsOffscreenCanvas() const {
return host_type_ == kOffscreenCanvasHost;
}
IdentifiableToken CanvasRenderingContextHost::IdentifiabilityInputDigest(
const CanvasRenderingContext* const context) const {
const uint64_t context_digest =
context ? context->IdentifiableTextToken().ToUkmMetricValue() : 0;
const IdentifiabilityPaintOpDigest* const identifiability_paintop_digest =
ResourceProvider()
? &(ResourceProvider()->GetIdentifiablityPaintOpDigest())
: nullptr;
const uint64_t canvas_digest =
identifiability_paintop_digest
? identifiability_paintop_digest->GetToken().ToUkmMetricValue()
: 0;
const uint64_t context_type =
context ? context->GetContextType()
: CanvasRenderingContext::kContextTypeUnknown;
const bool encountered_skipped_ops =
(context && context->IdentifiabilityEncounteredSkippedOps()) ||
(identifiability_paintop_digest &&
identifiability_paintop_digest->encountered_skipped_ops());
const bool encountered_sensitive_ops =
context && context->IdentifiabilityEncounteredSensitiveOps();
const bool encountered_partially_digested_image =
identifiability_paintop_digest &&
identifiability_paintop_digest->encountered_partially_digested_image();
// Bits [0-3] are the context type, bits [4-6] are skipped ops, sensitive
// ops, and partial image ops bits, respectively. The remaining bits are
// for the canvas digest.
uint64_t final_digest =
((context_digest ^ canvas_digest) << 7) | context_type;
if (encountered_skipped_ops)
final_digest |= IdentifiableSurface::CanvasTaintBit::kSkipped;
if (encountered_sensitive_ops)
final_digest |= IdentifiableSurface::CanvasTaintBit::kSensitive;
if (encountered_partially_digested_image)
final_digest |= IdentifiableSurface::CanvasTaintBit::kPartiallyDigested;
return final_digest;
}
} // namespace blink
......@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CANVAS_CANVAS_RENDERING_CONTEXT_HOST_H_
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
......@@ -82,9 +83,10 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost,
// For deferred canvases this will have the side effect of drawing recorded
// commands in order to finalize the frame.
virtual ScriptPromise convertToBlob(ScriptState*,
const ImageEncodeOptions*,
ExceptionState&);
ScriptPromise convertToBlob(ScriptState*,
const ImageEncodeOptions*,
ExceptionState&,
const CanvasRenderingContext* const context);
bool IsPaintable() const;
......@@ -119,6 +121,12 @@ class CORE_EXPORT CanvasRenderingContextHost : public CanvasResourceHost,
void CreateCanvasResourceProvider2D(RasterModeHint hint);
void CreateCanvasResourceProvider3D();
// Computes the digest that corresponds to the "input" of this canvas,
// including the context type, and if applicable, canvas digest, and taint
// bits.
IdentifiableToken IdentifiabilityInputDigest(
const CanvasRenderingContext* const context) const;
bool did_fail_to_create_resource_provider_ = false;
bool did_record_canvas_size_to_uma_ = false;
HostType host_type_ = kNone;
......
......@@ -270,42 +270,10 @@ void HTMLCanvasElement::IdentifiabilityReportWithDigest(
IdentifiableToken canvas_contents_token) const {
if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
blink::IdentifiableSurface::Type::kCanvasReadback)) {
const uint64_t context_digest =
context_ ? context_->IdentifiableTextToken().ToUkmMetricValue() : 0;
const IdentifiabilityPaintOpDigest* const identifiability_paintop_digest =
ResourceProvider()
? &(ResourceProvider()->GetIdentifiablityPaintOpDigest())
: nullptr;
const uint64_t canvas_digest =
identifiability_paintop_digest
? identifiability_paintop_digest->GetToken().ToUkmMetricValue()
: 0;
const uint64_t context_type =
context_ ? context_->GetContextType()
: CanvasRenderingContext::kContextTypeUnknown;
const bool encountered_skipped_ops =
(context_ && context_->IdentifiabilityEncounteredSkippedOps()) ||
(identifiability_paintop_digest &&
identifiability_paintop_digest->encountered_skipped_ops());
const bool encountered_sensitive_ops =
context_ && context_->IdentifiabilityEncounteredSensitiveOps();
const bool encountered_partially_digested_image =
identifiability_paintop_digest &&
identifiability_paintop_digest->encountered_partially_digested_image();
// Bits [0-3] are the context type, bits [4-6] are skipped ops, sensitive
// ops, and partial image ops bits, respectively. The remaining bits are
// for the canvas digest.
uint64_t final_digest =
((context_digest ^ canvas_digest) << 7) | context_type;
if (encountered_skipped_ops)
final_digest |= IdentifiableSurface::CanvasTaintBit::kSkipped;
if (encountered_sensitive_ops)
final_digest |= IdentifiableSurface::CanvasTaintBit::kSensitive;
if (encountered_partially_digested_image)
final_digest |= IdentifiableSurface::CanvasTaintBit::kPartiallyDigested;
RecordIdentifiabilityMetric(
blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::kCanvasReadback, final_digest),
blink::IdentifiableSurface::Type::kCanvasReadback,
IdentifiabilityInputDigest(context_)),
canvas_contents_token.ToUkmMetricValue());
}
}
......@@ -432,7 +400,7 @@ ScriptPromise HTMLCanvasElement::convertToBlob(
const ImageEncodeOptions* options,
ExceptionState& exception_state) {
return CanvasRenderingContextHost::convertToBlob(script_state, options,
exception_state);
exception_state, context_);
}
bool HTMLCanvasElement::ShouldBeDirectComposited() const {
......@@ -1068,13 +1036,13 @@ void HTMLCanvasElement::toBlob(V8BlobCallback* callback,
image_bitmap, options,
CanvasAsyncBlobCreator::kHTMLCanvasToBlobCallback, callback, start_time,
GetExecutionContext(),
UkmParameters{GetDocument().UkmRecorder(),
GetDocument().UkmSourceID()});
UkmParameters{GetDocument().UkmRecorder(), GetDocument().UkmSourceID()},
IdentifiabilityStudySettings::Get()->IsTypeAllowed(
IdentifiableSurface::Type::kCanvasReadback)
? IdentifiabilityInputDigest(context_)
: 0);
}
// TODO(crbug.com/973801): Report real digest for toBlob().
IdentifiabilityReportWithDigest(IdentifiableToken(0));
if (async_creator) {
async_creator->ScheduleAsyncBlobCreation(quality);
} else {
......
......@@ -292,7 +292,7 @@ class CORE_EXPORT HTMLCanvasElement final
ScriptPromise convertToBlob(ScriptState*,
const ImageEncodeOptions*,
ExceptionState&) override;
ExceptionState&);
bool NeedsUnbufferedInputEvents() const { return needs_unbuffered_input_; }
......
......@@ -179,6 +179,13 @@ void OffscreenCanvas::SetSize(const IntSize& size) {
}
}
ScriptPromise OffscreenCanvas::convertToBlob(ScriptState* script_state,
const ImageEncodeOptions* options,
ExceptionState& exception_state) {
return CanvasRenderingContextHost::convertToBlob(script_state, options,
exception_state, context_);
}
void OffscreenCanvas::RecordTransfer() {
UMA_HISTOGRAM_BOOLEAN("Blink.OffscreenCanvas.Transferred", true);
}
......
......@@ -69,6 +69,10 @@ class CORE_EXPORT OffscreenCanvas final
// API Methods
ImageBitmap* transferToImageBitmap(ScriptState*, ExceptionState&);
ScriptPromise convertToBlob(ScriptState* script_state,
const ImageEncodeOptions* options,
ExceptionState& exception_state);
const IntSize& Size() const override { return size_; }
void SetSize(const IntSize&);
void RecordTransfer();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment