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. | |
| 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. | |
| 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()); | |
| 200 } | |
| 201 if (m_scriptPromiseResolver) { | |
| 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(); |
| 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); |
|
xlai (Olivia)
2016/10/19 18:51:06
All these assertion of isMainThread() need to be r
| |
| 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::createNullAndInvokeCallback, | |
| 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::createBlobAndInvokeCallback, | |
| 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( |
| 321 BLINK_FROM_HERE, | 363 BLINK_FROM_HERE, |
| 322 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, | 364 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, |
| 323 wrapPersistent(this))); | 365 wrapPersistent(this))); |
| 324 } else { | 366 } else { |
| 325 this->createBlobAndInvokeCallback(); | 367 this->createBlobAndInvokeCallback(); |
| 326 } | 368 } |
| 327 } | 369 } |
| 328 | 370 |
| 329 void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { | 371 void CanvasAsyncBlobCreator::idleEncodeRowsJpeg(double deadlineSeconds) { |
| 330 ASSERT(isMainThread()); | 372 if (m_callback) { |
| 331 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { | 373 if (m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask) { |
| 332 return; | 374 return; |
| 375 } | |
| 333 } | 376 } |
| 334 | 377 |
| 335 double startTime = WTF::monotonicallyIncreasingTime(); | 378 double startTime = WTF::monotonicallyIncreasingTime(); |
| 336 m_numRowsCompleted = JPEGImageEncoder::progressiveEncodeRowsJpegHelper( | 379 m_numRowsCompleted = JPEGImageEncoder::progressiveEncodeRowsJpegHelper( |
| 337 m_jpegEncoderState.get(), m_data->data(), m_numRowsCompleted, | 380 m_jpegEncoderState.get(), m_data->data(), m_numRowsCompleted, |
| 338 SlackBeforeDeadline, deadlineSeconds); | 381 SlackBeforeDeadline, deadlineSeconds); |
| 339 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); | 382 m_elapsedTime += (WTF::monotonicallyIncreasingTime() - startTime); |
| 340 if (m_numRowsCompleted == m_size.height()) { | 383 if (m_numRowsCompleted == m_size.height()) { |
| 341 m_idleTaskStatus = IdleTaskCompleted; | 384 m_idleTaskStatus = IdleTaskCompleted; |
| 342 recordElapsedTimeHistogram(IdleEncodeDuration, MimeTypeJpeg, m_elapsedTime); | 385 recordElapsedTimeHistogram(m_functionType, IdleEncodeDuration, MimeTypeJpeg, |
| 386 m_elapsedTime); | |
| 343 | 387 |
| 344 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 388 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
| 345 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 389 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 346 ->postTask( | 390 ->postTask( |
| 347 BLINK_FROM_HERE, | 391 BLINK_FROM_HERE, |
| 348 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, | 392 WTF::bind(&CanvasAsyncBlobCreator::createBlobAndInvokeCallback, |
| 349 wrapPersistent(this))); | 393 wrapPersistent(this))); |
| 350 } else { | 394 } else { |
| 351 this->createBlobAndInvokeCallback(); | 395 this->createBlobAndInvokeCallback(); |
| 352 } | 396 } |
| 353 } else if (m_numRowsCompleted == JPEGImageEncoder::ProgressiveEncodeFailed) { | 397 } else if (m_numRowsCompleted == JPEGImageEncoder::ProgressiveEncodeFailed) { |
| 354 m_idleTaskStatus = IdleTaskFailed; | 398 m_idleTaskStatus = IdleTaskFailed; |
| 355 this->createNullAndInvokeCallback(); | 399 this->createNullAndInvokeCallback(); |
| 356 } else { | 400 } else { |
| 357 Platform::current()->currentThread()->scheduler()->postIdleTask( | 401 Platform::current()->currentThread()->scheduler()->postIdleTask( |
| 358 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsJpeg, | 402 BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleEncodeRowsJpeg, |
| 359 wrapPersistent(this))); | 403 wrapPersistent(this))); |
| 360 } | 404 } |
| 361 } | 405 } |
| 362 | 406 |
| 363 void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { | 407 void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { |
| 364 ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); | 408 DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| 365 | 409 |
| 366 // Continue encoding from the last completed row | 410 // Continue encoding from the last completed row |
| 367 unsigned char* inputPixels = | 411 unsigned char* inputPixels = |
| 368 m_data->data() + m_pixelRowStride * m_numRowsCompleted; | 412 m_data->data() + m_pixelRowStride * m_numRowsCompleted; |
| 369 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { | 413 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { |
| 370 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); | 414 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); |
| 371 inputPixels += m_pixelRowStride; | 415 inputPixels += m_pixelRowStride; |
| 372 } | 416 } |
| 373 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); | 417 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); |
| 374 this->createBlobAndInvokeCallback(); | 418 this->createBlobAndInvokeCallback(); |
| 375 | 419 |
| 376 this->signalAlternativeCodePathFinishedForTesting(); | 420 this->signalAlternativeCodePathFinishedForTesting(); |
| 377 } | 421 } |
| 378 | 422 |
| 379 void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { | 423 void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { |
| 380 ASSERT(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); | 424 DCHECK(m_idleTaskStatus == IdleTaskSwitchedToMainThreadTask); |
| 381 | 425 |
| 382 // Continue encoding from the last completed row | 426 // Continue encoding from the last completed row |
| 383 if (JPEGImageEncoder::encodeWithPreInitializedState( | 427 if (JPEGImageEncoder::encodeWithPreInitializedState( |
| 384 std::move(m_jpegEncoderState), m_data->data(), m_numRowsCompleted)) { | 428 std::move(m_jpegEncoderState), m_data->data(), m_numRowsCompleted)) { |
| 385 this->createBlobAndInvokeCallback(); | 429 this->createBlobAndInvokeCallback(); |
| 386 } else { | 430 } else { |
| 387 this->createNullAndInvokeCallback(); | 431 this->createNullAndInvokeCallback(); |
| 388 } | 432 } |
| 389 | 433 |
| 390 this->signalAlternativeCodePathFinishedForTesting(); | 434 this->signalAlternativeCodePathFinishedForTesting(); |
| 391 } | 435 } |
| 392 | 436 |
| 393 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() { | 437 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() { |
| 394 ASSERT(isMainThread()); | 438 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 395 recordIdleTaskStatusHistogram(m_idleTaskStatus); | 439 recordElapsedTimeHistogram(m_functionType, ToBlobDuration, m_mimeType, |
| 440 WTF::monotonicallyIncreasingTime() - m_startTime); | |
| 396 | 441 |
| 397 recordElapsedTimeHistogram(ToBlobDuration, m_mimeType, | |
| 398 WTF::monotonicallyIncreasingTime() - m_startTime); | |
| 399 Blob* resultBlob = | 442 Blob* resultBlob = |
| 400 Blob::create(m_encodedImage->data(), m_encodedImage->size(), | 443 Blob::create(m_encodedImage->data(), m_encodedImage->size(), |
| 401 convertMimeTypeEnumToString(m_mimeType)); | 444 convertMimeTypeEnumToString(m_mimeType)); |
| 402 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 445 if (m_functionType == HTMLCanvasToBlobCallback) { |
| 403 ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, | 446 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 404 wrapPersistent(m_callback.get()), | 447 ->postTask(BLINK_FROM_HERE, WTF::bind(&BlobCallback::handleEvent, |
| 405 wrapPersistent(resultBlob))); | 448 wrapPersistent(m_callback.get()), |
| 449 wrapPersistent(resultBlob))); | |
| 450 } else { | |
| 451 m_scriptPromiseResolver->resolve(resultBlob); | |
| 452 } | |
| 406 // Avoid unwanted retention, see dispose(). | 453 // Avoid unwanted retention, see dispose(). |
| 407 dispose(); | 454 dispose(); |
| 408 } | 455 } |
| 409 | 456 |
| 410 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() { | 457 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() { |
| 411 ASSERT(isMainThread()); | 458 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 412 recordIdleTaskStatusHistogram(m_idleTaskStatus); | 459 if (m_functionType == HTMLCanvasToBlobCallback) { |
| 413 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 460 DCHECK(isMainThread()); |
| 414 ->postTask(BLINK_FROM_HERE, | 461 recordIdleTaskStatusHistogram(m_functionType, m_idleTaskStatus); |
| 415 WTF::bind(&BlobCallback::handleEvent, | 462 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 416 wrapPersistent(m_callback.get()), nullptr)); | 463 ->postTask(BLINK_FROM_HERE, |
| 464 WTF::bind(&BlobCallback::handleEvent, | |
| 465 wrapPersistent(m_callback.get()), nullptr)); | |
| 466 } else { | |
| 467 Blob* blob = nullptr; | |
| 468 m_scriptPromiseResolver->reject(blob); | |
| 469 } | |
| 417 // Avoid unwanted retention, see dispose(). | 470 // Avoid unwanted retention, see dispose(). |
| 418 dispose(); | 471 dispose(); |
| 419 } | 472 } |
| 420 | 473 |
| 421 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { | 474 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { |
| 422 ASSERT(!isMainThread()); | 475 DCHECK(!isMainThread()); |
| 423 ASSERT(m_mimeType == MimeTypeWebp); | 476 DCHECK(m_mimeType == MimeTypeWebp); |
| 424 | 477 |
| 425 if (!ImageDataBuffer(m_size, m_data->data()) | 478 if (!ImageDataBuffer(m_size, m_data->data()) |
| 426 .encodeImage("image/webp", quality, m_encodedImage.get())) { | 479 .encodeImage("image/webp", quality, m_encodedImage.get())) { |
| 427 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) | 480 m_parentFrameTaskRunner->get(TaskType::CanvasBlobSerialization) |
| 428 ->postTask(BLINK_FROM_HERE, | 481 ->postTask(BLINK_FROM_HERE, |
| 429 crossThreadBind(&BlobCallback::handleEvent, | 482 crossThreadBind(&BlobCallback::handleEvent, |
| 430 wrapCrossThreadPersistent(m_callback.get()), | 483 wrapCrossThreadPersistent(m_callback.get()), |
| 431 nullptr)); | 484 nullptr)); |
| 432 return; | 485 return; |
| 433 } | 486 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 532 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 480 ->postTask( | 533 ->postTask( |
| 481 BLINK_FROM_HERE, | 534 BLINK_FROM_HERE, |
| 482 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, | 535 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, |
| 483 wrapPersistent(this))); | 536 wrapPersistent(this))); |
| 484 } else { | 537 } else { |
| 485 // Failing in initialization of png struct | 538 // Failing in initialization of png struct |
| 486 this->signalAlternativeCodePathFinishedForTesting(); | 539 this->signalAlternativeCodePathFinishedForTesting(); |
| 487 } | 540 } |
| 488 } else { | 541 } else { |
| 489 ASSERT(m_mimeType == MimeTypeJpeg); | 542 DCHECK(m_mimeType == MimeTypeJpeg); |
| 490 if (initializeJpegStruct(quality)) { | 543 if (initializeJpegStruct(quality)) { |
| 491 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 544 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 492 ->postTask( | 545 ->postTask( |
| 493 BLINK_FROM_HERE, | 546 BLINK_FROM_HERE, |
| 494 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, | 547 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, |
| 495 wrapPersistent(this))); | 548 wrapPersistent(this))); |
| 496 } else { | 549 } else { |
| 497 // Failing in initialization of jpeg struct | 550 // Failing in initialization of jpeg struct |
| 498 this->signalAlternativeCodePathFinishedForTesting(); | 551 this->signalAlternativeCodePathFinishedForTesting(); |
| 499 } | 552 } |
| 500 } | 553 } |
| 501 } else { | 554 } else { |
| 502 ASSERT(m_idleTaskStatus == IdleTaskFailed || | 555 DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| 503 m_idleTaskStatus == IdleTaskCompleted); | 556 m_idleTaskStatus == IdleTaskCompleted); |
| 504 this->signalAlternativeCodePathFinishedForTesting(); | 557 this->signalAlternativeCodePathFinishedForTesting(); |
| 505 } | 558 } |
| 506 } | 559 } |
| 507 | 560 |
| 508 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { | 561 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() { |
| 509 ASSERT(m_idleTaskStatus != IdleTaskNotStarted); | 562 DCHECK(m_idleTaskStatus != IdleTaskNotStarted); |
| 510 | 563 |
| 511 if (m_idleTaskStatus == IdleTaskStarted) { | 564 if (m_idleTaskStatus == IdleTaskStarted) { |
| 512 // It has taken too long to complete for the idle task. | 565 // It has taken too long to complete for the idle task. |
| 513 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; | 566 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; |
| 514 signalTaskSwitchInCompleteTimeoutEventForTesting(); | 567 signalTaskSwitchInCompleteTimeoutEventForTesting(); |
| 515 | 568 |
| 516 if (m_mimeType == MimeTypePng) { | 569 if (m_mimeType == MimeTypePng) { |
| 517 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 570 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 518 ->postTask( | 571 ->postTask( |
| 519 BLINK_FROM_HERE, | 572 BLINK_FROM_HERE, |
| 520 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, | 573 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, |
| 521 wrapPersistent(this))); | 574 wrapPersistent(this))); |
| 522 } else { | 575 } else { |
| 523 ASSERT(m_mimeType == MimeTypeJpeg); | 576 DCHECK(m_mimeType == MimeTypeJpeg); |
| 524 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 577 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 525 ->postTask( | 578 ->postTask( |
| 526 BLINK_FROM_HERE, | 579 BLINK_FROM_HERE, |
| 527 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, | 580 WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, |
| 528 wrapPersistent(this))); | 581 wrapPersistent(this))); |
| 529 } | 582 } |
| 530 } else { | 583 } else { |
| 531 ASSERT(m_idleTaskStatus == IdleTaskFailed || | 584 DCHECK(m_idleTaskStatus == IdleTaskFailed || |
| 532 m_idleTaskStatus == IdleTaskCompleted); | 585 m_idleTaskStatus == IdleTaskCompleted); |
| 533 this->signalAlternativeCodePathFinishedForTesting(); | 586 this->signalAlternativeCodePathFinishedForTesting(); |
| 534 } | 587 } |
| 535 } | 588 } |
| 536 | 589 |
| 537 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread( | 590 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread( |
| 538 const WebTraceLocation& location, | 591 const WebTraceLocation& location, |
| 539 std::unique_ptr<WTF::Closure> task, | 592 std::unique_ptr<WTF::Closure> task, |
| 540 double delayMs) { | 593 double delayMs) { |
| 541 DCHECK(isMainThread()); | 594 DCHECK(isMainThread()); |
| 542 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) | 595 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) |
| 543 ->postDelayedTask(location, std::move(task), delayMs); | 596 ->postDelayedTask(location, std::move(task), delayMs); |
| 544 } | 597 } |
| 545 | 598 |
| 546 DEFINE_TRACE(CanvasAsyncBlobCreator) { | 599 DEFINE_TRACE(CanvasAsyncBlobCreator) { |
| 547 visitor->trace(m_document); | 600 visitor->trace(m_document); |
| 548 visitor->trace(m_data); | 601 visitor->trace(m_data); |
| 549 visitor->trace(m_callback); | 602 visitor->trace(m_callback); |
| 550 visitor->trace(m_parentFrameTaskRunner); | 603 visitor->trace(m_parentFrameTaskRunner); |
| 604 visitor->trace(m_scriptPromiseResolver); | |
| 551 } | 605 } |
| 552 | 606 |
| 553 } // namespace blink | 607 } // namespace blink |
| OLD | NEW |