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 "CanvasAsyncBlobCreator.h" | 5 #include "CanvasAsyncBlobCreator.h" |
6 | 6 |
7 #include "core/fileapi/Blob.h" | 7 #include "core/fileapi/Blob.h" |
8 #include "platform/ThreadSafeFunctional.h" | 8 #include "platform/ThreadSafeFunctional.h" |
9 #include "platform/graphics/ImageBuffer.h" | 9 #include "platform/graphics/ImageBuffer.h" |
10 #include "platform/heap/Handle.h" | 10 #include "platform/heap/Handle.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 const int NumChannelsPng = 4; | 27 const int NumChannelsPng = 4; |
28 const int LongTaskImageSizeThreshold = 1000 * 1000; // The max image size we exp
ect to encode in 14ms on Linux in PNG format | 28 const int LongTaskImageSizeThreshold = 1000 * 1000; // The max image size we exp
ect to encode in 14ms on Linux in PNG format |
29 | 29 |
30 bool isDeadlineNearOrPassed(double deadlineSeconds) | 30 bool isDeadlineNearOrPassed(double deadlineSeconds) |
31 { | 31 { |
32 return (deadlineSeconds - SlackBeforeDeadline - monotonicallyIncreasingTime(
) <= 0); | 32 return (deadlineSeconds - SlackBeforeDeadline - monotonicallyIncreasingTime(
) <= 0); |
33 } | 33 } |
34 | 34 |
35 } // anonymous namespace | 35 } // anonymous namespace |
36 | 36 |
37 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::create(DOMUint8ClampedArray* unp
remultipliedRGBAImageData, const String& mimeType, const IntSize& size, BlobCall
back* callback) | 37 PassRefPtr<CanvasAsyncBlobCreator> CanvasAsyncBlobCreator::create(PassRefPtr<DOM
Uint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const I
ntSize& size, BlobCallback* callback) |
38 { | 38 { |
39 return new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, mimeType, si
ze, callback); | 39 RefPtr<CanvasAsyncBlobCreator> asyncBlobCreator = adoptRef(new CanvasAsyncBl
obCreator(unpremultipliedRGBAImageData, mimeType, size, callback)); |
| 40 return asyncBlobCreator.release(); |
40 } | 41 } |
41 | 42 |
42 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data, const
String& mimeType, const IntSize& size, BlobCallback* callback) | 43 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(PassRefPtr<DOMUint8ClampedArray>
data, const String& mimeType, const IntSize& size, BlobCallback* callback) |
43 : m_data(data) | 44 : m_data(data) |
44 , m_size(size) | 45 , m_size(size) |
45 , m_mimeType(mimeType) | 46 , m_mimeType(mimeType) |
46 , m_callback(callback) | 47 , m_callback(callback) |
47 { | 48 { |
48 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4)); | 49 ASSERT(m_data->length() == (unsigned) (size.height() * size.width() * 4)); |
49 m_encodedImage = adoptPtr(new Vector<unsigned char>()); | 50 m_encodedImage = adoptPtr(new Vector<unsigned char>()); |
50 m_pixelRowStride = size.width() * NumChannelsPng; | 51 m_pixelRowStride = size.width() * NumChannelsPng; |
51 m_numRowsCompleted = 0; | 52 m_numRowsCompleted = 0; |
52 } | 53 } |
53 | 54 |
54 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() | 55 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() |
55 { | 56 { |
56 } | 57 } |
57 | 58 |
58 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) | 59 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) |
59 { | 60 { |
60 // TODO: async blob creation should be supported in worker_pool threads as w
ell. but right now blink does not have that | 61 // TODO: async blob creation should be supported in worker_pool threads as w
ell. but right now blink does not have that |
61 ASSERT(isMainThread()); | 62 ASSERT(isMainThread()); |
62 | 63 |
63 // Make self-reference to keep this object alive until the final task comple
tes | 64 // Make self-reference to keep this object alive until the final task comple
tes |
64 m_keepAlive = this; | 65 m_selfRef = this; |
65 | 66 |
66 // At the time being, progressive encoding is only applicable to png image f
ormat, | 67 // At the time being, progressive encoding is only applicable to png image f
ormat, |
67 // and thus idle tasks scheduling can only be applied to png image format. | 68 // and thus idle tasks scheduling can only be applied to png image format. |
68 // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.co
m/571398, crbug.com/571399) | 69 // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.co
m/571398, crbug.com/571399) |
69 if (canUseIdlePeriodScheduling) { | 70 if (canUseIdlePeriodScheduling) { |
70 ASSERT(m_mimeType == "image/png"); | 71 ASSERT(m_mimeType == "image/png"); |
71 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); | 72 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); |
72 } else if (m_mimeType == "image/jpeg") { | 73 } else if (m_mimeType == "image/jpeg") { |
73 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); | 74 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); |
74 } else { | 75 } else { |
75 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt
h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa
sk : BackgroundTaskRunner::TaskSizeShortRunningTask; | 76 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt
h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa
sk : BackgroundTaskRunner::TaskSizeShortRunningTask; |
76 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe
Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess
(this), quality), taskSize); | 77 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe
Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess
(this), quality), taskSize); |
77 } | 78 } |
78 } | 79 } |
79 | 80 |
80 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) | 81 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) |
81 { | 82 { |
82 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); | 83 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); |
83 if (!m_jpegEncoderState) { | 84 if (!m_jpegEncoderState) { |
84 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 85 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
85 m_keepAlive.clear(); | 86 m_selfRef.clear(); |
86 return; | 87 return; |
87 } | 88 } |
88 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width()
>= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask :
BackgroundTaskRunner::TaskSizeShortRunningTask; | 89 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width()
>= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask :
BackgroundTaskRunner::TaskSizeShortRunningTask; |
89 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind
(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(thi
s), quality), taskSize); | 90 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind
(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(thi
s), quality), taskSize); |
90 } | 91 } |
91 | 92 |
92 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) | 93 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) |
93 { | 94 { |
94 ASSERT(isMainThread()); | 95 ASSERT(isMainThread()); |
95 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); | 96 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); |
96 if (!m_pngEncoderState) { | 97 if (!m_pngEncoderState) { |
97 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 98 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
98 m_keepAlive.clear(); | 99 m_selfRef.clear(); |
99 return; | 100 return; |
100 } | 101 } |
101 | 102 |
102 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); | 103 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); |
103 } | 104 } |
104 | 105 |
105 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() | 106 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() |
106 { | 107 { |
107 ASSERT(isMainThread()); | 108 ASSERT(isMainThread()); |
108 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); | 109 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 } | 157 } |
157 | 158 |
158 scheduleCreateBlobAndCallOnMainThread(); | 159 scheduleCreateBlobAndCallOnMainThread(); |
159 } | 160 } |
160 | 161 |
161 void CanvasAsyncBlobCreator::clearSelfReference() | 162 void CanvasAsyncBlobCreator::clearSelfReference() |
162 { | 163 { |
163 // Some persistent members in CanvasAsyncBlobCreator can only be destroyed | 164 // Some persistent members in CanvasAsyncBlobCreator can only be destroyed |
164 // on the thread that creates them. In this case, it's the main thread. | 165 // on the thread that creates them. In this case, it's the main thread. |
165 ASSERT(isMainThread()); | 166 ASSERT(isMainThread()); |
166 m_keepAlive.clear(); | 167 m_selfRef.clear(); |
167 } | 168 } |
168 | 169 |
169 void CanvasAsyncBlobCreator::scheduleCreateBlobAndCallOnMainThread() | 170 void CanvasAsyncBlobCreator::scheduleCreateBlobAndCallOnMainThread() |
170 { | 171 { |
171 ASSERT(!isMainThread()); | 172 ASSERT(!isMainThread()); |
172 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); | 173 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); |
173 } | 174 } |
174 | 175 |
175 void CanvasAsyncBlobCreator::scheduleCreateNullptrAndCallOnMainThread() | 176 void CanvasAsyncBlobCreator::scheduleCreateNullptrAndCallOnMainThread() |
176 { | 177 { |
177 ASSERT(!isMainThread()); | 178 ASSERT(!isMainThread()); |
178 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&BlobCallback::handleEvent, m_callback.get(), nullptr)); | 179 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&BlobCallback::handleEvent, m_callback.get(), nullptr)); |
179 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThrea
dAccess(this))); | 180 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThrea
dAccess(this))); |
180 } | 181 } |
181 | 182 |
182 } // namespace blink | 183 } // namespace blink |
OLD | NEW |