Chromium Code Reviews| 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 |