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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 } | 138 } |
139 | 139 |
140 DEFINE_NODE_FACTORY(HTMLCanvasElement) | 140 DEFINE_NODE_FACTORY(HTMLCanvasElement) |
141 | 141 |
142 HTMLCanvasElement::~HTMLCanvasElement() { | 142 HTMLCanvasElement::~HTMLCanvasElement() { |
143 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( | 143 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory( |
144 -m_externallyAllocatedMemory); | 144 -m_externallyAllocatedMemory); |
145 } | 145 } |
146 | 146 |
147 void HTMLCanvasElement::dispose() { | 147 void HTMLCanvasElement::dispose() { |
| 148 releasePlaceholderFrame(); |
| 149 |
148 if (m_context) { | 150 if (m_context) { |
149 m_context->detachCanvas(); | 151 m_context->detachCanvas(); |
150 m_context = nullptr; | 152 m_context = nullptr; |
151 } | 153 } |
152 m_imageBuffer = nullptr; | 154 m_imageBuffer = nullptr; |
153 } | 155 } |
154 | 156 |
155 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, | 157 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, |
156 const AtomicString& oldValue, | 158 const AtomicString& oldValue, |
157 const AtomicString& value) { | 159 const AtomicString& value) { |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) | 465 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) |
464 layoutBox()->contentChanged(CanvasChanged); | 466 layoutBox()->contentChanged(CanvasChanged); |
465 } | 467 } |
466 if (hadImageBuffer) | 468 if (hadImageBuffer) |
467 layoutObject->setShouldDoFullPaintInvalidation(); | 469 layoutObject->setShouldDoFullPaintInvalidation(); |
468 } | 470 } |
469 } | 471 } |
470 } | 472 } |
471 | 473 |
472 bool HTMLCanvasElement::paintsIntoCanvasBuffer() const { | 474 bool HTMLCanvasElement::paintsIntoCanvasBuffer() const { |
| 475 if (placeholderFrame()) |
| 476 return false; |
473 DCHECK(m_context); | 477 DCHECK(m_context); |
474 | |
475 if (!m_context->isAccelerated()) | 478 if (!m_context->isAccelerated()) |
476 return true; | 479 return true; |
477 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) | 480 if (layoutBox() && layoutBox()->hasAcceleratedCompositing()) |
478 return false; | 481 return false; |
479 | 482 |
480 return true; | 483 return true; |
481 } | 484 } |
482 | 485 |
483 void HTMLCanvasElement::notifyListenersCanvasChanged() { | 486 void HTMLCanvasElement::notifyListenersCanvasChanged() { |
484 if (m_listeners.size() == 0) | 487 if (m_listeners.size() == 0) |
(...skipping 23 matching lines...) Expand all Loading... |
508 if (listener->needsNewFrame()) { | 511 if (listener->needsNewFrame()) { |
509 listener->sendNewFrame(image); | 512 listener->sendNewFrame(image); |
510 } | 513 } |
511 } | 514 } |
512 } | 515 } |
513 } | 516 } |
514 | 517 |
515 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r) { | 518 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r) { |
516 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and | 519 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and |
517 // compositing feature. | 520 // compositing feature. |
518 if (!m_context) | 521 if (!m_context && !placeholderFrame()) |
519 return; | 522 return; |
520 | 523 |
521 const ComputedStyle* style = ensureComputedStyle(); | 524 const ComputedStyle* style = ensureComputedStyle(); |
522 SkFilterQuality filterQuality = | 525 SkFilterQuality filterQuality = |
523 (style && style->imageRendering() == ImageRenderingPixelated) | 526 (style && style->imageRendering() == ImageRenderingPixelated) |
524 ? kNone_SkFilterQuality | 527 ? kNone_SkFilterQuality |
525 : kLow_SkFilterQuality; | 528 : kLow_SkFilterQuality; |
526 | 529 |
527 if (is3D()) { | 530 if (is3D()) { |
528 m_context->setFilterQuality(filterQuality); | 531 m_context->setFilterQuality(filterQuality); |
529 } else if (hasImageBuffer()) { | 532 } else if (hasImageBuffer()) { |
530 m_imageBuffer->setFilterQuality(filterQuality); | 533 m_imageBuffer->setFilterQuality(filterQuality); |
531 } | 534 } |
532 | 535 |
533 if (hasImageBuffer() && !m_imageBufferIsClear) | 536 if (hasImageBuffer() && !m_imageBufferIsClear) |
534 PaintTiming::from(document()).markFirstContentfulPaint(); | 537 PaintTiming::from(document()).markFirstContentfulPaint(); |
535 | 538 |
536 if (!paintsIntoCanvasBuffer() && !document().printing()) | 539 if (!paintsIntoCanvasBuffer() && !document().printing()) |
537 return; | 540 return; |
538 | 541 |
| 542 if (placeholderFrame()) { |
| 543 DCHECK(document().printing()); |
| 544 context.drawImage(placeholderFrame().get(), pixelSnappedIntRect(r)); |
| 545 return; |
| 546 } |
| 547 |
539 // TODO(junov): Paint is currently only implemented by ImageBitmap contexts. | 548 // TODO(junov): Paint is currently only implemented by ImageBitmap contexts. |
540 // We could improve the abstraction by making all context types paint | 549 // We could improve the abstraction by making all context types paint |
541 // themselves (implement paint()). | 550 // themselves (implement paint()). |
542 if (m_context->paint(context, pixelSnappedIntRect(r))) | 551 if (m_context->paint(context, pixelSnappedIntRect(r))) |
543 return; | 552 return; |
544 | 553 |
545 m_context->paintRenderingResultsToCanvas(FrontBuffer); | 554 m_context->paintRenderingResultsToCanvas(FrontBuffer); |
546 if (hasImageBuffer()) { | 555 if (hasImageBuffer()) { |
547 if (!context.contextDisabled()) { | 556 if (!context.contextDisabled()) { |
548 SkBlendMode compositeOperator = | 557 SkBlendMode compositeOperator = |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); | 621 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); |
613 snapshot->readPixels(imageInfo, imageData->data()->data(), | 622 snapshot->readPixels(imageInfo, imageData->data()->data(), |
614 imageInfo.minRowBytes(), 0, 0); | 623 imageInfo.minRowBytes(), 0, 0); |
615 } | 624 } |
616 } | 625 } |
617 return imageData; | 626 return imageData; |
618 } | 627 } |
619 | 628 |
620 imageData = ImageData::create(m_size); | 629 imageData = ImageData::create(m_size); |
621 | 630 |
622 if (!m_context || !imageData) | 631 if ((!m_context || !imageData) && !placeholderFrame()) |
623 return imageData; | 632 return imageData; |
624 | 633 |
625 DCHECK(m_context->is2d()); | 634 DCHECK((m_context && m_context->is2d()) || placeholderFrame()); |
| 635 sk_sp<SkImage> snapshot; |
626 if (hasImageBuffer()) { | 636 if (hasImageBuffer()) { |
627 sk_sp<SkImage> snapshot = | 637 snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration, reason); |
628 buffer()->newSkImageSnapshot(PreferNoAcceleration, reason); | 638 } else if (placeholderFrame()) { |
629 if (snapshot) { | 639 snapshot = placeholderFrame()->imageForCurrentFrame(); |
630 SkImageInfo imageInfo = SkImageInfo::Make( | 640 } |
631 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); | 641 |
632 snapshot->readPixels(imageInfo, imageData->data()->data(), | 642 if (snapshot) { |
633 imageInfo.minRowBytes(), 0, 0); | 643 SkImageInfo imageInfo = SkImageInfo::Make( |
634 } | 644 width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); |
| 645 snapshot->readPixels(imageInfo, imageData->data()->data(), |
| 646 imageInfo.minRowBytes(), 0, 0); |
635 } | 647 } |
636 | 648 |
637 return imageData; | 649 return imageData; |
638 } | 650 } |
639 | 651 |
640 String HTMLCanvasElement::toDataURLInternal( | 652 String HTMLCanvasElement::toDataURLInternal( |
641 const String& mimeType, | 653 const String& mimeType, |
642 const double& quality, | 654 const double& quality, |
643 SourceDrawingBuffer sourceBuffer) const { | 655 SourceDrawingBuffer sourceBuffer) const { |
644 if (!isPaintable()) | 656 if (!isPaintable()) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 if (!imageData) // allocation failure | 688 if (!imageData) // allocation failure |
677 return String("data:,"); | 689 return String("data:,"); |
678 | 690 |
679 return ImageDataBuffer(imageData->size(), imageData->data()->data()) | 691 return ImageDataBuffer(imageData->size(), imageData->data()->data()) |
680 .toDataURL(encodingMimeType, quality); | 692 .toDataURL(encodingMimeType, quality); |
681 } | 693 } |
682 | 694 |
683 String HTMLCanvasElement::toDataURL(const String& mimeType, | 695 String HTMLCanvasElement::toDataURL(const String& mimeType, |
684 const ScriptValue& qualityArgument, | 696 const ScriptValue& qualityArgument, |
685 ExceptionState& exceptionState) const { | 697 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()) { | 698 if (!originClean()) { |
694 exceptionState.throwSecurityError("Tainted canvases may not be exported."); | 699 exceptionState.throwSecurityError("Tainted canvases may not be exported."); |
695 return String(); | 700 return String(); |
696 } | 701 } |
697 | 702 |
698 double quality = UndefinedQualityValue; | 703 double quality = UndefinedQualityValue; |
699 if (!qualityArgument.isEmpty()) { | 704 if (!qualityArgument.isEmpty()) { |
700 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 705 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
701 if (v8Value->IsNumber()) { | 706 if (v8Value->IsNumber()) { |
702 quality = v8Value.As<v8::Number>()->Value(); | 707 quality = v8Value.As<v8::Number>()->Value(); |
703 } | 708 } |
704 } | 709 } |
705 return toDataURLInternal(mimeType, quality, BackBuffer); | 710 return toDataURLInternal(mimeType, quality, BackBuffer); |
706 } | 711 } |
707 | 712 |
708 void HTMLCanvasElement::toBlob(BlobCallback* callback, | 713 void HTMLCanvasElement::toBlob(BlobCallback* callback, |
709 const String& mimeType, | 714 const String& mimeType, |
710 const ScriptValue& qualityArgument, | 715 const ScriptValue& qualityArgument, |
711 ExceptionState& exceptionState) { | 716 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()) { | 717 if (!originClean()) { |
721 exceptionState.throwSecurityError("Tainted canvases may not be exported."); | 718 exceptionState.throwSecurityError("Tainted canvases may not be exported."); |
722 return; | 719 return; |
723 } | 720 } |
724 | 721 |
725 if (!isPaintable()) { | 722 if (!isPaintable()) { |
726 // If the canvas element's bitmap has no pixels | 723 // If the canvas element's bitmap has no pixels |
727 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, &document()) | 724 TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, &document()) |
728 ->postTask(BLINK_FROM_HERE, | 725 ->postTask(BLINK_FROM_HERE, |
729 WTF::bind(&BlobCallback::handleEvent, | 726 WTF::bind(&BlobCallback::handleEvent, |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1193 if (!width() || !height()) { | 1190 if (!width() || !height()) { |
1194 *status = ZeroSizeCanvasSourceImageStatus; | 1191 *status = ZeroSizeCanvasSourceImageStatus; |
1195 return nullptr; | 1192 return nullptr; |
1196 } | 1193 } |
1197 | 1194 |
1198 if (!isPaintable()) { | 1195 if (!isPaintable()) { |
1199 *status = InvalidSourceImageStatus; | 1196 *status = InvalidSourceImageStatus; |
1200 return nullptr; | 1197 return nullptr; |
1201 } | 1198 } |
1202 | 1199 |
| 1200 if (placeholderFrame()) { |
| 1201 *status = NormalSourceImageStatus; |
| 1202 return placeholderFrame(); |
| 1203 } |
| 1204 |
1203 if (!m_context) { | 1205 if (!m_context) { |
1204 *status = NormalSourceImageStatus; | 1206 *status = NormalSourceImageStatus; |
1205 return createTransparentImage(size()); | 1207 return createTransparentImage(size()); |
1206 } | 1208 } |
1207 | 1209 |
1208 sk_sp<SkImage> skImage; | 1210 sk_sp<SkImage> skImage; |
1209 if (m_context->is3d()) { | 1211 if (m_context->is3d()) { |
1210 // Because WebGL sources always require making a copy of the back buffer, we | 1212 // Because WebGL sources always require making a copy of the back buffer, we |
1211 // use paintRenderingResultsToCanvas instead of getImage in order to keep a | 1213 // use paintRenderingResultsToCanvas instead of getImage in order to keep a |
1212 // cached copy of the backing in the canvas's ImageBuffer. | 1214 // 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; | 1359 mojom::blink::OffscreenCanvasSurfacePtr service; |
1358 Platform::current()->interfaceProvider()->getInterface( | 1360 Platform::current()->interfaceProvider()->getInterface( |
1359 mojo::GetProxy(&service)); | 1361 mojo::GetProxy(&service)); |
1360 m_surfaceLayerBridge = | 1362 m_surfaceLayerBridge = |
1361 wrapUnique(new CanvasSurfaceLayerBridge(std::move(service))); | 1363 wrapUnique(new CanvasSurfaceLayerBridge(std::move(service))); |
1362 return m_surfaceLayerBridge->createSurfaceLayer(this->width(), | 1364 return m_surfaceLayerBridge->createSurfaceLayer(this->width(), |
1363 this->height()); | 1365 this->height()); |
1364 } | 1366 } |
1365 | 1367 |
1366 } // namespace blink | 1368 } // namespace blink |
OLD | NEW |