Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Unified Diff: third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp

Issue 2878333004: Use SkJpegEncoder in WebKit platform (Closed)
Patch Set: Create instead of Make Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..2426d280ba0f46cff612e2834d89d143af2d922e 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::Create(&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::Create(&encoded_image_, src_data_, options);
}
- 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();
}
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);

Powered by Google App Engine
This is Rietveld 408576698