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

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

Issue 2420203002: Implement convertToBlob() in OffscreenCanvas (Closed)
Patch Set: rename function name 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: 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698