OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. |
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> | 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> |
4 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. | 4 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 14 matching lines...) Expand all Loading... | |
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 #include "core/html/HTMLCanvasElement.h" | 28 #include "core/html/HTMLCanvasElement.h" |
29 | 29 |
30 #include "bindings/core/v8/ExceptionMessages.h" | 30 #include "bindings/core/v8/ExceptionMessages.h" |
31 #include "bindings/core/v8/ExceptionState.h" | 31 #include "bindings/core/v8/ExceptionState.h" |
32 #include "bindings/core/v8/ScriptController.h" | 32 #include "bindings/core/v8/ScriptController.h" |
33 #include "core/HTMLNames.h" | 33 #include "core/HTMLNames.h" |
34 #include "core/InputTypeNames.h" | 34 #include "core/InputTypeNames.h" |
35 #include "core/dom/DOMNodeIds.h" | |
xidachen
2016/11/11 16:54:00
Do we need to include this header here?
Justin Novosad
2016/11/11 22:09:00
Done.
| |
35 #include "core/dom/Document.h" | 36 #include "core/dom/Document.h" |
36 #include "core/dom/Element.h" | 37 #include "core/dom/Element.h" |
37 #include "core/dom/ElementTraversal.h" | 38 #include "core/dom/ElementTraversal.h" |
38 #include "core/dom/ExceptionCode.h" | 39 #include "core/dom/ExceptionCode.h" |
39 #include "core/dom/TaskRunnerHelper.h" | 40 #include "core/dom/TaskRunnerHelper.h" |
40 #include "core/fileapi/File.h" | 41 #include "core/fileapi/File.h" |
41 #include "core/frame/ImageBitmap.h" | 42 #include "core/frame/ImageBitmap.h" |
42 #include "core/frame/LocalFrame.h" | 43 #include "core/frame/LocalFrame.h" |
43 #include "core/frame/Settings.h" | 44 #include "core/frame/Settings.h" |
44 #include "core/frame/UseCounter.h" | 45 #include "core/frame/UseCounter.h" |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 } | 139 } |
139 | 140 |
140 DEFINE_NODE_FACTORY(HTMLCanvasElement) | 141 DEFINE_NODE_FACTORY(HTMLCanvasElement) |
141 | 142 |
142 HTMLCanvasElement::~HTMLCanvasElement() { | 143 HTMLCanvasElement::~HTMLCanvasElement() { |
143 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( | 144 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
144 -m_externallyAllocatedMemory); | 145 -m_externallyAllocatedMemory); |
145 } | 146 } |
146 | 147 |
147 void HTMLCanvasElement::dispose() { | 148 void HTMLCanvasElement::dispose() { |
149 releasePlaceholderFrame(); | |
150 | |
148 if (m_context) { | 151 if (m_context) { |
149 m_context->detachCanvas(); | 152 m_context->detachCanvas(); |
150 m_context = nullptr; | 153 m_context = nullptr; |
151 } | 154 } |
152 m_imageBuffer = nullptr; | 155 m_imageBuffer = nullptr; |
153 } | 156 } |
154 | 157 |
155 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, | 158 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, |
156 const AtomicString& oldValue, | 159 const AtomicString& oldValue, |
157 const AtomicString& value) { | 160 const AtomicString& value) { |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
463 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) | 466 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) |
464 layoutBox()->contentChanged(CanvasChanged); | 467 layoutBox()->contentChanged(CanvasChanged); |
465 } | 468 } |
466 if (hadImageBuffer) | 469 if (hadImageBuffer) |
467 layoutObject->setShouldDoFullPaintInvalidation(); | 470 layoutObject->setShouldDoFullPaintInvalidation(); |
468 } | 471 } |
469 } | 472 } |
470 } | 473 } |
471 | 474 |
472 bool HTMLCanvasElement::paintsIntoCanvasBuffer() const { | 475 bool HTMLCanvasElement::paintsIntoCanvasBuffer() const { |
476 if (placeholderFrame()) | |
477 return false; | |
473 DCHECK(m_context); | 478 DCHECK(m_context); |
474 | |
475 if (!m_context->isAccelerated()) | 479 if (!m_context->isAccelerated()) |
476 return true; | 480 return true; |
477 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) | 481 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) |
478 return false; | 482 return false; |
479 | 483 |
480 return true; | 484 return true; |
481 } | 485 } |
482 | 486 |
483 void HTMLCanvasElement::notifyListenersCanvasChanged() { | 487 void HTMLCanvasElement::notifyListenersCanvasChanged() { |
484 if (m_listeners.size() == 0) | 488 if (m_listeners.size() == 0) |
(...skipping 23 matching lines...) Expand all Loading... | |
508 if (listener->needsNewFrame()) { | 512 if (listener->needsNewFrame()) { |
509 listener->sendNewFrame(image); | 513 listener->sendNewFrame(image); |
510 } | 514 } |
511 } | 515 } |
512 } | 516 } |
513 } | 517 } |
514 | 518 |
515 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r) { | 519 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r) { |
516 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and | 520 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and |
517 // compositing feature. | 521 // compositing feature. |
518 if (!m_context) | 522 if (!m_context && !placeholderFrame()) |
519 return; | 523 return; |
520 | 524 |
521 const ComputedStyle* style = ensureComputedStyle(); | 525 const ComputedStyle* style = ensureComputedStyle(); |
522 SkFilterQuality filterQuality = | 526 SkFilterQuality filterQuality = |
523 (style && style->imageRendering() == ImageRenderingPixelated) | 527 (style && style->imageRendering() == ImageRenderingPixelated) |
524 ? kNone_SkFilterQuality | 528 ? kNone_SkFilterQuality |
525 : kLow_SkFilterQuality; | 529 : kLow_SkFilterQuality; |
526 | 530 |
527 if (is3D()) { | 531 if (is3D()) { |
528 m_context->setFilterQuality(filterQuality); | 532 m_context->setFilterQuality(filterQuality); |
529 } else if (hasImageBuffer()) { | 533 } else if (hasImageBuffer()) { |
530 m_imageBuffer->setFilterQuality(filterQuality); | 534 m_imageBuffer->setFilterQuality(filterQuality); |
531 } | 535 } |
532 | 536 |
533 if (hasImageBuffer() && !m_imageBufferIsClear) | 537 if (hasImageBuffer() && !m_imageBufferIsClear) |
534 PaintTiming::from(document()).markFirstContentfulPaint(); | 538 PaintTiming::from(document()).markFirstContentfulPaint(); |
535 | 539 |
536 if (!paintsIntoCanvasBuffer() && !document().printing()) | 540 if (!paintsIntoCanvasBuffer() && !document().printing()) |
537 return; | 541 return; |
538 | 542 |
543 if (placeholderFrame()) { | |
544 DCHECK(document().printing()); | |
545 context.drawImage(placeholderFrame().get(), pixelSnappedIntRect(r)); | |
546 return; | |
547 } | |
548 | |
539 // TODO(junov): Paint is currently only implemented by ImageBitmap contexts. | 549 // TODO(junov): Paint is currently only implemented by ImageBitmap contexts. |
540 // We could improve the abstraction by making all context types paint | 550 // We could improve the abstraction by making all context types paint |
541 // themselves (implement paint()). | 551 // themselves (implement paint()). |
542 if (m_context->paint(context, pixelSnappedIntRect(r))) | 552 if (m_context->paint(context, pixelSnappedIntRect(r))) |
543 return; | 553 return; |
544 | 554 |
545 m_context->paintRenderingResultsToCanvas(FrontBuffer); | 555 m_context->paintRenderingResultsToCanvas(FrontBuffer); |
546 if (hasImageBuffer()) { | 556 if (hasImageBuffer()) { |
547 if (!context.contextDisabled()) { | 557 if (!context.contextDisabled()) { |
548 SkBlendMode compositeOperator = | 558 SkBlendMode compositeOperator = |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
612 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); | 622 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); |
613 snapshot->readPixels(imageInfo, imageData->data()->data(), | 623 snapshot->readPixels(imageInfo, imageData->data()->data(), |
614 imageInfo.minRowBytes(), 0, 0); | 624 imageInfo.minRowBytes(), 0, 0); |
615 } | 625 } |
616 } | 626 } |
617 return imageData; | 627 return imageData; |
618 } | 628 } |
619 | 629 |
620 imageData = ImageData::create(m_size); | 630 imageData = ImageData::create(m_size); |
621 | 631 |
622 if (!m_context || !imageData) | 632 if ((!m_context || !imageData) && !placeholderFrame()) |
623 return imageData; | 633 return imageData; |
624 | 634 |
625 DCHECK(m_context->is2d()); | 635 DCHECK((m_context && m_context->is2d()) || placeholderFrame()); |
636 sk_sp<SkImage> snapshot; | |
626 if (hasImageBuffer()) { | 637 if (hasImageBuffer()) { |
627 sk_sp<SkImage> snapshot = | 638 snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration, reason); |
628 buffer()->newSkImageSnapshot(PreferNoAcceleration, reason); | 639 } else if (placeholderFrame()) { |
629 if (snapshot) { | 640 snapshot = placeholderFrame()->imageForCurrentFrame(); |
630 SkImageInfo imageInfo = SkImageInfo::Make( | 641 } |
631 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); | 642 |
632 snapshot->readPixels(imageInfo, imageData->data()->data(), | 643 if (snapshot) { |
633 imageInfo.minRowBytes(), 0, 0); | 644 SkImageInfo imageInfo = SkImageInfo::Make( |
634 } | 645 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); |
646 snapshot->readPixels(imageInfo, imageData->data()->data(), | |
647 imageInfo.minRowBytes(), 0, 0); | |
635 } | 648 } |
636 | 649 |
637 return imageData; | 650 return imageData; |
638 } | 651 } |
639 | 652 |
640 String HTMLCanvasElement::toDataURLInternal( | 653 String HTMLCanvasElement::toDataURLInternal( |
641 const String& mimeType, | 654 const String& mimeType, |
642 const double& quality, | 655 const double& quality, |
643 SourceDrawingBuffer sourceBuffer) const { | 656 SourceDrawingBuffer sourceBuffer) const { |
644 if (!isPaintable()) | 657 if (!isPaintable()) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
676 if (!imageData) // allocation failure | 689 if (!imageData) // allocation failure |
677 return String("data:,"); | 690 return String("data:,"); |
678 | 691 |
679 return ImageDataBuffer(imageData->size(), imageData->data()->data()) | 692 return ImageDataBuffer(imageData->size(), imageData->data()->data()) |
680 .toDataURL(encodingMimeType, quality); | 693 .toDataURL(encodingMimeType, quality); |
681 } | 694 } |
682 | 695 |
683 String HTMLCanvasElement::toDataURL(const String& mimeType, | 696 String HTMLCanvasElement::toDataURL(const String& mimeType, |
684 const ScriptValue& qualityArgument, | 697 const ScriptValue& qualityArgument, |
685 ExceptionState& exceptionState) const { | 698 ExceptionState& exceptionState) const { |
686 if (surfaceLayerBridge()) { | |
687 exceptionState.throwDOMException(InvalidStateError, | |
688 "canvas.toDataURL is not allowed for a " | |
689 "canvas that has transferred its control " | |
690 "to offscreen."); | |
691 return String(); | |
692 } | |
693 if (!originClean()) { | 699 if (!originClean()) { |
694 exceptionState.throwSecurityError("Tainted canvases may not be exported."); | 700 exceptionState.throwSecurityError("Tainted canvases may not be exported."); |
695 return String(); | 701 return String(); |
696 } | 702 } |
697 | 703 |
698 double quality = UndefinedQualityValue; | 704 double quality = UndefinedQualityValue; |
699 if (!qualityArgument.isEmpty()) { | 705 if (!qualityArgument.isEmpty()) { |
700 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 706 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
701 if (v8Value->IsNumber()) { | 707 if (v8Value->IsNumber()) { |
702 quality = v8Value.As<v8::Number>()->Value(); | 708 quality = v8Value.As<v8::Number>()->Value(); |
703 } | 709 } |
704 } | 710 } |
705 return toDataURLInternal(mimeType, quality, BackBuffer); | 711 return toDataURLInternal(mimeType, quality, BackBuffer); |
706 } | 712 } |
707 | 713 |
708 void HTMLCanvasElement::toBlob(BlobCallback* callback, | 714 void HTMLCanvasElement::toBlob(BlobCallback* callback, |
709 const String& mimeType, | 715 const String& mimeType, |
710 const ScriptValue& qualityArgument, | 716 const ScriptValue& qualityArgument, |
711 ExceptionState& exceptionState) { | 717 ExceptionState& exceptionState) { |
712 if (surfaceLayerBridge()) { | |
713 exceptionState.throwDOMException(InvalidStateError, | |
714 "canvas.toBlob is not allowed for a " | |
715 "canvas that has transferred its control " | |
716 "to offscreen."); | |
717 return; | |
718 } | |
719 | |
720 if (!originClean()) { | 718 if (!originClean()) { |
721 exceptionState.throwSecurityError("Tainted canvases may not be exported."); | 719 exceptionState.throwSecurityError("Tainted canvases may not be exported."); |
722 return; | 720 return; |
723 } | 721 } |
724 | 722 |
725 if (!isPaintable()) { | 723 if (!isPaintable()) { |
726 // If the canvas element's bitmap has no pixels | 724 // If the canvas element's bitmap has no pixels |
727 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, &document()) | 725 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, &document()) |
728 ->postTask(BLINK_FROM_HERE, | 726 ->postTask(BLINK_FROM_HERE, |
729 WTF::bind(&BlobCallback::handleEvent, | 727 WTF::bind(&BlobCallback::handleEvent, |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1193 if (!width() || !height()) { | 1191 if (!width() || !height()) { |
1194 *status = ZeroSizeCanvasSourceImageStatus; | 1192 *status = ZeroSizeCanvasSourceImageStatus; |
1195 return nullptr; | 1193 return nullptr; |
1196 } | 1194 } |
1197 | 1195 |
1198 if (!isPaintable()) { | 1196 if (!isPaintable()) { |
1199 *status = InvalidSourceImageStatus; | 1197 *status = InvalidSourceImageStatus; |
1200 return nullptr; | 1198 return nullptr; |
1201 } | 1199 } |
1202 | 1200 |
1201 if (placeholderFrame()) { | |
1202 *status = NormalSourceImageStatus; | |
1203 return placeholderFrame(); | |
1204 } | |
1205 | |
1203 if (!m_context) { | 1206 if (!m_context) { |
1204 *status = NormalSourceImageStatus; | 1207 *status = NormalSourceImageStatus; |
1205 return createTransparentImage(size()); | 1208 return createTransparentImage(size()); |
1206 } | 1209 } |
1207 | 1210 |
1208 sk_sp<SkImage> skImage; | 1211 sk_sp<SkImage> skImage; |
1209 if (m_context->is3d()) { | 1212 if (m_context->is3d()) { |
1210 // Because WebGL sources always require making a copy of the back buffer, we | 1213 // Because WebGL sources always require making a copy of the back buffer, we |
1211 // use paintRenderingResultsToCanvas instead of getImage in order to keep a | 1214 // use paintRenderingResultsToCanvas instead of getImage in order to keep a |
1212 // cached copy of the backing in the canvas's ImageBuffer. | 1215 // cached copy of the backing in the canvas's ImageBuffer. |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1357 mojom::blink::OffscreenCanvasSurfacePtr service; | 1360 mojom::blink::OffscreenCanvasSurfacePtr service; |
1358 Platform::current()->interfaceProvider()->getInterface( | 1361 Platform::current()->interfaceProvider()->getInterface( |
1359 mojo::GetProxy(&service)); | 1362 mojo::GetProxy(&service)); |
1360 m_surfaceLayerBridge = | 1363 m_surfaceLayerBridge = |
1361 wrapUnique(new CanvasSurfaceLayerBridge(std::move(service))); | 1364 wrapUnique(new CanvasSurfaceLayerBridge(std::move(service))); |
1362 return m_surfaceLayerBridge->createSurfaceLayer(this->width(), | 1365 return m_surfaceLayerBridge->createSurfaceLayer(this->width(), |
1363 this->height()); | 1366 this->height()); |
1364 } | 1367 } |
1365 | 1368 |
1366 } // namespace blink | 1369 } // namespace blink |
OLD | NEW |