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 "core/html/canvas/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" | |
11 #include "platform/image-encoders/skia/JPEGImageEncoder.h" | 10 #include "platform/image-encoders/skia/JPEGImageEncoder.h" |
12 #include "platform/image-encoders/skia/PNGImageEncoder.h" | 11 #include "platform/image-encoders/skia/PNGImageEncoder.h" |
13 #include "platform/threading/BackgroundTaskRunner.h" | 12 #include "platform/threading/BackgroundTaskRunner.h" |
14 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" |
15 #include "public/platform/WebScheduler.h" | 14 #include "public/platform/WebScheduler.h" |
16 #include "public/platform/WebTaskRunner.h" | 15 #include "public/platform/WebTaskRunner.h" |
17 #include "public/platform/WebThread.h" | 16 #include "public/platform/WebThread.h" |
18 #include "public/platform/WebTraceLocation.h" | 17 #include "public/platform/WebTraceLocation.h" |
19 #include "wtf/CurrentTime.h" | 18 #include "wtf/CurrentTime.h" |
20 #include "wtf/Functional.h" | 19 #include "wtf/Functional.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 | 52 |
54 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() | 53 CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() |
55 { | 54 { |
56 } | 55 } |
57 | 56 |
58 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) | 57 void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodSche
duling, double quality) |
59 { | 58 { |
60 // TODO: async blob creation should be supported in worker_pool threads as w
ell. but right now blink does not have that | 59 // 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()); | 60 ASSERT(isMainThread()); |
62 | 61 |
63 // Make self-reference to keep this object alive until the final task comple
tes | |
64 m_keepAlive = this; | |
65 | |
66 // At the time being, progressive encoding is only applicable to png image f
ormat, | 62 // 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. | 63 // 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) | 64 // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.co
m/571398, crbug.com/571399) |
69 if (canUseIdlePeriodScheduling) { | 65 if (canUseIdlePeriodScheduling) { |
70 ASSERT(m_mimeType == "image/png"); | 66 ASSERT(m_mimeType == "image/png"); |
71 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); | 67 Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_
HERE, bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); |
72 } else if (m_mimeType == "image/jpeg") { | 68 } else if (m_mimeType == "image/jpeg") { |
73 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); | 69 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::initiateJpegEncoding, this, quality)); |
74 } else { | 70 } else { |
75 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.widt
h() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTa
sk : BackgroundTaskRunner::TaskSizeShortRunningTask; | 71 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); | 72 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafe
Bind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess
(this), quality), taskSize); |
77 } | 73 } |
78 } | 74 } |
79 | 75 |
80 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) | 76 void CanvasAsyncBlobCreator::initiateJpegEncoding(const double& quality) |
81 { | 77 { |
82 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); | 78 m_jpegEncoderState = JPEGImageEncoderState::create(m_size, quality, m_encode
dImage.get()); |
83 if (!m_jpegEncoderState) { | 79 if (!m_jpegEncoderState) { |
84 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 80 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
85 m_keepAlive.clear(); | |
86 return; | 81 return; |
87 } | 82 } |
88 BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width()
>= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask :
BackgroundTaskRunner::TaskSizeShortRunningTask; | 83 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); | 84 BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind
(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(thi
s), quality), taskSize); |
90 } | 85 } |
91 | 86 |
92 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) | 87 void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds) |
93 { | 88 { |
94 ASSERT(isMainThread()); | 89 ASSERT(isMainThread()); |
95 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); | 90 m_pngEncoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get(
)); |
96 if (!m_pngEncoderState) { | 91 if (!m_pngEncoderState) { |
97 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); | 92 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr)); |
98 m_keepAlive.clear(); | |
99 return; | 93 return; |
100 } | 94 } |
101 | 95 |
102 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); | 96 CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds); |
103 } | 97 } |
104 | 98 |
105 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() | 99 void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng() |
106 { | 100 { |
107 ASSERT(isMainThread()); | 101 ASSERT(isMainThread()); |
108 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); | 102 Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_H
ERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this)); |
109 } | 103 } |
110 | 104 |
111 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) | 105 void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds) |
112 { | 106 { |
113 ASSERT(isMainThread()); | 107 ASSERT(isMainThread()); |
114 unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCo
mpleted; | 108 unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCo
mpleted; |
115 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { | 109 for (int y = m_numRowsCompleted; y < m_size.height(); ++y) { |
116 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 110 if (isDeadlineNearOrPassed(deadlineSeconds)) { |
117 m_numRowsCompleted = y; | 111 m_numRowsCompleted = y; |
118 CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng(); | 112 CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng(); |
119 return; | 113 return; |
120 } | 114 } |
121 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); | 115 PNGImageEncoder::writeOneRowToPng(inputPixels, m_pngEncoderState.get()); |
122 inputPixels += m_pixelRowStride; | 116 inputPixels += m_pixelRowStride; |
123 } | 117 } |
124 m_numRowsCompleted = m_size.height(); | 118 m_numRowsCompleted = m_size.height(); |
125 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); | 119 PNGImageEncoder::finalizePng(m_pngEncoderState.get()); |
126 | 120 |
127 if (isDeadlineNearOrPassed(deadlineSeconds)) { | 121 if (isDeadlineNearOrPassed(deadlineSeconds)) |
128 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::createBlobAndCall, this)); | 122 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, bind(&CanvasAsyncBlobCreator::createBlobAndCall, this)); |
129 } else { | 123 else |
130 this->createBlobAndCall(); | 124 this->createBlobAndCall(); |
131 } | |
132 } | 125 } |
133 | 126 |
134 void CanvasAsyncBlobCreator::createBlobAndCall() | 127 void CanvasAsyncBlobCreator::createBlobAndCall() |
135 { | 128 { |
136 ASSERT(isMainThread()); | 129 ASSERT(isMainThread()); |
137 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size
(), m_mimeType); | 130 Blob* resultBlob = Blob::create(m_encodedImage->data(), m_encodedImage->size
(), m_mimeType); |
138 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); | 131 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, bind(&BlobCallback::handleEvent, m_callback, resultBlob)); |
139 clearSelfReference(); // self-destruct once job is done. | |
140 } | 132 } |
141 | 133 |
142 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) | 134 void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) |
143 { | 135 { |
144 ASSERT(!isMainThread()); | 136 ASSERT(!isMainThread()); |
145 | 137 |
146 bool success; | 138 bool success; |
147 if (m_mimeType == "image/jpeg") { | 139 if (m_mimeType == "image/jpeg") |
148 success = JPEGImageEncoder::encodeWithPreInitializedState(m_jpegEncoderS
tate.release(), m_data->data()); | 140 success = JPEGImageEncoder::encodeWithPreInitializedState(m_jpegEncoderS
tate.release(), m_data->data()); |
149 } else { | 141 else |
150 success = ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType
, quality, m_encodedImage.get()); | 142 success = ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType
, quality, m_encodedImage.get()); |
151 } | |
152 | 143 |
153 if (!success) { | 144 if (!success) { |
154 scheduleCreateNullptrAndCallOnMainThread(); | 145 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&BlobCallback::handleEvent, m_callback.get(), nullptr)); |
155 return; | 146 return; |
156 } | 147 } |
157 | 148 |
158 scheduleCreateBlobAndCallOnMainThread(); | |
159 } | |
160 | |
161 void CanvasAsyncBlobCreator::clearSelfReference() | |
162 { | |
163 // 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 ASSERT(isMainThread()); | |
166 m_keepAlive.clear(); | |
167 } | |
168 | |
169 void CanvasAsyncBlobCreator::scheduleCreateBlobAndCallOnMainThread() | |
170 { | |
171 ASSERT(!isMainThread()); | |
172 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); | 149 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_H
ERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThread
Access(this))); |
173 } | 150 } |
174 | 151 |
175 void CanvasAsyncBlobCreator::scheduleCreateNullptrAndCallOnMainThread() | |
176 { | |
177 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(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThrea
dAccess(this))); | |
180 } | |
181 | |
182 } // namespace blink | 152 } // namespace blink |
OLD | NEW |