Chromium Code Reviews| 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 "core/html/canvas/CanvasAsyncBlobCreator.h" | 5 #include "core/html/canvas/CanvasAsyncBlobCreator.h" |
| 6 | 6 |
| 7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
| 8 #include "core/dom/TaskRunnerHelper.h" | 8 #include "core/dom/TaskRunnerHelper.h" |
| 9 #include "core/fileapi/Blob.h" | 9 #include "core/fileapi/Blob.h" |
| 10 #include "platform/CrossThreadFunctional.h" | 10 #include "platform/CrossThreadFunctional.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeJpeg; | 79 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeJpeg; |
| 80 } else if (mimeType == "image/webp") { | 80 } else if (mimeType == "image/webp") { |
| 81 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeWebp; | 81 mimeTypeEnum = CanvasAsyncBlobCreator::MimeTypeWebp; |
| 82 } else { | 82 } else { |
| 83 mimeTypeEnum = CanvasAsyncBlobCreator::NumberOfMimeTypeSupported; | 83 mimeTypeEnum = CanvasAsyncBlobCreator::NumberOfMimeTypeSupported; |
| 84 } | 84 } |
| 85 return mimeTypeEnum; | 85 return mimeTypeEnum; |
| 86 } | 86 } |
| 87 | 87 |
| 88 void recordIdleTaskStatusHistogram( | 88 void recordIdleTaskStatusHistogram( |
| 89 CanvasAsyncBlobCreator::ToBlobFunctionType functionType, | |
| 89 CanvasAsyncBlobCreator::IdleTaskStatus status) { | 90 CanvasAsyncBlobCreator::IdleTaskStatus status) { |
| 91 // TODO: Add histograms for OffscreenCanvas.convertToBlob. | |
|
Justin Novosad
2016/10/19 19:59:32
Preferred syntax is // TODO(crbug...):
xlai (Olivia)
2016/10/20 15:58:54
Done.
| |
| 92 // See crbug.com/653599. | |
| 93 if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) | |
| 94 return; | |
| 90 DEFINE_STATIC_LOCAL(EnumerationHistogram, toBlobIdleTaskStatus, | 95 DEFINE_STATIC_LOCAL(EnumerationHistogram, toBlobIdleTaskStatus, |
| 91 ("Blink.Canvas.ToBlob.IdleTaskStatus", | 96 ("Blink.Canvas.ToBlob.IdleTaskStatus", |
| 92 CanvasAsyncBlobCreator::IdleTaskCount)); | 97 CanvasAsyncBlobCreator::IdleTaskCount)); |
| 93 toBlobIdleTaskStatus.count(status); | 98 toBlobIdleTaskStatus.count(status); |
| 94 } | 99 } |
| 95 | 100 |
| 96 // This enum is used in histogram and any more types should be appended at the | 101 // This enum is used in histogram and any more types should be appended at the |
| 97 // end of the list. | 102 // end of the list. |
| 98 enum ElapsedTimeHistogramType { | 103 enum ElapsedTimeHistogramType { |
| 99 InitiateEncodingDelay, | 104 InitiateEncodingDelay, |
| 100 IdleEncodeDuration, | 105 IdleEncodeDuration, |
| 101 ToBlobDuration, | 106 ToBlobDuration, |
| 102 NumberOfElapsedTimeHistogramTypes | 107 NumberOfElapsedTimeHistogramTypes |
| 103 }; | 108 }; |
| 104 | 109 |
| 105 void recordElapsedTimeHistogram(ElapsedTimeHistogramType type, | 110 void recordElapsedTimeHistogram( |
| 106 CanvasAsyncBlobCreator::MimeType mimeType, | 111 CanvasAsyncBlobCreator::ToBlobFunctionType functionType, |
| 107 double elapsedTime) { | 112 ElapsedTimeHistogramType type, |
| 113 CanvasAsyncBlobCreator::MimeType mimeType, | |
| 114 double elapsedTime) { | |
| 115 // TODO: Add histograms for OffscreenCanvas.convertToBlob. | |
|
Justin Novosad
2016/10/19 19:59:32
TODO(crbug...):
xlai (Olivia)
2016/10/20 15:58:54
Done.
| |
| 116 // See crbug.com/653599. | |
| 117 if (functionType == CanvasAsyncBlobCreator::OffscreenCanvasToBlobPromise) | |
| 118 return; | |
| 119 | |
| 108 if (type == InitiateEncodingDelay) { | 120 if (type == InitiateEncodingDelay) { |
| 109 if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { | 121 if (mimeType == CanvasAsyncBlobCreator::MimeTypePng) { |
| 110 DEFINE_STATIC_LOCAL( | 122 DEFINE_STATIC_LOCAL( |
| 111 CustomCountHistogram, toBlobPNGInitiateEncodingCounter, | 123 CustomCountHistogram, toBlobPNGInitiateEncodingCounter, |
| 112 ("Blink.Canvas.ToBlob.InitiateEncodingDelay.PNG", 0, 10000000, 50)); | 124 ("Blink.Canvas.ToBlob.InitiateEncodingDelay.PNG", 0, 10000000, 50)); |
| 113 toBlobPNGInitiateEncodingCounter.count(elapsedTime * 1000000.0); | 125 toBlobPNGInitiateEncodingCounter.count(elapsedTime * 1000000.0); |
| 114 } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeJpeg) { | 126 } else if (mimeType == CanvasAsyncBlobCreator::MimeTypeJpeg) { |
| 115 DEFINE_STATIC_LOCAL( | 127 DEFINE_STATIC_LOCAL( |
| 116 CustomCountHistogram, toBlobJPEGInitiateEncodingCounter, | 128 CustomCountHistogram, toBlobJPEGInitiateEncodingCounter, |
| 117 ("Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", 0, 10000000, 50)); | 129 ("Blink.Canvas.ToBlob.InitiateEncodingDelay.JPEG", 0, 10000000, 50)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 149 } | 161 } |
| 150 | 162 |
| 151 } // anonymous namespace | 163 } // anonymous namespace |
| 152 | 164 |
| 153 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create( | 165 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create( |
| 154 DOMUint8ClampedArray* unpremultipliedRGBAImageData, | 166 DOMUint8ClampedArray* unpremultipliedRGBAImageData, |
| 155 const String& mimeType, | 167 const String& mimeType, |
| 156 const IntSize& size, | 168 const IntSize& size, |
| 157 BlobCallback* callback, | 169 BlobCallback* callback, |
| 158 double startTime, | 170 double startTime, |
| 159 Document& document) { | 171 Document* document, |
| 172 ScriptPromiseResolver* resolver) { | |
| 160 return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, | 173 return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, |
| 161 convertMimeTypeStringToEnum(mimeType), size, | 174 convertMimeTypeStringToEnum(mimeType), size, |
| 162 callback, startTime, document); | 175 callback, startTime, document, resolver); |
| 163 } | 176 } |
| 164 | 177 |
| 165 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, | 178 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, |
| 166 MimeType mimeType, | 179 MimeType mimeType, |
| 167 const IntSize& size, | 180 const IntSize& size, |
| 168 BlobCallback* callback, | 181 BlobCallback* callback, |
| 169 double startTime, | 182 double startTime, |
| 170 Document& document) | 183 Document* document, |
| 184 ScriptPromiseResolver* resolver) | |
| 171 : m_data(data), | 185 : m_data(data), |
| 172 m_document(&document), | 186 m_document(document), |
| 173 m_size(size), | 187 m_size(size), |
| 174 m_mimeType(mimeType), | 188 m_mimeType(mimeType), |
| 175 m_callback(callback), | |
| 176 m_startTime(startTime), | 189 m_startTime(startTime), |
| 177 m_elapsedTime(0), | 190 m_elapsedTime(0), |
| 178 m_parentFrameTaskRunner( | 191 m_callback(callback), |
| 179 ParentFrameTaskRunners::create(document.frame())) { | 192 m_scriptPromiseResolver(resolver) { |
| 180 ASSERT(m_data->length() == (unsigned)(size.height() * size.width() * 4)); | 193 DCHECK(m_data->length() == (unsigned)(size.height() * size.width() * 4)); |
| 181 m_encodedImage = wrapUnique(new Vector<unsigned char>()); | 194 m_encodedImage = wrapUnique(new Vector<unsigned char>()); |
| 182 m_pixelRowStride = size.width() * NumChannelsPng; | 195 m_pixelRowStride = size.width() * NumChannelsPng; |
| 183 m_idleTaskStatus = IdleTaskNotSupported; | 196 m_idleTaskStatus = IdleTaskNotSupported; |
| 184 m_numRowsCompleted = 0; | 197 m_numRowsCompleted = 0; |
| 198 if (document) { | |
| 199 m_parentFrameTaskRunner = ParentFrameTaskRunners::create(document->frame()); | |
|
Justin Novosad
2016/10/19 19:59:32
DCHECK(m_callback);
xlai (Olivia)
2016/10/20 15:58:54
If I do a DCHECK here, the unit test will fail...u
| |
| 200 } | |
| 201 if (m_scriptPromiseResolver) { | |
|
Justin Novosad
2016/10/19 19:59:32
Not necessary.
| |
| 202 m_functionType = OffscreenCanvasToBlobPromise; | |
| 203 } else { | |
| 204 m_functionType = HTMLCanvasToBlobCallback; | |
| 205 } | |
| 185 } | 206 } |
| 186 | 207 |
| 187 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() {} | 208 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() {} |
| 188 | 209 |
| 189 void CanvasAsyncBlobCreator::dispose() { | 210 void CanvasAsyncBlobCreator::dispose() { |
| 190 // Eagerly let go of references to prevent retention of these | 211 // Eagerly let go of references to prevent retention of these |
| 191 // resources while any remaining posted tasks are queued. | 212 // resources while any remaining posted tasks are queued. |
| 192 m_data.clear(); | 213 m_data.clear(); |
| 193 m_document.clear(); | 214 m_document.clear(); |
| 194 m_callback.clear(); | 215 m_callback.clear(); |
|
Justin Novosad
2016/10/19 19:59:32
How about the promise resolver?
xlai (Olivia)
2016/10/20 15:58:54
Done.
| |
| 195 } | 216 } |
| 196 | 217 |
| 197 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation( | 218 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(const double& quality) { |
| 198 bool canUseIdlePeriodScheduling, | 219 if (m_mimeType == MimeTypeWebp) { |
| 199 const double& quality) { | 220 if (!isMainThread()) { |
| 200 ASSERT(isMainThread()); | 221 DCHECK(m_functionType == OffscreenCanvasToBlobPromise); |
| 222 // When OffscreenCanvas.convertToBlob() occurs on worker thread, | |
| 223 // we do not need to use background task runner to reduce load on main. | |
| 224 // So we just directly encode images on the worker thread. | |
| 225 if (!ImageDataBuffer(m_size, m_data->data()) | |
| 226 .encodeImage("image/webp", quality, m_encodedImage.get())) { | |
| 227 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | |
| 228 ->postTask( | |
| 229 BLINK_FROM_HERE, | |
| 230 WTF::bind(&CanvasAsyncBlobCreator::createNullAndReturnResult, | |
| 231 wrapPersistent(this))); | |
| 201 | 232 |
| 202 if (canUseIdlePeriodScheduling) { | 233 return; |
| 234 } | |
| 235 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | |
| 236 ->postTask( | |
| 237 BLINK_FROM_HERE, | |
| 238 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndReturnResult, | |
| 239 wrapPersistent(this))); | |
| 240 | |
| 241 } else { | |
| 242 BackgroundTaskRunner::TaskSize taskSize = | |
| 243 (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) | |
| 244 ? BackgroundTaskRunner::TaskSizeLongRunningTask | |
| 245 : BackgroundTaskRunner::TaskSizeShortRunningTask; | |
| 246 BackgroundTaskRunner::postOnBackgroundThread( | |
| 247 BLINK_FROM_HERE, | |
| 248 crossThreadBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, | |
| 249 wrapCrossThreadPersistent(this), quality), | |
| 250 taskSize); | |
| 251 } | |
| 252 } else { | |
| 203 m_idleTaskStatus = IdleTaskNotStarted; | 253 m_idleTaskStatus = IdleTaskNotStarted; |
| 204 if (m_mimeType == MimeTypePng) { | 254 if (m_mimeType == MimeTypePng) { |
| 205 this->scheduleInitiatePngEncoding(); | 255 this->scheduleInitiatePngEncoding(); |
| 206 } else if (m_mimeType == MimeTypeJpeg) { | 256 } else if (m_mimeType == MimeTypeJpeg) { |
| 207 this->scheduleInitiateJpegEncoding(quality); | 257 this->scheduleInitiateJpegEncoding(quality); |
| 208 } else { | 258 } else { |
| 209 // Progressive encoding is only applicable to png and jpeg image format, | 259 // Progressive encoding is only applicable to png and jpeg image format, |
| 210 // and thus idle tasks scheduling can only be applied to these image | 260 // and thus idle tasks scheduling can only be applied to these image |
| 211 // formats. | 261 // formats. |
| 212 // TODO(xlai): Progressive encoding on webp image formats | 262 // TODO(xlai): Progressive encoding on webp image formats |
| 213 // (crbug.com/571399) | 263 // (crbug.com/571399) |
| 214 ASSERT_NOT_REACHED(); | 264 NOTREACHED(); |
| 215 } | 265 } |
| 216 // We post the below task to check if the above idle task isn't late. | 266 |
| 217 // There's no risk of concurrency as both tasks are on main thread. | 267 // TODO: Enforce OffscreenCanvas.convertToBlob to finish within deadline. |
| 218 this->postDelayedTaskToMainThread( | 268 // See crbug.com/657102. |
| 219 BLINK_FROM_HERE, | 269 if (m_functionType == HTMLCanvasToBlobCallback) { |
| 220 WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, | 270 // We post the below task to check if the above idle task isn't late. |
| 221 wrapPersistent(this), quality), | 271 // There's no risk of concurrency as both tasks are on main thread. |
| 222 IdleTaskStartTimeoutDelay); | 272 this->postDelayedTaskToMainThread( |
| 223 } else if (m_mimeType == MimeTypeWebp) { | 273 BLINK_FROM_HERE, |
| 224 BackgroundTaskRunner::TaskSize taskSize = | 274 WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, |
| 225 (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) | 275 wrapPersistent(this), quality), |
| 226 ? BackgroundTaskRunner::TaskSizeLongRunningTask | 276 IdleTaskStartTimeoutDelay); |
| 227 : BackgroundTaskRunner::TaskSizeShortRunningTask; | 277 } |
| 228 BackgroundTaskRunner::postOnBackgroundThread( | |
| 229 BLINK_FROM_HERE, | |
| 230 crossThreadBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, | |
| 231 wrapCrossThreadPersistent(this), quality), | |
| 232 taskSize); | |
| 233 } | 278 } |
| 234 } | 279 } |
| 235 | 280 |
| 236 void CanvasAsyncBlobCreator::scheduleInitiateJpegEncoding( | 281 void CanvasAsyncBlobCreator::scheduleInitiateJpegEncoding( |
| 237 const double& quality) { | 282 const double& quality) { |
| 238 m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); | 283 m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); |
| 239 Platform::current()->mainThread()->scheduler()->postIdleTask( | 284 Platform::current()->currentThread()->scheduler()->postIdleTask( |
| 240 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, | 285 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, |
| 241 wrapPersistent(this), quality)); | 286 wrapPersistent(this), quality)); |
| 242 } | 287 } |
| 243 | 288 |
| 244 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality, | 289 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality, |
| 245 double deadlineSeconds) { | 290 double deadlineSeconds) { |
| 246 ASSERT(isMainThread()); | |
| 247 recordElapsedTimeHistogram( | 291 recordElapsedTimeHistogram( |
| 248 InitiateEncodingDelay, MimeTypeJpeg, | 292 m_functionType, InitiateEncodingDelay, MimeTypeJpeg, |
| 249 WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); | 293 WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); |
| 250 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { | 294 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| 251 return; | 295 return; |
| 252 } | 296 } |
| 253 | 297 |
| 254 ASSERT(m_idleTaskStatus == IdleTaskNotStarted); | 298 DCHECK(m_idleTaskStatus == IdleTaskNotStarted); |
| 255 m_idleTaskStatus = IdleTaskStarted; | 299 m_idleTaskStatus = IdleTaskStarted; |
| 256 | 300 |
| 257 if (!initializeJpegStruct(quality)) { | 301 if (!initializeJpegStruct(quality)) { |
| 258 m_idleTaskStatus = IdleTaskFailed; | 302 m_idleTaskStatus = IdleTaskFailed; |
| 259 return; | 303 return; |
| 260 } | 304 } |
| 261 this->idleEncodeRowsJpeg(deadlineSeconds); | 305 this->idleEncodeRowsJpeg(deadlineSeconds); |
| 262 } | 306 } |
| 263 | 307 |
| 264 void CanvasAsyncBlobCreator::scheduleInitiatePngEncoding() { | 308 void CanvasAsyncBlobCreator::scheduleInitiatePngEncoding() { |
| 265 m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); | 309 m_scheduleInitiateStartTime = WTF::monotonicallyIncreasingTime(); |
| 266 Platform::current()->mainThread()->scheduler()->postIdleTask( | 310 Platform::current()->currentThread()->scheduler()->postIdleTask( |
| 267 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiatePngEncoding, | 311 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::initiatePngEncoding, |
| 268 wrapPersistent(this))); | 312 wrapPersistent(this))); |
| 269 } | 313 } |
| 270 | 314 |
| 271 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) { | 315 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) { |
| 272 ASSERT(isMainThread()); | |
| 273 recordElapsedTimeHistogram( | 316 recordElapsedTimeHistogram( |
| 274 InitiateEncodingDelay, MimeTypePng, | 317 m_functionType, InitiateEncodingDelay, MimeTypePng, |
| 275 WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); | 318 WTF::monotonicallyIncreasingTime() - m_scheduleInitiateStartTime); |
| 276 | |
| 277 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { | 319 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| 278 return; | 320 return; |
| 279 } | 321 } |
| 280 | 322 |
| 281 ASSERT(m_idleTaskStatus == IdleTaskNotStarted); | 323 DCHECK(m_idleTaskStatus == IdleTaskNotStarted); |
| 282 m_idleTaskStatus = IdleTaskStarted; | 324 m_idleTaskStatus = IdleTaskStarted; |
| 283 | 325 |
| 284 if (!initializePngStruct()) { | 326 if (!initializePngStruct()) { |
| 285 m_idleTaskStatus = IdleTaskFailed; | 327 m_idleTaskStatus = IdleTaskFailed; |
| 286 return; | 328 return; |
| 287 } | 329 } |
| 288 this->idleEncodeRowsPng(deadlineSeconds); | 330 this->idleEncodeRowsPng(deadlineSeconds); |
| 289 } | 331 } |
| 290 | 332 |
| 291 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) { | 333 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) { |
| 292 ASSERT(isMainThread()); | |
| 293 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { | 334 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| 294 return; | 335 return; |
| 295 } | 336 } |
| 296 | 337 |
| 297 double startTime = WTF::monotonicallyIncreasingTime(); | 338 double startTime = WTF::monotonicallyIncreasingTime(); |
| 298 unsigned char* inputPixels = | 339 unsigned char* inputPixels = |
| 299 m_data->data() + m_pixelRowStride * m_numRowsCompleted; | 340 m_data->data() + m_pixelRowStride * m_numRowsCompleted; |
| 300 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { | 341 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { |
| 301 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 342 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| 302 m_numRowsCompleted = y; | 343 m_numRowsCompleted = y; |
| 303 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); | 344 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| 304 Platform::current()->currentThread()->scheduler()->postIdleTask( | 345 Platform::current()->currentThread()->scheduler()->postIdleTask( |
| 305 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsPng, | 346 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsPng, |
| 306 wrapPersistent(this))); | 347 wrapPersistent(this))); |
| 307 return; | 348 return; |
| 308 } | 349 } |
| 309 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); | 350 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); |
| 310 inputPixels += m_pixelRowStride; | 351 inputPixels += m_pixelRowStride; |
| 311 } | 352 } |
| 312 m_numRowsCompleted = m_size.height(); | 353 m_numRowsCompleted = m_size.height(); |
| 313 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); | 354 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); |
| 314 | 355 |
| 315 m_idleTaskStatus = IdleTaskCompleted; | 356 m_idleTaskStatus = IdleTaskCompleted; |
| 316 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); | 357 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| 317 recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypePng, m_elapsedTime); | 358 recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypePng, |
| 359 m_elapsedTime); | |
| 318 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 360 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| 319 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 361 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 320 ->postTask( | 362 ->postTask(BLINK_FROM_HERE, |
| 321 BLINK_FROM_HERE, | 363 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndReturnResult, |
| 322 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, | 364 wrapPersistent(this))); |
| 323 wrapPersistent(this))); | |
| 324 } else { | 365 } else { |
| 325 this->createBlobAndInvokeCallback(); | 366 this->createBlobAndReturnResult(); |
| 326 } | 367 } |
| 327 } | 368 } |
| 328 | 369 |
| 329 void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { | 370 void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { |
| 330 ASSERT(isMainThread()); | |
| 331 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { | 371 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| 332 return; | 372 return; |
| 333 } | 373 } |
| 334 | 374 |
| 335 double startTime = WTF::monotonicallyIncreasingTime(); | 375 double startTime = WTF::monotonicallyIncreasingTime(); |
| 336 m_numRowsCompleted = JPEGImageEncoder::progressiveEncodeRowsJpegHelper( | 376 m_numRowsCompleted = JPEGImageEncoder::progressiveEncodeRowsJpegHelper( |
| 337 m_jpegEncoderState.get(), m_data->data(), m_numRowsCompleted, | 377 m_jpegEncoderState.get(), m_data->data(), m_numRowsCompleted, |
| 338 SlackBeforeDeadline, deadlineSeconds); | 378 SlackBeforeDeadline, deadlineSeconds); |
| 339 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); | 379 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| 340 if (m_numRowsCompleted == m_size.height()) { | 380 if (m_numRowsCompleted == m_size.height()) { |
| 341 m_idleTaskStatus = IdleTaskCompleted; | 381 m_idleTaskStatus = IdleTaskCompleted; |
| 342 recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypeJpeg, m_elapsedTime); | 382 recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypeJpeg, |
| 383 m_elapsedTime); | |
| 343 | 384 |
| 344 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 385 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| 345 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 386 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 346 ->postTask( | 387 ->postTask( |
| 347 BLINK_FROM_HERE, | 388 BLINK_FROM_HERE, |
| 348 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, | 389 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndReturnResult, |
| 349 wrapPersistent(this))); | 390 wrapPersistent(this))); |
| 350 } else { | 391 } else { |
| 351 this->createBlobAndInvokeCallback(); | 392 this->createBlobAndReturnResult(); |
| 352 } | 393 } |
| 353 } else if (m_numRowsCompleted == JPEGImageEncoder::ProgressiveEncodeFailed) { | 394 } else if (m_numRowsCompleted == JPEGImageEncoder::ProgressiveEncodeFailed) { |
| 354 m_idleTaskStatus = IdleTaskFailed; | 395 m_idleTaskStatus = IdleTaskFailed; |
| 355 this->createNullAndInvokeCallback(); | 396 this->createNullAndReturnResult(); |
| 356 } else { | 397 } else { |
| 357 Platform::current()->currentThread()->scheduler()->postIdleTask( | 398 Platform::current()->currentThread()->scheduler()->postIdleTask( |
| 358 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsJpeg, | 399 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsJpeg, |
| 359 wrapPersistent(this))); | 400 wrapPersistent(this))); |
| 360 } | 401 } |
| 361 } | 402 } |
| 362 | 403 |
| 363 void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { | 404 void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { |
| 364 ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); | 405 DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| 365 | 406 |
| 366 // Continue encoding from the last completed row | 407 // Continue encoding from the last completed row |
| 367 unsigned char* inputPixels = | 408 unsigned char* inputPixels = |
| 368 m_data->data() + m_pixelRowStride * m_numRowsCompleted; | 409 m_data->data() + m_pixelRowStride * m_numRowsCompleted; |
| 369 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { | 410 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { |
| 370 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); | 411 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); |
| 371 inputPixels += m_pixelRowStride; | 412 inputPixels += m_pixelRowStride; |
| 372 } | 413 } |
| 373 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); | 414 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); |
| 374 this->createBlobAndInvokeCallback(); | 415 this->createBlobAndReturnResult(); |
| 375 | 416 |
| 376 this->signalAlternativeCodePathFinishedForTesting(); | 417 this->signalAlternativeCodePathFinishedForTesting(); |
| 377 } | 418 } |
| 378 | 419 |
| 379 void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { | 420 void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { |
| 380 ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); | 421 DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| 381 | 422 |
| 382 // Continue encoding from the last completed row | 423 // Continue encoding from the last completed row |
| 383 if (JPEGImageEncoder::encodeWithPreInitializedState( | 424 if (JPEGImageEncoder::encodeWithPreInitializedState( |
| 384 std::move(m_jpegEncoderState), m_data->data(), m_numRowsCompleted)) { | 425 std::move(m_jpegEncoderState), m_data->data(), m_numRowsCompleted)) { |
| 385 this->createBlobAndInvokeCallback(); | 426 this->createBlobAndReturnResult(); |
| 386 } else { | 427 } else { |
| 387 this->createNullAndInvokeCallback(); | 428 this->createNullAndReturnResult(); |
| 388 } | 429 } |
| 389 | 430 |
| 390 this->signalAlternativeCodePathFinishedForTesting(); | 431 this->signalAlternativeCodePathFinishedForTesting(); |
| 391 } | 432 } |
| 392 | 433 |
| 393 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() { | 434 void CanvasAsyncBlobCreator::createBlobAndReturnResult() { |
| 394 ASSERT(isMainThread()); | 435 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 395 recordIdleTaskStatusHistogram(m_idleTaskStatus); | 436 recordElapsedTimeHistogram(m_functionType, ToBlobDuration, m_mimeType, |
| 437 WTF::monotonicallyIncreasingTime() - m_startTime); | |
| 396 | 438 |
| 397 recordElapsedTimeHistogram(ToBlobDuration, m_mimeType, | |
| 398 WTF::monotonicallyIncreasingTime() - m_startTime); | |
| 399 Blob* resultBlob = | 439 Blob* resultBlob = |
| 400 Blob::create(m_encodedImage->data(), m_encodedImage->size(), | 440 Blob::create(m_encodedImage->data(), m_encodedImage->size(), |
| 401 convertMimeTypeEnumToString(m_mimeType)); | 441 convertMimeTypeEnumToString(m_mimeType)); |
| 402 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 442 if (m_functionType == HTMLCanvasToBlobCallback) { |
| 403 ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, | 443 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 404 wrapPersistent(m_callback.get()), | 444 ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, |
| 405 wrapPersistent(resultBlob))); | 445 wrapPersistent(m_callback.get()), |
| 446 wrapPersistent(resultBlob))); | |
| 447 } else { | |
| 448 m_scriptPromiseResolver->resolve(resultBlob); | |
| 449 } | |
| 406 // Avoid unwanted retention, see dispose(). | 450 // Avoid unwanted retention, see dispose(). |
| 407 dispose(); | 451 dispose(); |
| 408 } | 452 } |
| 409 | 453 |
| 410 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() { | 454 void CanvasAsyncBlobCreator::createNullAndReturnResult() { |
| 411 ASSERT(isMainThread()); | 455 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 412 recordIdleTaskStatusHistogram(m_idleTaskStatus); | 456 if (m_functionType == HTMLCanvasToBlobCallback) { |
| 413 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 457 DCHECK(isMainThread()); |
| 414 ->postTask(BLINK_FROM_HERE, | 458 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 415 WTF::bind(&BlobCallback::handleEvent, | 459 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 416 wrapPersistent(m_callback.get()), nullptr)); | 460 ->postTask(BLINK_FROM_HERE, |
| 461 WTF::bind(&BlobCallback::handleEvent, | |
| 462 wrapPersistent(m_callback.get()), nullptr)); | |
| 463 } else { | |
| 464 Blob* blob = nullptr; | |
| 465 m_scriptPromiseResolver->reject(blob); | |
| 466 } | |
| 417 // Avoid unwanted retention, see dispose(). | 467 // Avoid unwanted retention, see dispose(). |
| 418 dispose(); | 468 dispose(); |
| 419 } | 469 } |
| 420 | 470 |
| 421 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { | 471 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { |
| 422 ASSERT(!isMainThread()); | 472 DCHECK(!isMainThread()); |
| 423 ASSERT(m_mimeType == MimeTypeWebp); | 473 DCHECK(m_mimeType == MimeTypeWebp); |
| 424 | 474 |
| 425 if (!ImageDataBuffer(m_size, m_data->data()) | 475 if (!ImageDataBuffer(m_size, m_data->data()) |
| 426 .encodeImage("image/webp", quality, m_encodedImage.get())) { | 476 .encodeImage("image/webp", quality, m_encodedImage.get())) { |
| 427 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) | 477 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) |
| 428 ->postTask(BLINK_FROM_HERE, | 478 ->postTask(BLINK_FROM_HERE, |
| 429 crossThreadBind(&BlobCallback::handleEvent, | 479 crossThreadBind(&BlobCallback::handleEvent, |
| 430 wrapCrossThreadPersistent(m_callback.get()), | 480 wrapCrossThreadPersistent(m_callback.get()), |
| 431 nullptr)); | 481 nullptr)); |
| 432 return; | 482 return; |
| 433 } | 483 } |
| 434 | 484 |
| 435 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) | 485 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) |
| 436 ->postTask( | 486 ->postTask( |
| 437 BLINK_FROM_HERE, | 487 BLINK_FROM_HERE, |
| 438 crossThreadBind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, | 488 crossThreadBind(&CanvasAsyncBlobCreator::createBlobAndReturnResult, |
| 439 wrapCrossThreadPersistent(this))); | 489 wrapCrossThreadPersistent(this))); |
| 440 } | 490 } |
| 441 | 491 |
| 442 bool CanvasAsyncBlobCreator::initializePngStruct() { | 492 bool CanvasAsyncBlobCreator::initializePngStruct() { |
| 443 m_pngEncoderState = | 493 m_pngEncoderState = |
| 444 PNGImageEncoderState::create(m_size, m_encodedImage.get()); | 494 PNGImageEncoderState::create(m_size, m_encodedImage.get()); |
| 445 if (!m_pngEncoderState) { | 495 if (!m_pngEncoderState) { |
| 446 this->createNullAndInvokeCallback(); | 496 this->createNullAndReturnResult(); |
| 447 return false; | 497 return false; |
| 448 } | 498 } |
| 449 return true; | 499 return true; |
| 450 } | 500 } |
| 451 | 501 |
| 452 bool CanvasAsyncBlobCreator::initializeJpegStruct(double quality) { | 502 bool CanvasAsyncBlobCreator::initializeJpegStruct(double quality) { |
| 453 m_jpegEncoderState = | 503 m_jpegEncoderState = |
| 454 JPEGImageEncoderState::create(m_size, quality, m_encodedImage.get()); | 504 JPEGImageEncoderState::create(m_size, quality, m_encodedImage.get()); |
| 455 if (!m_jpegEncoderState) { | 505 if (!m_jpegEncoderState) { |
| 456 this->createNullAndInvokeCallback(); | 506 this->createNullAndReturnResult(); |
| 457 return false; | 507 return false; |
| 458 } | 508 } |
| 459 return true; | 509 return true; |
| 460 } | 510 } |
| 461 | 511 |
| 462 void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) { | 512 void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) { |
| 463 if (m_idleTaskStatus == IdleTaskStarted) { | 513 if (m_idleTaskStatus == IdleTaskStarted) { |
| 464 // Even if the task started quickly, we still want to ensure completion | 514 // Even if the task started quickly, we still want to ensure completion |
| 465 this->postDelayedTaskToMainThread( | 515 this->postDelayedTaskToMainThread( |
| 466 BLINK_FROM_HERE, | 516 BLINK_FROM_HERE, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 479 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 529 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 480 ->postTask( | 530 ->postTask( |
| 481 BLINK_FROM_HERE, | 531 BLINK_FROM_HERE, |
| 482 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, | 532 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, |
| 483 wrapPersistent(this))); | 533 wrapPersistent(this))); |
| 484 } else { | 534 } else { |
| 485 // Failing in initialization of png struct | 535 // Failing in initialization of png struct |
| 486 this->signalAlternativeCodePathFinishedForTesting(); | 536 this->signalAlternativeCodePathFinishedForTesting(); |
| 487 } | 537 } |
| 488 } else { | 538 } else { |
| 489 ASSERT(m_mimeType == MimeTypeJpeg); | 539 DCHECK(m_mimeType == MimeTypeJpeg); |
| 490 if (initializeJpegStruct(quality)) { | 540 if (initializeJpegStruct(quality)) { |
| 491 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 541 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 492 ->postTask( | 542 ->postTask( |
| 493 BLINK_FROM_HERE, | 543 BLINK_FROM_HERE, |
| 494 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, | 544 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, |
| 495 wrapPersistent(this))); | 545 wrapPersistent(this))); |
| 496 } else { | 546 } else { |
| 497 // Failing in initialization of jpeg struct | 547 // Failing in initialization of jpeg struct |
| 498 this->signalAlternativeCodePathFinishedForTesting(); | 548 this->signalAlternativeCodePathFinishedForTesting(); |
| 499 } | 549 } |
| 500 } | 550 } |
| 501 } else { | 551 } else { |
| 502 ASSERT(m_idleTaskStatus == IdleTaskFailed || | 552 DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| 503 m_idleTaskStatus == IdleTaskCompleted); | 553 m_idleTaskStatus == IdleTaskCompleted); |
| 504 this->signalAlternativeCodePathFinishedForTesting(); | 554 this->signalAlternativeCodePathFinishedForTesting(); |
| 505 } | 555 } |
| 506 } | 556 } |
| 507 | 557 |
| 508 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { | 558 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { |
| 509 ASSERT(m_idleTaskStatus != IdleTaskNotStarted); | 559 DCHECK(m_idleTaskStatus != IdleTaskNotStarted); |
| 510 | 560 |
| 511 if (m_idleTaskStatus == IdleTaskStarted) { | 561 if (m_idleTaskStatus == IdleTaskStarted) { |
| 512 // It has taken too long to complete for the idle task. | 562 // It has taken too long to complete for the idle task. |
| 513 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; | 563 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; |
| 514 signalTaskSwitchInCompleteTimeoutEventForTesting(); | 564 signalTaskSwitchInCompleteTimeoutEventForTesting(); |
| 515 | 565 |
| 516 if (m_mimeType == MimeTypePng) { | 566 if (m_mimeType == MimeTypePng) { |
| 517 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 567 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 518 ->postTask( | 568 ->postTask( |
| 519 BLINK_FROM_HERE, | 569 BLINK_FROM_HERE, |
| 520 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, | 570 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, |
| 521 wrapPersistent(this))); | 571 wrapPersistent(this))); |
| 522 } else { | 572 } else { |
| 523 ASSERT(m_mimeType == MimeTypeJpeg); | 573 DCHECK(m_mimeType == MimeTypeJpeg); |
| 524 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 574 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 525 ->postTask( | 575 ->postTask( |
| 526 BLINK_FROM_HERE, | 576 BLINK_FROM_HERE, |
| 527 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, | 577 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, |
| 528 wrapPersistent(this))); | 578 wrapPersistent(this))); |
| 529 } | 579 } |
| 530 } else { | 580 } else { |
| 531 ASSERT(m_idleTaskStatus == IdleTaskFailed || | 581 DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| 532 m_idleTaskStatus == IdleTaskCompleted); | 582 m_idleTaskStatus == IdleTaskCompleted); |
| 533 this->signalAlternativeCodePathFinishedForTesting(); | 583 this->signalAlternativeCodePathFinishedForTesting(); |
| 534 } | 584 } |
| 535 } | 585 } |
| 536 | 586 |
| 537 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread( | 587 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread( |
| 538 const WebTraceLocation& location, | 588 const WebTraceLocation& location, |
| 539 std::unique_ptr<WTF::Closure> task, | 589 std::unique_ptr<WTF::Closure> task, |
| 540 double delayMs) { | 590 double delayMs) { |
| 541 DCHECK(isMainThread()); | 591 DCHECK(isMainThread()); |
| 542 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 592 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 543 ->postDelayedTask(location, std::move(task), delayMs); | 593 ->postDelayedTask(location, std::move(task), delayMs); |
| 544 } | 594 } |
| 545 | 595 |
| 546 DEFINE_TRACE(CanvasAsyncBlobCreator) { | 596 DEFINE_TRACE(CanvasAsyncBlobCreator) { |
| 547 visitor->trace(m_document); | 597 visitor->trace(m_document); |
| 548 visitor->trace(m_data); | 598 visitor->trace(m_data); |
| 549 visitor->trace(m_callback); | 599 visitor->trace(m_callback); |
| 550 visitor->trace(m_parentFrameTaskRunner); | 600 visitor->trace(m_parentFrameTaskRunner); |
| 601 visitor->trace(m_scriptPromiseResolver); | |
| 551 } | 602 } |
| 552 | 603 |
| 553 } // namespace blink | 604 } // namespace blink |
| OLD | NEW |