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 |