OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2013, Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 #include "modules/imagebitmap/ImageBitmapFactories.h" | |
33 | |
34 #include "RuntimeEnabledFeatures.h" | |
35 #include "V8ImageBitmap.h" | |
36 #include "bindings/v8/ExceptionState.h" | |
37 #include "bindings/v8/ScriptScope.h" | |
38 #include "bindings/v8/ScriptState.h" | |
39 #include "core/html/HTMLCanvasElement.h" | |
40 #include "core/html/HTMLImageElement.h" | |
41 #include "core/html/HTMLVideoElement.h" | |
42 #include "core/html/ImageData.h" | |
43 #include "core/html/canvas/CanvasRenderingContext2D.h" | |
44 #include "core/page/DOMWindow.h" | |
45 #include "core/page/ImageBitmap.h" | |
46 #include "core/platform/SharedBuffer.h" | |
47 #include "core/platform/graphics/BitmapImage.h" | |
48 #include "core/platform/graphics/ImageSource.h" | |
49 #include "core/platform/graphics/skia/NativeImageSkia.h" | |
50 | |
51 namespace WebCore { | |
52 | |
53 static LayoutSize sizeFor(HTMLImageElement* image) | |
54 { | |
55 if (ImageResource* cachedImage = image->cachedImage()) | |
56 return cachedImage->imageSizeForRenderer(image->renderer(), 1.0f); // FI XME: Not sure about this. | |
57 return IntSize(); | |
58 } | |
59 | |
60 static IntSize sizeFor(HTMLVideoElement* video) | |
61 { | |
62 if (MediaPlayer* player = video->player()) | |
63 return player->naturalSize(); | |
64 return IntSize(); | |
65 } | |
66 | |
67 static ScriptObject fulfillImageBitmap(ScriptExecutionContext* context, PassRefP tr<ImageBitmap> imageBitmap) | |
68 { | |
69 // Promises must be enabled. | |
70 ASSERT(RuntimeEnabledFeatures::promiseEnabled()); | |
71 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(conte xt); | |
72 resolver->fulfill(imageBitmap); | |
73 return resolver->promise(); | |
74 } | |
75 | |
76 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLImageElement* image, ExceptionState& es) | |
77 { | |
78 LayoutSize s = sizeFor(image); | |
79 return createImageBitmap(eventTarget, image, 0, 0, s.width(), s.height(), es ); | |
80 } | |
81 | |
82 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLImageElement* image, int sx, int sy, int sw, int sh, ExceptionState& es) | |
83 { | |
84 if (!image) { | |
85 es.throwTypeError(); | |
86 return ScriptObject(); | |
87 } | |
88 if (!image->cachedImage()) { | |
89 es.throwDOMException(InvalidStateError); | |
90 return ScriptObject(); | |
91 } | |
92 if (image->cachedImage()->image()->isSVGImage()) { | |
93 es.throwDOMException(InvalidStateError); | |
94 return ScriptObject(); | |
95 } | |
96 if (!sw || !sh) { | |
97 es.throwDOMException(IndexSizeError); | |
98 return ScriptObject(); | |
99 } | |
100 if (!image->cachedImage()->image()->hasSingleSecurityOrigin()) { | |
101 es.throwDOMException(SecurityError); | |
102 return ScriptObject(); | |
103 } | |
104 if (!image->cachedImage()->passesAccessControlCheck(eventTarget->toDOMWindow ()->document()->securityOrigin()) | |
105 && eventTarget->toDOMWindow()->document()->securityOrigin()->taintsCanvas(im age->src())) { | |
106 es.throwDOMException(SecurityError); | |
107 return ScriptObject(); | |
108 } | |
109 // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 | |
110 return fulfillImageBitmap(eventTarget->scriptExecutionContext(), ImageBitmap ::create(image, IntRect(sx, sy, sw, sh))); | |
111 } | |
112 | |
113 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLVideoElement* video, ExceptionState& es) | |
114 { | |
115 IntSize s = sizeFor(video); | |
116 return createImageBitmap(eventTarget, video, 0, 0, s.width(), s.height(), es ); | |
117 } | |
118 | |
119 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLVideoElement* video, int sx, int sy, int sw, int sh, ExceptionState& es) | |
120 { | |
121 if (!video) { | |
122 es.throwTypeError(); | |
123 return ScriptObject(); | |
124 } | |
125 if (!video->player()) { | |
126 es.throwDOMException(InvalidStateError); | |
127 return ScriptObject(); | |
128 } | |
129 if (video->networkState() == HTMLMediaElement::NETWORK_EMPTY) { | |
130 es.throwDOMException(InvalidStateError); | |
131 return ScriptObject(); | |
132 } | |
133 if (video->player()->readyState() <= MediaPlayer::HaveMetadata) { | |
134 es.throwDOMException(InvalidStateError); | |
135 return ScriptObject(); | |
136 } | |
137 if (!sw || !sh) { | |
138 es.throwDOMException(IndexSizeError); | |
139 return ScriptObject(); | |
140 } | |
141 if (!video->hasSingleSecurityOrigin()) { | |
142 es.throwDOMException(SecurityError); | |
143 return ScriptObject(); | |
144 } | |
145 if (!video->player()->didPassCORSAccessCheck() && eventTarget->toDOMWindow() ->document()->securityOrigin()->taintsCanvas(video->currentSrc())) { | |
146 es.throwDOMException(SecurityError); | |
147 return ScriptObject(); | |
148 } | |
149 // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 | |
150 return fulfillImageBitmap(eventTarget->scriptExecutionContext(), ImageBitmap ::create(video, IntRect(sx, sy, sw, sh))); | |
151 } | |
152 | |
153 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, C anvasRenderingContext2D* context, ExceptionState& es) | |
154 { | |
155 return createImageBitmap(eventTarget, context->canvas(), es); | |
156 } | |
157 | |
158 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, C anvasRenderingContext2D* context, int sx, int sy, int sw, int sh, ExceptionState & es) | |
159 { | |
160 return createImageBitmap(eventTarget, context->canvas(), sx, sy, sw, sh, es) ; | |
161 } | |
162 | |
163 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLCanvasElement* canvas, ExceptionState& es) | |
164 { | |
165 return createImageBitmap(eventTarget, canvas, 0, 0, canvas->width(), canvas- >height(), es); | |
166 } | |
167 | |
168 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, H TMLCanvasElement* canvas, int sx, int sy, int sw, int sh, ExceptionState& es) | |
169 { | |
170 if (!canvas) { | |
171 es.throwTypeError(); | |
172 return ScriptObject(); | |
173 } | |
174 if (!canvas->originClean()) { | |
175 es.throwDOMException(InvalidStateError); | |
176 return ScriptObject(); | |
177 } | |
178 if (!sw || !sh) { | |
179 es.throwDOMException(IndexSizeError); | |
180 return ScriptObject(); | |
181 } | |
182 // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 | |
183 return fulfillImageBitmap(eventTarget->scriptExecutionContext(), ImageBitmap ::create(canvas, IntRect(sx, sy, sw, sh))); | |
184 } | |
185 | |
186 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, B lob* blob, ExceptionState& es) | |
187 { | |
188 // Promises must be enabled. | |
189 ASSERT(RuntimeEnabledFeatures::promiseEnabled()); | |
190 | |
191 if (!blob) { | |
192 es.throwDOMException(TypeError); | |
193 return ScriptObject(); | |
194 } | |
195 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(event Target->scriptExecutionContext()); | |
196 IntRect cropRect(0, 0, 0, 0); | |
197 RefPtr<ImageBitmapLoader> loader = ImageBitmapFactories::ImageBitmapLoader:: create(from(eventTarget->toDOMWindow()), resolver, cropRect); | |
do-not-use
2013/08/14 08:10:29
e.g. You would add loader to m_pendingLoaders here
| |
198 loader->loadBlobAsync(eventTarget->scriptExecutionContext(), blob); | |
199 return resolver->promise(); | |
200 } | |
201 | |
202 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, B lob* blob, int sx, int sy, int sw, int sh, ExceptionState& es) | |
203 { | |
204 // Promises must be enabled. | |
205 ASSERT(RuntimeEnabledFeatures::promiseEnabled()); | |
206 | |
207 if (!blob) { | |
208 es.throwDOMException(TypeError); | |
209 return ScriptObject(); | |
210 } | |
211 if (!sw || !sh) { | |
212 es.throwDOMException(IndexSizeError); | |
213 return ScriptObject(); | |
214 } | |
215 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(event Target->scriptExecutionContext()); | |
216 IntRect cropRect(sx, sy, sw, sh); | |
217 RefPtr<ImageBitmapLoader> loader = ImageBitmapFactories::ImageBitmapLoader:: create(from(eventTarget->toDOMWindow()), resolver, cropRect); | |
218 loader->loadBlobAsync(eventTarget->scriptExecutionContext(), blob); | |
219 return resolver->promise(); | |
220 } | |
221 | |
222 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, I mageData* data, ExceptionState& es) | |
223 { | |
224 return createImageBitmap(eventTarget, data, 0, 0, data->width(), data->heigh t(), es); | |
225 } | |
226 | |
227 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, I mageData* data, int sx, int sy, int sw, int sh, ExceptionState& es) | |
228 { | |
229 if (!data) { | |
230 es.throwTypeError(); | |
231 return ScriptObject(); | |
232 } | |
233 if (!sw || !sh) { | |
234 es.throwDOMException(IndexSizeError); | |
235 return ScriptObject(); | |
236 } | |
237 // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 | |
238 return fulfillImageBitmap(eventTarget->scriptExecutionContext(), ImageBitmap ::create(data, IntRect(sx, sy, sw, sh))); | |
239 } | |
240 | |
241 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, I mageBitmap* bitmap, ExceptionState& es) | |
242 { | |
243 return createImageBitmap(eventTarget, bitmap, 0, 0, bitmap->width(), bitmap- >height(), es); | |
244 } | |
245 | |
246 ScriptObject ImageBitmapFactories::createImageBitmap(EventTarget* eventTarget, I mageBitmap* bitmap, int sx, int sy, int sw, int sh, ExceptionState& es) | |
247 { | |
248 if (!bitmap) { | |
249 es.throwTypeError(); | |
250 return ScriptObject(); | |
251 } | |
252 if (!sw || !sh) { | |
253 es.throwDOMException(IndexSizeError); | |
254 return ScriptObject(); | |
255 } | |
256 // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 | |
257 return fulfillImageBitmap(eventTarget->scriptExecutionContext(), ImageBitmap ::create(bitmap, IntRect(sx, sy, sw, sh))); | |
258 } | |
259 | |
260 const char* ImageBitmapFactories::supplementName() | |
261 { | |
262 return "ImageBitmapFactories"; | |
263 } | |
264 | |
265 ImageBitmapFactories* ImageBitmapFactories::from(DOMWindow* window) | |
266 { | |
267 ImageBitmapFactories* supplement = static_cast<ImageBitmapFactories*>(Supple ment<DOMWindow>::from(window, supplementName())); | |
268 if (!supplement) { | |
269 supplement = new ImageBitmapFactories(); | |
270 provideTo(window, supplementName(), adoptPtr(supplement)); | |
271 } | |
272 return supplement; | |
273 } | |
274 | |
275 void ImageBitmapFactories::didStartLoading(PassRefPtr<ImageBitmapLoader> loader) | |
276 { | |
277 m_pendingLoaders.add(loader); | |
278 } | |
279 | |
280 void ImageBitmapFactories::didFinishLoading(PassRefPtr<ImageBitmapLoader> loader ) | |
281 { | |
282 ASSERT(m_pendingLoaders.contains(loader)); | |
283 m_pendingLoaders.remove(loader); | |
284 } | |
285 | |
286 ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(ImageBitmapFactories* factory, PassRefPtr<ScriptPromiseResolver> resolver, const IntRect& cropRect) | |
287 : m_loader(FileReaderLoader::ReadAsArrayBuffer, this) | |
288 , m_scriptState(ScriptState::current()) | |
289 , m_factory(factory) | |
290 , m_resolver(resolver) | |
291 , m_cropRect(cropRect) | |
292 { | |
293 } | |
294 | |
295 void ImageBitmapFactories::ImageBitmapLoader::loadBlobAsync(ScriptExecutionConte xt* context, Blob* blob) | |
296 { | |
297 m_factory->didStartLoading(this); | |
do-not-use
2013/08/14 08:10:29
I believe the issue was that you were creating a s
| |
298 m_loader.start(context, *blob); | |
299 } | |
300 | |
301 void ImageBitmapFactories::ImageBitmapLoader::rejectPromise() | |
302 { | |
303 ScriptScope scope(m_scriptState); | |
304 m_resolver->reject(ScriptValue::createNull()); | |
305 m_factory->didFinishLoading(this); | |
306 } | |
307 | |
308 void ImageBitmapFactories::ImageBitmapLoader::didFinishLoading() | |
309 { | |
310 if (!m_loader.arrayBufferResult()) { | |
311 rejectPromise(); | |
312 return; | |
313 } | |
314 RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create((char*)m_loader.arr ayBufferResult()->data(), m_loader.arrayBufferResult()->byteLength()); | |
315 | |
316 OwnPtr<ImageSource> source = adoptPtr(new ImageSource()); | |
317 source->setData(sharedBuffer.get(), true); | |
318 RefPtr<NativeImageSkia> imageSkia = source->createFrameAtIndex(0); | |
319 if (!imageSkia) { | |
320 rejectPromise(); | |
321 return; | |
322 } | |
323 | |
324 RefPtr<Image> image = BitmapImage::create(imageSkia); | |
325 if (!image->width() || !image->height()) { | |
326 rejectPromise(); | |
327 return; | |
328 } | |
329 if (!m_cropRect.width() && !m_cropRect.height()) { | |
330 // No cropping variant was called. | |
331 m_cropRect = IntRect(IntPoint(), image->size()); | |
332 } | |
333 | |
334 RefPtr<ImageBitmap> imageBitmap = ImageBitmap::create(image.get(), m_cropRec t); | |
335 ScriptScope scope(m_scriptState); | |
336 m_resolver->fulfill(imageBitmap.release()); | |
337 m_factory->didFinishLoading(this); | |
338 } | |
339 | |
340 void ImageBitmapFactories::ImageBitmapLoader::didFail(FileError::ErrorCode) | |
341 { | |
342 rejectPromise(); | |
343 } | |
344 | |
345 } // namespace WebCore | |
OLD | NEW |