| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "CanvasAsyncBlobCreator.h" | 5 #include "core/html/canvas/CanvasAsyncBlobCreator.h" |
| 6 | 6 |
| 7 #include "core/fileapi/Blob.h" | 7 #include "core/fileapi/Blob.h" |
| 8 #include "platform/ThreadSafeFunctional.h" | 8 #include "platform/ThreadSafeFunctional.h" |
| 9 #include "platform/graphics/ImageBuffer.h" | 9 #include "platform/graphics/ImageBuffer.h" |
| 10 #include "platform/heap/Handle.h" | |
| 11 #include "platform/image-encoders/skia/JPEGImageEncoder.h" | 10 #include "platform/image-encoders/skia/JPEGImageEncoder.h" |
| 12 #include "platform/image-encoders/skia/PNGImageEncoder.h" | 11 #include "platform/image-encoders/skia/PNGImageEncoder.h" |
| 13 #include "platform/threading/BackgroundTaskRunner.h" | 12 #include "platform/threading/BackgroundTaskRunner.h" |
| 14 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" |
| 15 #include "public/platform/WebScheduler.h" | 14 #include "public/platform/WebScheduler.h" |
| 16 #include "public/platform/WebTaskRunner.h" | 15 #include "public/platform/WebTaskRunner.h" |
| 17 #include "public/platform/WebThread.h" | 16 #include "public/platform/WebThread.h" |
| 18 #include "public/platform/WebTraceLocation.h" | 17 #include "public/platform/WebTraceLocation.h" |
| 19 #include "wtf/CurrentTime.h" | 18 #include "wtf/CurrentTime.h" |
| 20 #include "wtf/Functional.h" | 19 #include "wtf/Functional.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 | 52 |
| 54 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() | 53 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() |
| 55 { | 54 { |
| 56 } | 55 } |
| 57 | 56 |
| 58 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) | 57 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) |
| 59 { | 58 { |
| 60 // TODO: async blob creation should be supported in worker_pool threads as w
ell. but right now blink does not have that | 59 // TODO: async blob creation should be supported in worker_pool threads as w
ell. but right now blink does not have that |
| 61 ASSERT(isMainThread()); | 60 ASSERT(isMainThread()); |
| 62 | 61 |
| 63 // Make self-reference to keep this object alive until the final task comple
tes | |
| 64 m_keepAlive = this; | |
| 65 | |
| 66 // At the time being, progressive encoding is only applicable to png image f
ormat, | 62 // At the time being, progressive encoding is only applicable to png image f
ormat, |
| 67 // and thus idle tasks scheduling can only be applied to png image format. | 63 // and thus idle tasks scheduling can only be applied to png image format. |
| 68 // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.co
m/571398, crbug.com/571399) | 64 // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.co
m/571398, crbug.com/571399) |
| 69 if (canUseIdlePeriodScheduling) { | 65 if (canUseIdlePeriodScheduling) { |
| 70 ASSERT(m_mimeType == "image/png"); | 66 ASSERT(m_mimeType == "image/png"); |
| 71 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); | 67 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); |
| 72 } else if (m_mimeType == "image/jpeg") { | 68 } else if (m_mimeType == "image/jpeg") { |
| 73 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); | 69 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); |
| 74 } else { | 70 } else { |
| 75 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt
h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa
sk : BackgroundTaskRunner::TaskSizeShortRunningTask; | 71 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt
h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa
sk : BackgroundTaskRunner::TaskSizeShortRunningTask; |
| 76 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe
Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess
(this), quality), taskSize); | 72 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe
Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess
(this), quality), taskSize); |
| 77 } | 73 } |
| 78 } | 74 } |
| 79 | 75 |
| 80 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) | 76 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) |
| 81 { | 77 { |
| 82 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); | 78 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); |
| 83 if (!m_jpegEncoderState) { | 79 if (!m_jpegEncoderState) { |
| 84 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 80 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
| 85 m_keepAlive.clear(); | |
| 86 return; | 81 return; |
| 87 } | 82 } |
| 88 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width()
>= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask :
BackgroundTaskRunner::TaskSizeShortRunningTask; | 83 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width()
>= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask :
BackgroundTaskRunner::TaskSizeShortRunningTask; |
| 89 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind
(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(thi
s), quality), taskSize); | 84 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind
(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(thi
s), quality), taskSize); |
| 90 } | 85 } |
| 91 | 86 |
| 92 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) | 87 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) |
| 93 { | 88 { |
| 94 ASSERT(isMainThread()); | 89 ASSERT(isMainThread()); |
| 95 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); | 90 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); |
| 96 if (!m_pngEncoderState) { | 91 if (!m_pngEncoderState) { |
| 97 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 92 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
| 98 m_keepAlive.clear(); | |
| 99 return; | 93 return; |
| 100 } | 94 } |
| 101 | 95 |
| 102 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); | 96 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); |
| 103 } | 97 } |
| 104 | 98 |
| 105 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() | 99 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() |
| 106 { | 100 { |
| 107 ASSERT(isMainThread()); | 101 ASSERT(isMainThread()); |
| 108 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); | 102 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); |
| 109 } | 103 } |
| 110 | 104 |
| 111 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) | 105 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) |
| 112 { | 106 { |
| 113 ASSERT(isMainThread()); | 107 ASSERT(isMainThread()); |
| 114 unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCo
mpleted; | 108 unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCo
mpleted; |
| 115 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { | 109 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { |
| 116 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 110 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| 117 m_numRowsCompleted = y; | 111 m_numRowsCompleted = y; |
| 118 CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng(); | 112 CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng(); |
| 119 return; | 113 return; |
| 120 } | 114 } |
| 121 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); | 115 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); |
| 122 inputPixels += m_pixelRowStride; | 116 inputPixels += m_pixelRowStride; |
| 123 } | 117 } |
| 124 m_numRowsCompleted = m_size.height(); | 118 m_numRowsCompleted = m_size.height(); |
| 125 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); | 119 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); |
| 126 | 120 |
| 127 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 121 if (isDeadlineNearOrPassed(deadlineSeconds)) |
| 128 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::createBlobAndCall, this)); | 122 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::createBlobAndCall, this)); |
| 129 } else { | 123 else |
| 130 this->createBlobAndCall(); | 124 this->createBlobAndCall(); |
| 131 } | |
| 132 } | 125 } |
| 133 | 126 |
| 134 void CanvasAsyncBlobCreator::createBlobAndCall() | 127 void CanvasAsyncBlobCreator::createBlobAndCall() |
| 135 { | 128 { |
| 136 ASSERT(isMainThread()); | 129 ASSERT(isMainThread()); |
| 137 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size
(), m_mimeType); | 130 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size
(), m_mimeType); |
| 138 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); | 131 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); |
| 139 clearSelfReference(); // self-destruct once job is done. | |
| 140 } | 132 } |
| 141 | 133 |
| 142 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) | 134 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) |
| 143 { | 135 { |
| 144 ASSERT(!isMainThread()); | 136 ASSERT(!isMainThread()); |
| 145 | 137 |
| 146 bool success; | 138 bool success; |
| 147 if (m_mimeType == "image/jpeg") { | 139 if (m_mimeType == "image/jpeg") |
| 148 success = JPEGImageEncoder::encodeWithPreInitializedState(m_jpegEncoderS
tate.release(), m_data->data()); | 140 success = JPEGImageEncoder::encodeWithPreInitializedState(m_jpegEncoderS
tate.release(), m_data->data()); |
| 149 } else { | 141 else |
| 150 success = ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType
, quality, m_encodedImage.get()); | 142 success = ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType
, quality, m_encodedImage.get()); |
| 151 } | |
| 152 | 143 |
| 153 if (!success) { | 144 if (!success) { |
| 154 scheduleCreateNullptrAndCallOnMainThread(); | 145 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&BlobCallback::handleEvent, m_callback.get(), nullptr)); |
| 155 return; | 146 return; |
| 156 } | 147 } |
| 157 | 148 |
| 158 scheduleCreateBlobAndCallOnMainThread(); | |
| 159 } | |
| 160 | |
| 161 void CanvasAsyncBlobCreator::clearSelfReference() | |
| 162 { | |
| 163 // Some persistent members in CanvasAsyncBlobCreator can only be destroyed | |
| 164 // on the thread that creates them. In this case, it's the main thread. | |
| 165 ASSERT(isMainThread()); | |
| 166 m_keepAlive.clear(); | |
| 167 } | |
| 168 | |
| 169 void CanvasAsyncBlobCreator::scheduleCreateBlobAndCallOnMainThread() | |
| 170 { | |
| 171 ASSERT(!isMainThread()); | |
| 172 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); | 149 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); |
| 173 } | 150 } |
| 174 | 151 |
| 175 void CanvasAsyncBlobCreator::scheduleCreateNullptrAndCallOnMainThread() | |
| 176 { | |
| 177 ASSERT(!isMainThread()); | |
| 178 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&BlobCallback::handleEvent, m_callback.get(), nullptr)); | |
| 179 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThrea
dAccess(this))); | |
| 180 } | |
| 181 | |
| 182 } // namespace blink | 152 } // namespace blink |
| OLD | NEW |