Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp

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

Powered by Google App Engine
This is Rietveld 408576698