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 |