Chromium Code Reviews| 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 58af50fe0faec277b63645d9c0f4022c0d274dc5..88ed5afaebefdc30ad5f3e93c854f07f8234f343 100644 |
| --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
| +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp |
| @@ -86,7 +86,12 @@ CanvasAsyncBlobCreator::MimeType convertMimeTypeStringToEnum( |
| } |
| void recordIdleTaskStatusHistogram( |
| + CanvasAsyncBlobCreator::ToBlobFunctionType functionType, |
| CanvasAsyncBlobCreator::IdleTaskStatus status) { |
| + // TODO: Add histograms for OffscreenCanvas.convertToBlob. |
| + // See crbug.com/653599. |
| + if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) |
| + return; |
| DEFINE_STATIC_LOCAL(EnumerationHistogram, toBlobIdleTaskStatus, |
| ("Blink.Canvas.ToBlob.IdleTaskStatus", |
| CanvasAsyncBlobCreator::IdleTaskCount)); |
| @@ -102,9 +107,16 @@ enum ElapsedTimeHistogramType { |
| NumberOfElapsedTimeHistogramTypes |
| }; |
| -void recordElapsedTimeHistogram(ElapsedTimeHistogramType type, |
| - CanvasAsyncBlobCreator::MimeType mimeType, |
| - double elapsedTime) { |
| +void recordElapsedTimeHistogram( |
| + CanvasAsyncBlobCreator::ToBlobFunctionType functionType, |
| + ElapsedTimeHistogramType type, |
| + CanvasAsyncBlobCreator::MimeType mimeType, |
| + double elapsedTime) { |
| + // TODO: Add histograms for OffscreenCanvas.convertToBlob. |
| + // See crbug.com/653599. |
| + if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) |
| + return; |
| + |
| if (type == InitiateEncodingDelay) { |
| if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { |
| DEFINE_STATIC_LOCAL( |
| @@ -156,10 +168,11 @@ CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create( |
| const IntSize& size, |
| BlobCallback* callback, |
| double startTime, |
| - Document& document) { |
| + Document* document, |
| + ScriptPromiseResolver* resolver) { |
| return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, |
| convertMimeTypeStringToEnum(mimeType), size, |
| - callback, startTime, document); |
| + callback, startTime, document, resolver); |
| } |
| CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, |
| @@ -167,21 +180,29 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, |
| const IntSize& size, |
| BlobCallback* callback, |
| double startTime, |
| - Document& document) |
| + Document* document, |
| + ScriptPromiseResolver* resolver) |
| : m_data(data), |
| - m_document(&document), |
| + m_document(document), |
| m_size(size), |
| m_mimeType(mimeType), |
| - m_callback(callback), |
| m_startTime(startTime), |
| m_elapsedTime(0), |
| - m_parentFrameTaskRunner( |
| - ParentFrameTaskRunners::create(document.frame())) { |
| - ASSERT(m_data->length() == (unsigned)(size.height() * size.width() * 4)); |
| + m_callback(callback), |
| + m_scriptPromiseResolver(resolver) { |
| + DCHECK(m_data->length() == (unsigned)(size.height() * size.width() * 4)); |
| m_encodedImage = wrapUnique(new Vector<unsigned char>()); |
| m_pixelRowStride = size.width() * NumChannelsPng; |
| m_idleTaskStatus = IdleTaskNotSupported; |
| m_numRowsCompleted = 0; |
| + if (document) { |
| + m_parentFrameTaskRunner = ParentFrameTaskRunners::create(document->frame()); |
| + } |
| + if (m_scriptPromiseResolver) { |
| + m_functionType = OffscreenCanvasToBlobPromise; |
| + } else { |
| + m_functionType = HTMLCanvasToBlobCallback; |
| + } |
| } |
| CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() {} |
| @@ -194,12 +215,41 @@ void CanvasAsyncBlobCreator::dispose() { |
| m_callback.clear(); |
| } |
| -void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation( |
| - bool canUseIdlePeriodScheduling, |
| - const double& quality) { |
| - ASSERT(isMainThread()); |
|
xlai (Olivia)
2016/10/19 18:51:06
All these assertion of isMainThread() need to be r
|
| +void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(const double& quality) { |
| + if (m_mimeType == MimeTypeWebp) { |
| + if (!isMainThread()) { |
| + DCHECK(m_functionType == OffscreenCanvasToBlobPromise); |
| + // 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(m_size, m_data->data()) |
| + .encodeImage("image/webp", quality, m_encodedImage.get())) { |
| + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| + ->postTask( |
| + BLINK_FROM_HERE, |
| + WTF::bind(&CanvasAsyncBlobCreator::createNullAndInvokeCallback, |
| + wrapPersistent(this))); |
| - if (canUseIdlePeriodScheduling) { |
| + return; |
| + } |
| + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| + ->postTask( |
| + BLINK_FROM_HERE, |
| + WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, |
| + wrapPersistent(this))); |
| + |
| + } else { |
| + BackgroundTaskRunner::TaskSize taskSize = |
| + (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) |
| + ? BackgroundTaskRunner::TaskSizeLongRunningTask |
| + : BackgroundTaskRunner::TaskSizeShortRunningTask; |
| + BackgroundTaskRunner::postOnBackgroundThread( |
| + BLINK_FROM_HERE, |
| + crossThreadBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, |
| + wrapCrossThreadPersistent(this), quality), |
| + taskSize); |
| + } |
| + } else { |
| m_idleTaskStatus = IdleTaskNotStarted; |
| if (m_mimeType == MimeTypePng) { |
| this->scheduleInitiatePngEncoding(); |
| @@ -211,47 +261,41 @@ void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation( |
| // formats. |
| // TODO(xlai): Progressive encoding on webp image formats |
| // (crbug.com/571399) |
| - ASSERT_NOT_REACHED(); |
| + NOTREACHED(); |
| + } |
| + |
| + // TODO: Enforce OffscreenCanvas.convertToBlob to finish within deadline. |
| + // See crbug.com/657102. |
| + if (m_functionType == HTMLCanvasToBlobCallback) { |
| + // 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 main thread. |
| + this->postDelayedTaskToMainThread( |
| + BLINK_FROM_HERE, |
| + WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, |
| + wrapPersistent(this), quality), |
| + IdleTaskStartTimeoutDelay); |
| } |
| - // 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 main thread. |
| - this->postDelayedTaskToMainThread( |
| - BLINK_FROM_HERE, |
| - WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, |
| - wrapPersistent(this), quality), |
| - IdleTaskStartTimeoutDelay); |
| - } else if (m_mimeType == MimeTypeWebp) { |
| - BackgroundTaskRunner::TaskSize taskSize = |
| - (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) |
| - ? BackgroundTaskRunner::TaskSizeLongRunningTask |
| - : BackgroundTaskRunner::TaskSizeShortRunningTask; |
| - BackgroundTaskRunner::postOnBackgroundThread( |
| - BLINK_FROM_HERE, |
| - crossThreadBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, |
| - wrapCrossThreadPersistent(this), quality), |
| - taskSize); |
| } |
| } |
| void CanvasAsyncBlobCreator::scheduleInitiateJpegEncoding( |
| const double& quality) { |
| m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); |
| - Platform::current()->mainThread()->scheduler()->postIdleTask( |
| + Platform::current()->currentThread()->scheduler()->postIdleTask( |
| BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, |
| wrapPersistent(this), quality)); |
| } |
| void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality, |
| double deadlineSeconds) { |
| - ASSERT(isMainThread()); |
| recordElapsedTimeHistogram( |
| - InitiateEncodingDelay, MimeTypeJpeg, |
| + m_functionType, InitiateEncodingDelay, MimeTypeJpeg, |
| WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); |
| if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| return; |
| } |
| - ASSERT(m_idleTaskStatus == IdleTaskNotStarted); |
| + DCHECK(m_idleTaskStatus == IdleTaskNotStarted); |
| m_idleTaskStatus = IdleTaskStarted; |
| if (!initializeJpegStruct(quality)) { |
| @@ -263,22 +307,20 @@ void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality, |
| void CanvasAsyncBlobCreator::scheduleInitiatePngEncoding() { |
| m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); |
| - Platform::current()->mainThread()->scheduler()->postIdleTask( |
| + Platform::current()->currentThread()->scheduler()->postIdleTask( |
| BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiatePngEncoding, |
| wrapPersistent(this))); |
| } |
| void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) { |
| - ASSERT(isMainThread()); |
| recordElapsedTimeHistogram( |
| - InitiateEncodingDelay, MimeTypePng, |
| + m_functionType, InitiateEncodingDelay, MimeTypePng, |
| WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); |
| - |
| if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| return; |
| } |
| - ASSERT(m_idleTaskStatus == IdleTaskNotStarted); |
| + DCHECK(m_idleTaskStatus == IdleTaskNotStarted); |
| m_idleTaskStatus = IdleTaskStarted; |
| if (!initializePngStruct()) { |
| @@ -289,7 +331,6 @@ void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) { |
| } |
| void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) { |
| - ASSERT(isMainThread()); |
| if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| return; |
| } |
| @@ -314,7 +355,8 @@ void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) { |
| m_idleTaskStatus = IdleTaskCompleted; |
| m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| - recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypePng, m_elapsedTime); |
| + recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypePng, |
| + m_elapsedTime); |
| if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| ->postTask( |
| @@ -327,9 +369,10 @@ void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) { |
| } |
| void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { |
| - ASSERT(isMainThread()); |
| - if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| - return; |
| + if (m_callback) { |
| + if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| + return; |
| + } |
| } |
| double startTime = WTF::monotonicallyIncreasingTime(); |
| @@ -339,7 +382,8 @@ void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { |
| m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| if (m_numRowsCompleted == m_size.height()) { |
| m_idleTaskStatus = IdleTaskCompleted; |
| - recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypeJpeg, m_elapsedTime); |
| + recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypeJpeg, |
| + m_elapsedTime); |
| if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| @@ -361,7 +405,7 @@ void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { |
| } |
| void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { |
| - ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| + DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| // Continue encoding from the last completed row |
| unsigned char* inputPixels = |
| @@ -377,7 +421,7 @@ void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { |
| } |
| void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { |
| - ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| + DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| // Continue encoding from the last completed row |
| if (JPEGImageEncoder::encodeWithPreInitializedState( |
| @@ -391,36 +435,45 @@ void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { |
| } |
| void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() { |
| - ASSERT(isMainThread()); |
| - recordIdleTaskStatusHistogram(m_idleTaskStatus); |
| - |
| - recordElapsedTimeHistogram(ToBlobDuration, m_mimeType, |
| + recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| + recordElapsedTimeHistogram(m_functionType, ToBlobDuration, m_mimeType, |
| WTF::monotonicallyIncreasingTime() - m_startTime); |
| + |
| Blob* resultBlob = |
| Blob::create(m_encodedImage->data(), m_encodedImage->size(), |
| convertMimeTypeEnumToString(m_mimeType)); |
| - TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| - ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, |
| - wrapPersistent(m_callback.get()), |
| - wrapPersistent(resultBlob))); |
| + if (m_functionType == HTMLCanvasToBlobCallback) { |
| + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| + ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, |
| + wrapPersistent(m_callback.get()), |
| + wrapPersistent(resultBlob))); |
| + } else { |
| + m_scriptPromiseResolver->resolve(resultBlob); |
| + } |
| // Avoid unwanted retention, see dispose(). |
| dispose(); |
| } |
| void CanvasAsyncBlobCreator::createNullAndInvokeCallback() { |
| - ASSERT(isMainThread()); |
| - recordIdleTaskStatusHistogram(m_idleTaskStatus); |
| - TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| - ->postTask(BLINK_FROM_HERE, |
| - WTF::bind(&BlobCallback::handleEvent, |
| - wrapPersistent(m_callback.get()), nullptr)); |
| + recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| + if (m_functionType == HTMLCanvasToBlobCallback) { |
| + DCHECK(isMainThread()); |
| + recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| + ->postTask(BLINK_FROM_HERE, |
| + WTF::bind(&BlobCallback::handleEvent, |
| + wrapPersistent(m_callback.get()), nullptr)); |
| + } else { |
| + Blob* blob = nullptr; |
| + m_scriptPromiseResolver->reject(blob); |
| + } |
| // Avoid unwanted retention, see dispose(). |
| dispose(); |
| } |
| void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { |
| - ASSERT(!isMainThread()); |
| - ASSERT(m_mimeType == MimeTypeWebp); |
| + DCHECK(!isMainThread()); |
| + DCHECK(m_mimeType == MimeTypeWebp); |
| if (!ImageDataBuffer(m_size, m_data->data()) |
| .encodeImage("image/webp", quality, m_encodedImage.get())) { |
| @@ -486,7 +539,7 @@ void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) { |
| this->signalAlternativeCodePathFinishedForTesting(); |
| } |
| } else { |
| - ASSERT(m_mimeType == MimeTypeJpeg); |
| + DCHECK(m_mimeType == MimeTypeJpeg); |
| if (initializeJpegStruct(quality)) { |
| TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| ->postTask( |
| @@ -499,14 +552,14 @@ void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) { |
| } |
| } |
| } else { |
| - ASSERT(m_idleTaskStatus == IdleTaskFailed || |
| + DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| m_idleTaskStatus == IdleTaskCompleted); |
| this->signalAlternativeCodePathFinishedForTesting(); |
| } |
| } |
| void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { |
| - ASSERT(m_idleTaskStatus != IdleTaskNotStarted); |
| + DCHECK(m_idleTaskStatus != IdleTaskNotStarted); |
| if (m_idleTaskStatus == IdleTaskStarted) { |
| // It has taken too long to complete for the idle task. |
| @@ -520,7 +573,7 @@ void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { |
| WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, |
| wrapPersistent(this))); |
| } else { |
| - ASSERT(m_mimeType == MimeTypeJpeg); |
| + DCHECK(m_mimeType == MimeTypeJpeg); |
| TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| ->postTask( |
| BLINK_FROM_HERE, |
| @@ -528,7 +581,7 @@ void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { |
| wrapPersistent(this))); |
| } |
| } else { |
| - ASSERT(m_idleTaskStatus == IdleTaskFailed || |
| + DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| m_idleTaskStatus == IdleTaskCompleted); |
| this->signalAlternativeCodePathFinishedForTesting(); |
| } |
| @@ -548,6 +601,7 @@ DEFINE_TRACE(CanvasAsyncBlobCreator) { |
| visitor->trace(m_data); |
| visitor->trace(m_callback); |
| visitor->trace(m_parentFrameTaskRunner); |
| + visitor->trace(m_scriptPromiseResolver); |
| } |
| } // namespace blink |