Index: third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
index 0250b7938a27d7e4410ff773c317a84ef56ab812..22582621462a481ab8dcc74c20573b79ee7cfa47 100644 |
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
@@ -12,8 +12,6 @@ |
#include "platform/Histogram.h" |
#include "platform/WebTaskRunner.h" |
#include "platform/graphics/ImageBuffer.h" |
-#include "platform/image-encoders/JPEGImageEncoder.h" |
-#include "platform/image-encoders/PNGImageEncoder.h" |
#include "platform/scheduler/child/web_scheduler.h" |
#include "platform/threading/BackgroundTaskRunner.h" |
#include "platform/wtf/CurrentTime.h" |
@@ -29,7 +27,6 @@ namespace { |
const double kSlackBeforeDeadline = |
0.001; // a small slack period between deadline and current time for safety |
-const int kNumChannelsPng = 4; |
// The encoding task is highly likely to switch from idle task to alternative |
// code path when the startTimeoutDelay is set to be below 150ms. As we want the |
@@ -191,15 +188,17 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, |
ScriptPromiseResolver* resolver) |
: data_(data), |
document_(document), |
- size_(size), |
mime_type_(mime_type), |
start_time_(start_time), |
elapsed_time_(0), |
callback_(callback), |
script_promise_resolver_(resolver) { |
- DCHECK(data_->length() == (unsigned)(size.Height() * size.Width() * 4)); |
- encoded_image_ = WTF::WrapUnique(new Vector<unsigned char>()); |
- pixel_row_stride_ = size.Width() * kNumChannelsPng; |
+ size_t rowBytes = size.Width() * 4; |
+ DCHECK(data_->length() == (unsigned)(size.Height() * rowBytes)); |
+ SkImageInfo info = |
+ SkImageInfo::Make(size.Width(), size.Height(), kRGBA_8888_SkColorType, |
+ kUnpremul_SkAlphaType, nullptr); |
+ src_data_.reset(info, data_->Data(), rowBytes); |
idle_task_status_ = kIdleTaskNotSupported; |
num_rows_completed_ = 0; |
if (document) { |
@@ -232,8 +231,9 @@ void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) { |
// When OffscreenCanvas.convertToBlob() occurs on worker thread, |
// we do not need to use background task runner to reduce load on main. |
// So we just directly encode images on the worker thread. |
- if (!ImageDataBuffer(size_, data_->Data()) |
- .EncodeImage("image/webp", quality, encoded_image_.get())) { |
+ IntSize size(src_data_.width(), src_data_.height()); |
+ if (!ImageDataBuffer(size, data_->Data()) |
+ .EncodeImage("image/webp", quality, &encoded_image_)) { |
TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
->PostTask( |
BLINK_FROM_HERE, |
@@ -256,18 +256,7 @@ void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) { |
} |
} else { |
idle_task_status_ = kIdleTaskNotStarted; |
- if (mime_type_ == kMimeTypePng) { |
- this->ScheduleInitiatePngEncoding(); |
- } else if (mime_type_ == kMimeTypeJpeg) { |
- this->ScheduleInitiateJpegEncoding(quality); |
- } else { |
- // Progressive encoding is only applicable to png and jpeg image format, |
- // and thus idle tasks scheduling can only be applied to these image |
- // formats. |
- // TODO(xlai): Progressive encoding on webp image formats |
- // (crbug.com/571399) |
- NOTREACHED(); |
- } |
+ this->ScheduleInitiateEncoding(quality); |
// We post the below task to check if the above idle task isn't late. |
// There's no risk of concurrency as both tasks are on the same thread. |
@@ -279,18 +268,17 @@ void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) { |
} |
} |
-void CanvasAsyncBlobCreator::ScheduleInitiateJpegEncoding( |
- const double& quality) { |
+void CanvasAsyncBlobCreator::ScheduleInitiateEncoding(double quality) { |
schedule_initiate_start_time_ = WTF::MonotonicallyIncreasingTime(); |
Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask( |
- BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::InitiateJpegEncoding, |
+ BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::InitiateEncoding, |
WrapPersistent(this), quality)); |
} |
-void CanvasAsyncBlobCreator::InitiateJpegEncoding(const double& quality, |
- double deadline_seconds) { |
+void CanvasAsyncBlobCreator::InitiateEncoding(double quality, |
+ double deadline_seconds) { |
RecordElapsedTimeHistogram( |
- kInitiateEncodingDelay, kMimeTypeJpeg, |
+ kInitiateEncodingDelay, mime_type_, |
WTF::MonotonicallyIncreasingTime() - schedule_initiate_start_time_); |
if (idle_task_status_ == kIdleTaskSwitchedToImmediateTask) { |
return; |
@@ -299,64 +287,41 @@ void CanvasAsyncBlobCreator::InitiateJpegEncoding(const double& quality, |
DCHECK(idle_task_status_ == kIdleTaskNotStarted); |
idle_task_status_ = kIdleTaskStarted; |
- if (!InitializeJpegStruct(quality)) { |
+ if (!InitializeEncoder(quality)) { |
idle_task_status_ = kIdleTaskFailed; |
return; |
} |
- this->IdleEncodeRowsJpeg(deadline_seconds); |
-} |
- |
-void CanvasAsyncBlobCreator::ScheduleInitiatePngEncoding() { |
- schedule_initiate_start_time_ = WTF::MonotonicallyIncreasingTime(); |
- Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask( |
- BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::InitiatePngEncoding, |
- WrapPersistent(this))); |
-} |
- |
-void CanvasAsyncBlobCreator::InitiatePngEncoding(double deadline_seconds) { |
- RecordElapsedTimeHistogram( |
- kInitiateEncodingDelay, kMimeTypePng, |
- WTF::MonotonicallyIncreasingTime() - schedule_initiate_start_time_); |
- if (idle_task_status_ == kIdleTaskSwitchedToImmediateTask) { |
- return; |
- } |
- |
- DCHECK(idle_task_status_ == kIdleTaskNotStarted); |
- idle_task_status_ = kIdleTaskStarted; |
- if (!InitializePngStruct()) { |
- idle_task_status_ = kIdleTaskFailed; |
- return; |
- } |
- this->IdleEncodeRowsPng(deadline_seconds); |
+ this->IdleEncodeRows(deadline_seconds); |
} |
-void CanvasAsyncBlobCreator::IdleEncodeRowsPng(double deadline_seconds) { |
+void CanvasAsyncBlobCreator::IdleEncodeRows(double deadline_seconds) { |
if (idle_task_status_ == kIdleTaskSwitchedToImmediateTask) { |
return; |
} |
double start_time = WTF::MonotonicallyIncreasingTime(); |
- unsigned char* input_pixels = |
- data_->Data() + pixel_row_stride_ * num_rows_completed_; |
- for (int y = num_rows_completed_; y < size_.Height(); ++y) { |
+ for (int y = num_rows_completed_; y < src_data_.height(); ++y) { |
if (IsDeadlineNearOrPassed(deadline_seconds)) { |
num_rows_completed_ = y; |
elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time); |
Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask( |
- BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRowsPng, |
+ BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRows, |
WrapPersistent(this))); |
return; |
} |
- PNGImageEncoder::WriteOneRowToPng(input_pixels, png_encoder_state_.get()); |
- input_pixels += pixel_row_stride_; |
+ |
+ if (!encoder_->encodeRows(1)) { |
+ idle_task_status_ = kIdleTaskFailed; |
+ this->CreateNullAndReturnResult(); |
+ return; |
+ } |
} |
- num_rows_completed_ = size_.Height(); |
- PNGImageEncoder::FinalizePng(png_encoder_state_.get()); |
+ num_rows_completed_ = src_data_.height(); |
idle_task_status_ = kIdleTaskCompleted; |
elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time); |
- RecordElapsedTimeHistogram(kIdleEncodeDuration, kMimeTypePng, elapsed_time_); |
+ RecordElapsedTimeHistogram(kIdleEncodeDuration, mime_type_, elapsed_time_); |
if (IsDeadlineNearOrPassed(deadline_seconds)) { |
TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
->PostTask(BLINK_FROM_HERE, |
@@ -367,52 +332,18 @@ void CanvasAsyncBlobCreator::IdleEncodeRowsPng(double deadline_seconds) { |
} |
} |
-void CanvasAsyncBlobCreator::IdleEncodeRowsJpeg(double deadline_seconds) { |
- if (idle_task_status_ == kIdleTaskSwitchedToImmediateTask) { |
- return; |
- } |
- |
- double start_time = WTF::MonotonicallyIncreasingTime(); |
- num_rows_completed_ = JPEGImageEncoder::ProgressiveEncodeRowsJpegHelper( |
- jpeg_encoder_state_.get(), data_->Data(), num_rows_completed_, |
- kSlackBeforeDeadline, deadline_seconds); |
- elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time); |
- if (num_rows_completed_ == size_.Height()) { |
- idle_task_status_ = kIdleTaskCompleted; |
- RecordElapsedTimeHistogram(kIdleEncodeDuration, kMimeTypeJpeg, |
- elapsed_time_); |
- |
- if (IsDeadlineNearOrPassed(deadline_seconds)) { |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask( |
- BLINK_FROM_HERE, |
- WTF::Bind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult, |
- WrapPersistent(this))); |
- } else { |
- this->CreateBlobAndReturnResult(); |
- } |
- } else if (num_rows_completed_ == |
- JPEGImageEncoder::kProgressiveEncodeFailed) { |
- idle_task_status_ = kIdleTaskFailed; |
- this->CreateNullAndReturnResult(); |
- } else { |
- Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask( |
- BLINK_FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRowsJpeg, |
- WrapPersistent(this))); |
- } |
-} |
- |
-void CanvasAsyncBlobCreator::ForceEncodeRowsPngOnCurrentThread() { |
+void CanvasAsyncBlobCreator::ForceEncodeRowsOnCurrentThread() { |
DCHECK(idle_task_status_ == kIdleTaskSwitchedToImmediateTask); |
// Continue encoding from the last completed row |
- unsigned char* input_pixels = |
- data_->Data() + pixel_row_stride_ * num_rows_completed_; |
- for (int y = num_rows_completed_; y < size_.Height(); ++y) { |
- PNGImageEncoder::WriteOneRowToPng(input_pixels, png_encoder_state_.get()); |
- input_pixels += pixel_row_stride_; |
+ for (int y = num_rows_completed_; y < src_data_.height(); ++y) { |
+ if (!encoder_->encodeRows(1)) { |
+ idle_task_status_ = kIdleTaskFailed; |
+ this->CreateNullAndReturnResult(); |
+ return; |
+ } |
} |
- PNGImageEncoder::FinalizePng(png_encoder_state_.get()); |
+ num_rows_completed_ = src_data_.height(); |
if (IsMainThread()) { |
this->CreateBlobAndReturnResult(); |
@@ -427,38 +358,13 @@ void CanvasAsyncBlobCreator::ForceEncodeRowsPngOnCurrentThread() { |
this->SignalAlternativeCodePathFinishedForTesting(); |
} |
-void CanvasAsyncBlobCreator::ForceEncodeRowsJpegOnCurrentThread() { |
- DCHECK(idle_task_status_ == kIdleTaskSwitchedToImmediateTask); |
- |
- // Continue encoding from the last completed row |
- void (CanvasAsyncBlobCreator::*function_to_be_called)(void); |
- if (JPEGImageEncoder::EncodeWithPreInitializedState( |
- std::move(jpeg_encoder_state_), data_->Data(), num_rows_completed_)) { |
- function_to_be_called = &CanvasAsyncBlobCreator::CreateBlobAndReturnResult; |
- } else { |
- function_to_be_called = &CanvasAsyncBlobCreator::CreateNullAndReturnResult; |
- } |
- |
- if (IsMainThread()) { |
- (this->*function_to_be_called)(); |
- } else { |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask(BLINK_FROM_HERE, |
- CrossThreadBind(function_to_be_called, |
- WrapCrossThreadPersistent(this))); |
- } |
- |
- this->SignalAlternativeCodePathFinishedForTesting(); |
-} |
- |
void CanvasAsyncBlobCreator::CreateBlobAndReturnResult() { |
RecordIdleTaskStatusHistogram(idle_task_status_); |
RecordElapsedTimeHistogram(kToBlobDuration, mime_type_, |
WTF::MonotonicallyIncreasingTime() - start_time_); |
- Blob* result_blob = |
- Blob::Create(encoded_image_->data(), encoded_image_->size(), |
- ConvertMimeTypeEnumToString(mime_type_)); |
+ Blob* result_blob = Blob::Create(encoded_image_.data(), encoded_image_.size(), |
+ ConvertMimeTypeEnumToString(mime_type_)); |
if (function_type_ == kHTMLCanvasToBlobCallback) { |
TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
->PostTask(BLINK_FROM_HERE, WTF::Bind(&BlobCallback::handleEvent, |
@@ -492,8 +398,9 @@ void CanvasAsyncBlobCreator::EncodeImageOnEncoderThread(double quality) { |
DCHECK(!IsMainThread()); |
DCHECK(mime_type_ == kMimeTypeWebp); |
- if (!ImageDataBuffer(size_, data_->Data()) |
- .EncodeImage("image/webp", quality, encoded_image_.get())) { |
+ IntSize size(src_data_.width(), src_data_.height()); |
+ if (!ImageDataBuffer(size, data_->Data()) |
+ .EncodeImage("image/webp", quality, &encoded_image_)) { |
parent_frame_task_runner_->Get(TaskType::kCanvasBlobSerialization) |
->PostTask( |
BLINK_FROM_HERE, |
@@ -509,24 +416,31 @@ void CanvasAsyncBlobCreator::EncodeImageOnEncoderThread(double quality) { |
WrapCrossThreadPersistent(this))); |
} |
-bool CanvasAsyncBlobCreator::InitializePngStruct() { |
- png_encoder_state_ = |
- PNGImageEncoderState::Create(size_, encoded_image_.get()); |
- if (!png_encoder_state_) { |
- this->CreateNullAndReturnResult(); |
- return false; |
+bool CanvasAsyncBlobCreator::InitializeEncoder(double quality) { |
+ if (mime_type_ == kMimeTypeJpeg) { |
+ SkJpegEncoder::Options options; |
+ options.fQuality = ImageEncoder::ComputeJpegQuality(quality); |
+ options.fAlphaOption = SkJpegEncoder::AlphaOption::kBlendOnBlack; |
+ options.fBlendBehavior = SkTransferFunctionBehavior::kIgnore; |
+ if (options.fQuality == 100) { |
+ options.fDownsample = SkJpegEncoder::Downsample::k444; |
+ } |
+ encoder_ = ImageEncoder::Make(&encoded_image_, src_data_, options); |
+ } else { |
+ // Progressive encoding is only applicable to png and jpeg image format, |
+ // and thus idle tasks scheduling can only be applied to these image |
+ // formats. |
+ // TODO(xlai): Progressive encoding on webp image formats |
+ // (crbug.com/571399) |
+ DCHECK_EQ(kMimeTypePng, mime_type_); |
+ SkPngEncoder::Options options; |
+ options.fFilterFlags = SkPngEncoder::FilterFlag::kSub; |
+ options.fZLibLevel = 3; |
+ options.fUnpremulBehavior = SkTransferFunctionBehavior::kIgnore; |
+ encoder_ = ImageEncoder::Make(&encoded_image_, src_data_, options); |
f(malita)
2017/05/16 21:09:45
We can pull this out of both blocks, looks identic
msarett1
2017/05/17 02:26:59
Unfortunately I can't. One takes SkJpegEncoder::O
|
} |
- return true; |
-} |
-bool CanvasAsyncBlobCreator::InitializeJpegStruct(double quality) { |
- jpeg_encoder_state_ = |
- JPEGImageEncoderState::Create(size_, quality, encoded_image_.get()); |
- if (!jpeg_encoder_state_) { |
- this->CreateNullAndReturnResult(); |
- return false; |
- } |
- return true; |
+ return encoder_.get(); |
f(malita)
2017/05/16 21:09:46
Is .get() required? I think uniqueptr converts to
msarett1
2017/05/17 02:26:59
I thought it did too. For some reason, removing t
|
} |
void CanvasAsyncBlobCreator::IdleTaskStartTimeoutEvent(double quality) { |
@@ -544,31 +458,16 @@ void CanvasAsyncBlobCreator::IdleTaskStartTimeoutEvent(double quality) { |
idle_task_status_ = kIdleTaskSwitchedToImmediateTask; |
SignalTaskSwitchInStartTimeoutEventForTesting(); |
- if (mime_type_ == kMimeTypePng) { |
- if (InitializePngStruct()) { |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask( |
- BLINK_FROM_HERE, |
- WTF::Bind( |
- &CanvasAsyncBlobCreator::ForceEncodeRowsPngOnCurrentThread, |
- WrapPersistent(this))); |
- } else { |
- // Failing in initialization of png struct |
- this->SignalAlternativeCodePathFinishedForTesting(); |
- } |
+ DCHECK(mime_type_ == kMimeTypePng || mime_type_ == kMimeTypeJpeg); |
+ if (InitializeEncoder(quality)) { |
+ TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
+ ->PostTask( |
+ BLINK_FROM_HERE, |
+ WTF::Bind(&CanvasAsyncBlobCreator::ForceEncodeRowsOnCurrentThread, |
+ WrapPersistent(this))); |
} else { |
- DCHECK(mime_type_ == kMimeTypeJpeg); |
- if (InitializeJpegStruct(quality)) { |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask( |
- BLINK_FROM_HERE, |
- WTF::Bind( |
- &CanvasAsyncBlobCreator::ForceEncodeRowsJpegOnCurrentThread, |
- WrapPersistent(this))); |
- } else { |
- // Failing in initialization of jpeg struct |
- this->SignalAlternativeCodePathFinishedForTesting(); |
- } |
+ // Failing in initialization of encoder |
+ this->SignalAlternativeCodePathFinishedForTesting(); |
} |
} else { |
DCHECK(idle_task_status_ == kIdleTaskFailed || |
@@ -585,22 +484,12 @@ void CanvasAsyncBlobCreator::IdleTaskCompleteTimeoutEvent() { |
idle_task_status_ = kIdleTaskSwitchedToImmediateTask; |
SignalTaskSwitchInCompleteTimeoutEventForTesting(); |
- if (mime_type_ == kMimeTypePng) { |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask( |
- BLINK_FROM_HERE, |
- WTF::Bind( |
- &CanvasAsyncBlobCreator::ForceEncodeRowsPngOnCurrentThread, |
- WrapPersistent(this))); |
- } else { |
- DCHECK(mime_type_ == kMimeTypeJpeg); |
- TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
- ->PostTask( |
- BLINK_FROM_HERE, |
- WTF::Bind( |
- &CanvasAsyncBlobCreator::ForceEncodeRowsJpegOnCurrentThread, |
- WrapPersistent(this))); |
- } |
+ DCHECK(mime_type_ == kMimeTypePng || mime_type_ == kMimeTypeJpeg); |
+ TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_) |
+ ->PostTask( |
+ BLINK_FROM_HERE, |
+ WTF::Bind(&CanvasAsyncBlobCreator::ForceEncodeRowsOnCurrentThread, |
+ WrapPersistent(this))); |
} else { |
DCHECK(idle_task_status_ == kIdleTaskFailed || |
idle_task_status_ == kIdleTaskCompleted); |