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/fileapi/Blob.h" | 7 #include "core/fileapi/Blob.h" |
8 #include "platform/Histogram.h" | |
8 #include "platform/ThreadSafeFunctional.h" | 9 #include "platform/ThreadSafeFunctional.h" |
9 #include "platform/graphics/ImageBuffer.h" | 10 #include "platform/graphics/ImageBuffer.h" |
10 #include "platform/image-encoders/JPEGImageEncoder.h" | 11 #include "platform/image-encoders/JPEGImageEncoder.h" |
11 #include "platform/image-encoders/PNGImageEncoder.h" | 12 #include "platform/image-encoders/PNGImageEncoder.h" |
12 #include "platform/threading/BackgroundTaskRunner.h" | 13 #include "platform/threading/BackgroundTaskRunner.h" |
13 #include "public/platform/Platform.h" | 14 #include "public/platform/Platform.h" |
14 #include "public/platform/WebScheduler.h" | 15 #include "public/platform/WebScheduler.h" |
15 #include "public/platform/WebTaskRunner.h" | 16 #include "public/platform/WebTaskRunner.h" |
16 #include "public/platform/WebThread.h" | 17 #include "public/platform/WebThread.h" |
17 #include "public/platform/WebTraceLocation.h" | 18 #include "public/platform/WebTraceLocation.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 : m_data(data) | 88 : m_data(data) |
88 , m_size(size) | 89 , m_size(size) |
89 , m_mimeType(mimeType) | 90 , m_mimeType(mimeType) |
90 , m_callback(callback) | 91 , m_callback(callback) |
91 { | 92 { |
92 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4)); | 93 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4)); |
93 m_encodedImage = adoptPtr(new Vector<unsigned char>()); | 94 m_encodedImage = adoptPtr(new Vector<unsigned char>()); |
94 m_pixelRowStride = size.width() * NumChannelsPng; | 95 m_pixelRowStride = size.width() * NumChannelsPng; |
95 m_idleTaskStatus = IdleTaskNotSupported; | 96 m_idleTaskStatus = IdleTaskNotSupported; |
96 m_numRowsCompleted = 0; | 97 m_numRowsCompleted = 0; |
98 m_startTime = WTF::monotonicallyIncreasingTime(); | |
97 } | 99 } |
98 | 100 |
99 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() | 101 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() |
100 { | 102 { |
101 } | 103 } |
102 | 104 |
103 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche duling, const double& quality) | 105 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche duling, const double& quality) |
104 { | 106 { |
105 ASSERT(isMainThread()); | 107 ASSERT(isMainThread()); |
106 | 108 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 // Continue encoding from the last completed row | 246 // Continue encoding from the last completed row |
245 if (JPEGImageEncoder::encodeWithPreInitializedState(std::move(m_jpegEncoderS tate), m_data->data(), m_numRowsCompleted)) { | 247 if (JPEGImageEncoder::encodeWithPreInitializedState(std::move(m_jpegEncoderS tate), m_data->data(), m_numRowsCompleted)) { |
246 this->createBlobAndInvokeCallback(); | 248 this->createBlobAndInvokeCallback(); |
247 } else { | 249 } else { |
248 this->createNullAndInvokeCallback(); | 250 this->createNullAndInvokeCallback(); |
249 } | 251 } |
250 | 252 |
251 this->signalAlternativeCodePathFinishedForTesting(); | 253 this->signalAlternativeCodePathFinishedForTesting(); |
252 } | 254 } |
253 | 255 |
256 void CanvasAsyncBlobCreator::recordElapsedTime() | |
257 { | |
258 double elapsedTime = WTF::monotonicallyIncreasingTime() - m_startTime; | |
259 if (m_mimeType == MimeTypePng) { | |
260 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobPNGCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.PNG", 0, 10000000, 50)); | |
261 toBlobPNGCounter.count(elapsedTime * 1000000.0); | |
262 } else if (m_mimeType == MimeTypeJpeg) { | |
263 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobJPEGCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.JPEG", 0, 10000000, 50)); | |
264 toBlobJPEGCounter.count(elapsedTime * 1000000.0); | |
265 } else if (m_mimeType == MimeTypeWebp) { | |
266 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobWEBPCounter, new CustomCountHistogram("Blink.Canvas.ToBlob.WEBP", 0, 10000000, 50)); | |
267 toBlobWEBPCounter.count(elapsedTime * 1000000.0); | |
268 } else { | |
269 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, toBlobUnknownCount er, new CustomCountHistogram("Blink.Canvas.ToBlob.Unknown", 0, 10000000, 50)); | |
270 toBlobUnknownCounter.count(elapsedTime * 1000000.0); | |
271 } | |
272 } | |
273 | |
254 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() | 274 void CanvasAsyncBlobCreator::createBlobAndInvokeCallback() |
255 { | 275 { |
256 ASSERT(isMainThread()); | 276 ASSERT(isMainThread()); |
257 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size (), convertMimeTypeEnumToString(m_mimeType)); | 277 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size (), convertMimeTypeEnumToString(m_mimeType)); |
258 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); | 278 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); |
259 // Since toBlob is done, timeout events are no longer needed. So we clear | 279 // Since toBlob is done, timeout events are no longer needed. So we clear |
260 // non-GC members to allow teardown of CanvasAsyncBlobCreator. | 280 // non-GC members to allow teardown of CanvasAsyncBlobCreator. |
261 m_data.clear(); | 281 m_data.clear(); |
262 m_callback.clear(); | 282 m_callback.clear(); |
283 recordElapsedTime(); | |
263 } | 284 } |
264 | 285 |
265 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() | 286 void CanvasAsyncBlobCreator::createNullAndInvokeCallback() |
266 { | 287 { |
267 ASSERT(isMainThread()); | 288 ASSERT(isMainThread()); |
268 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 289 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H ERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
269 // Since toBlob is done (failed), timeout events are no longer needed. So we | 290 // Since toBlob is done (failed), timeout events are no longer needed. So we |
270 // clear non-GC members to allow teardown of CanvasAsyncBlobCreator. | 291 // clear non-GC members to allow teardown of CanvasAsyncBlobCreator. |
271 m_data.clear(); | 292 m_data.clear(); |
272 m_callback.clear(); | 293 m_callback.clear(); |
294 recordElapsedTime(); | |
Justin Novosad
2016/06/06 15:16:03
The failure case should not be recording to the sa
| |
273 } | 295 } |
274 | 296 |
275 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) | 297 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) |
276 { | 298 { |
277 ASSERT(!isMainThread()); | 299 ASSERT(!isMainThread()); |
278 ASSERT(m_mimeType == MimeTypeWebp); | 300 ASSERT(m_mimeType == MimeTypeWebp); |
279 | 301 |
280 if (!ImageDataBuffer(m_size, m_data->data()).encodeImage("image/webp", quali ty, m_encodedImage.get())) { | 302 if (!ImageDataBuffer(m_size, m_data->data()).encodeImage("image/webp", quali ty, m_encodedImage.get())) { |
281 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR OM_HERE, threadSafeBind(&BlobCallback::handleEvent, wrapCrossThreadPersistent(m_ callback.get()), nullptr)); | 303 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR OM_HERE, threadSafeBind(&BlobCallback::handleEvent, wrapCrossThreadPersistent(m_ callback.get()), nullptr)); |
282 return; | 304 return; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); | 359 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); |
338 this->signalAlternativeCodePathFinishedForTesting(); | 360 this->signalAlternativeCodePathFinishedForTesting(); |
339 } | 361 } |
340 | 362 |
341 } | 363 } |
342 | 364 |
343 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() | 365 void CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent() |
344 { | 366 { |
345 ASSERT(m_idleTaskStatus != IdleTaskNotStarted); | 367 ASSERT(m_idleTaskStatus != IdleTaskNotStarted); |
346 | 368 |
369 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, idleTaskCompleteTimeou tDelayHistogram, new EnumerationHistogram("Canvas.ToBlob.IdleTaskCompleteTimeout Delay", NumberOfMimeTypeSupported)); | |
Justin Novosad
2016/06/06 15:16:03
This histogram does not provide very significant i
| |
370 idleTaskCompleteTimeoutDelayHistogram.count(m_mimeType); | |
371 | |
347 if (m_idleTaskStatus == IdleTaskStarted) { | 372 if (m_idleTaskStatus == IdleTaskStarted) { |
348 // It has taken too long to complete for the idle task. | 373 // It has taken too long to complete for the idle task. |
349 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; | 374 m_idleTaskStatus = IdleTaskSwitchedToMainThreadTask; |
350 signalTaskSwitchInCompleteTimeoutEventForTesting(); | 375 signalTaskSwitchInCompleteTimeoutEventForTesting(); |
351 | 376 |
352 if (m_mimeType == MimeTypePng) { | 377 if (m_mimeType == MimeTypePng) { |
353 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this)); | 378 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, this)); |
354 } else { | 379 } else { |
355 ASSERT(m_mimeType == MimeTypeJpeg); | 380 ASSERT(m_mimeType == MimeTypeJpeg); |
356 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this)); | 381 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLIN K_FROM_HERE, bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, this)); |
357 } | 382 } |
358 } else { | 383 } else { |
359 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); | 384 ASSERT(m_idleTaskStatus == IdleTaskFailed || m_idleTaskStatus == IdleTas kCompleted); |
360 this->signalAlternativeCodePathFinishedForTesting(); | 385 this->signalAlternativeCodePathFinishedForTesting(); |
361 } | 386 } |
362 } | 387 } |
363 | 388 |
364 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread(const WebTraceLocation& location, std::unique_ptr<SameThreadClosure> task, double delayMs) | 389 void CanvasAsyncBlobCreator::postDelayedTaskToMainThread(const WebTraceLocation& location, std::unique_ptr<SameThreadClosure> task, double delayMs) |
365 { | 390 { |
366 DCHECK(isMainThread()); | 391 DCHECK(isMainThread()); |
367 Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(locat ion, std::move(task), delayMs); | 392 Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(locat ion, std::move(task), delayMs); |
368 } | 393 } |
369 | 394 |
370 } // namespace blink | 395 } // namespace blink |
OLD | NEW |