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 28 matching lines...) Expand all Loading... |
39 #include "core/html/ImageData.h" | 39 #include "core/html/ImageData.h" |
40 #include "core/html/canvas/Canvas2DContextAttributes.h" | 40 #include "core/html/canvas/Canvas2DContextAttributes.h" |
41 #include "core/html/canvas/CanvasRenderingContext2D.h" | 41 #include "core/html/canvas/CanvasRenderingContext2D.h" |
42 #include "core/html/canvas/WebGLContextAttributes.h" | 42 #include "core/html/canvas/WebGLContextAttributes.h" |
43 #include "core/html/canvas/WebGLContextEvent.h" | 43 #include "core/html/canvas/WebGLContextEvent.h" |
44 #include "core/html/canvas/WebGLRenderingContext.h" | 44 #include "core/html/canvas/WebGLRenderingContext.h" |
45 #include "core/rendering/RenderHTMLCanvas.h" | 45 #include "core/rendering/RenderHTMLCanvas.h" |
46 #include "core/rendering/RenderLayer.h" | 46 #include "core/rendering/RenderLayer.h" |
47 #include "platform/MIMETypeRegistry.h" | 47 #include "platform/MIMETypeRegistry.h" |
48 #include "platform/RuntimeEnabledFeatures.h" | 48 #include "platform/RuntimeEnabledFeatures.h" |
| 49 #include "platform/graphics/BitmapImage.h" |
49 #include "platform/graphics/Canvas2DImageBufferSurface.h" | 50 #include "platform/graphics/Canvas2DImageBufferSurface.h" |
50 #include "platform/graphics/GraphicsContextStateSaver.h" | 51 #include "platform/graphics/GraphicsContextStateSaver.h" |
51 #include "platform/graphics/RecordingImageBufferSurface.h" | 52 #include "platform/graphics/RecordingImageBufferSurface.h" |
52 #include "platform/graphics/StaticBitmapImage.h" | 53 #include "platform/graphics/StaticBitmapImage.h" |
53 #include "platform/graphics/UnacceleratedImageBufferSurface.h" | 54 #include "platform/graphics/UnacceleratedImageBufferSurface.h" |
54 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" | 55 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" |
55 #include "platform/image-encoders/ImageEncoder.h" | 56 #include "platform/image-encoders/ImageEncoder.h" |
56 #include "platform/transforms/AffineTransform.h" | 57 #include "platform/transforms/AffineTransform.h" |
57 #include "public/platform/Platform.h" | 58 #include "public/platform/Platform.h" |
58 #include <math.h> | 59 #include <math.h> |
(...skipping 10 matching lines...) Expand all Loading... |
69 const int DefaultHeight = 150; | 70 const int DefaultHeight = 150; |
70 | 71 |
71 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo
re it | 72 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo
re it |
72 // reaches that limit. We limit by area instead, giving us larger maximum dimens
ions, | 73 // reaches that limit. We limit by area instead, giving us larger maximum dimens
ions, |
73 // in exchange for a smaller maximum canvas size. | 74 // in exchange for a smaller maximum canvas size. |
74 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels | 75 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels |
75 | 76 |
76 //In Skia, we will also limit width/height to 32767. | 77 //In Skia, we will also limit width/height to 32767. |
77 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. | 78 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. |
78 | 79 |
79 bool canCreateImageBuffer(const IntSize& deviceSize) | 80 bool canCreateImageBuffer(const IntSize& size) |
80 { | 81 { |
81 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) | 82 if (size.isEmpty()) |
82 return false; | 83 return false; |
83 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) | 84 if (size.width() * size.height() > MaxCanvasArea) |
84 return false; | 85 return false; |
85 if (!deviceSize.width() || !deviceSize.height()) | 86 if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim) |
86 return false; | 87 return false; |
87 return true; | 88 return true; |
88 } | 89 } |
89 | 90 |
| 91 PassRefPtr<Image> createTransparentImage(const IntSize& size) |
| 92 { |
| 93 ASSERT(canCreateImageBuffer(size)); |
| 94 SkBitmap bitmap; |
| 95 bitmap.allocN32Pixels(size.width(), size.height()); |
| 96 bitmap.eraseColor(SK_ColorTRANSPARENT); |
| 97 return BitmapImage::create(NativeImageSkia::create(bitmap)); |
| 98 } |
| 99 |
90 } // namespace | 100 } // namespace |
91 | 101 |
92 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); | 102 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); |
93 | 103 |
94 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) | 104 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) |
95 : HTMLElement(canvasTag, document) | 105 : HTMLElement(canvasTag, document) |
96 , DocumentVisibilityObserver(document) | 106 , DocumentVisibilityObserver(document) |
97 , m_size(DefaultWidth, DefaultHeight) | 107 , m_size(DefaultWidth, DefaultHeight) |
98 , m_ignoreReset(false) | 108 , m_ignoreReset(false) |
99 , m_accelerationDisabled(false) | 109 , m_accelerationDisabled(false) |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 } else if (!m_context->is3d()) { | 210 } else if (!m_context->is3d()) { |
201 dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontext
creationerror, false, true, "Canvas has an existing, non-WebGL context")); | 211 dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontext
creationerror, false, true, "Canvas has an existing, non-WebGL context")); |
202 return nullptr; | 212 return nullptr; |
203 } | 213 } |
204 return m_context.get(); | 214 return m_context.get(); |
205 } | 215 } |
206 | 216 |
207 return nullptr; | 217 return nullptr; |
208 } | 218 } |
209 | 219 |
| 220 bool HTMLCanvasElement::isPaintable() const |
| 221 { |
| 222 if (!m_context) |
| 223 return canCreateImageBuffer(size()); |
| 224 return buffer(); |
| 225 } |
| 226 |
210 void HTMLCanvasElement::didDraw(const FloatRect& rect) | 227 void HTMLCanvasElement::didDraw(const FloatRect& rect) |
211 { | 228 { |
212 if (rect.isEmpty()) | 229 if (rect.isEmpty()) |
213 return; | 230 return; |
214 m_imageBufferIsClear = false; | 231 m_imageBufferIsClear = false; |
215 clearCopiedImage(); | 232 clearCopiedImage(); |
216 if (m_dirtyRect.isEmpty()) | 233 if (m_dirtyRect.isEmpty()) |
217 blink::Platform::current()->currentThread()->addTaskObserver(this); | 234 blink::Platform::current()->currentThread()->addTaskObserver(this); |
218 m_dirtyRect.unite(rect); | 235 m_dirtyRect.unite(rect); |
219 } | 236 } |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 | 364 |
348 if (renderBox() && renderBox()->hasAcceleratedCompositing()) | 365 if (renderBox() && renderBox()->hasAcceleratedCompositing()) |
349 return false; | 366 return false; |
350 | 367 |
351 return true; | 368 return true; |
352 } | 369 } |
353 | 370 |
354 | 371 |
355 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) | 372 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) |
356 { | 373 { |
357 if (m_context) { | 374 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and com
positing feature. |
358 if (!paintsIntoCanvasBuffer() && !document().printing()) | 375 if (!m_context) |
359 return; | 376 return; |
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); | 377 if (!paintsIntoCanvasBuffer() && !document().printing()) |
361 } | 378 return; |
362 | 379 |
| 380 m_context->paintRenderingResultsToCanvas(FrontBuffer); |
363 if (hasImageBuffer()) { | 381 if (hasImageBuffer()) { |
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha(
) ? CompositeSourceOver : CompositeCopy; | 382 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha(
) ? CompositeSourceOver : CompositeCopy; |
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO
perator); | 383 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO
perator); |
366 } else { | 384 } else { |
367 // When alpha is false, we should draw to opaque black. | 385 // When alpha is false, we should draw to opaque black. |
368 if (m_context && !m_context->hasAlpha()) | 386 if (!m_context->hasAlpha()) |
369 context->fillRect(FloatRect(r), Color(0, 0, 0)); | 387 context->fillRect(FloatRect(r), Color(0, 0, 0)); |
370 } | 388 } |
371 | 389 |
372 if (is3D()) | 390 if (is3D()) |
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); | 391 toWebGLRenderingContext(m_context.get())->markLayerComposited(); |
374 } | 392 } |
375 | 393 |
376 bool HTMLCanvasElement::is3D() const | 394 bool HTMLCanvasElement::is3D() const |
377 { | 395 { |
378 return m_context && m_context->is3d(); | 396 return m_context && m_context->is3d(); |
(...skipping 24 matching lines...) Expand all Loading... |
403 return lowercaseMimeType; | 421 return lowercaseMimeType; |
404 } | 422 } |
405 | 423 |
406 const AtomicString HTMLCanvasElement::imageSourceURL() const | 424 const AtomicString HTMLCanvasElement::imageSourceURL() const |
407 { | 425 { |
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); | 426 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); |
409 } | 427 } |
410 | 428 |
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
* quality, SourceDrawingBuffer sourceBuffer) const | 429 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
* quality, SourceDrawingBuffer sourceBuffer) const |
412 { | 430 { |
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) | 431 if (!canCreateImageBuffer(size())) |
414 return String("data:,"); | 432 return String("data:,"); |
415 | 433 |
416 String encodingMimeType = toEncodingMimeType(mimeType); | 434 String encodingMimeType = toEncodingMimeType(mimeType); |
417 if (!m_context) { | 435 if (!m_context) { |
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); | 436 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); |
419 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si
ze(), imageData->data()->data()), encodingMimeType, quality); | 437 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si
ze(), imageData->data()->data()), encodingMimeType, quality); |
420 } | 438 } |
421 | 439 |
422 if (m_context->is3d()) { | 440 if (m_context->is3d()) { |
423 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). | 441 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 return surface.release(); | 566 return surface.release(); |
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r
ecreate because old previous one was released | 567 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r
ecreate because old previous one was released |
550 } | 568 } |
551 | 569 |
552 return surfaceFactory->createSurface(deviceSize, opacityMode); | 570 return surfaceFactory->createSurface(deviceSize, opacityMode); |
553 } | 571 } |
554 | 572 |
555 void HTMLCanvasElement::createImageBuffer() | 573 void HTMLCanvasElement::createImageBuffer() |
556 { | 574 { |
557 createImageBufferInternal(); | 575 createImageBufferInternal(); |
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) | 576 if (m_didFailToCreateImageBuffer && m_context->is2d()) |
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); | 577 toCanvasRenderingContext2D(m_context.get())->loseContext(); |
560 } | 578 } |
561 | 579 |
562 void HTMLCanvasElement::createImageBufferInternal() | 580 void HTMLCanvasElement::createImageBufferInternal() |
563 { | 581 { |
564 ASSERT(!m_imageBuffer); | 582 ASSERT(!m_imageBuffer); |
565 ASSERT(!m_contextStateSaver); | 583 ASSERT(!m_contextStateSaver); |
566 | 584 |
567 m_didFailToCreateImageBuffer = true; | 585 m_didFailToCreateImageBuffer = true; |
568 m_imageBufferIsClear = true; | 586 m_imageBufferIsClear = true; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const | 675 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
658 { | 676 { |
659 if (!hasImageBuffer()) | 677 if (!hasImageBuffer()) |
660 return nullptr; | 678 return nullptr; |
661 | 679 |
662 return drawingContext(); | 680 return drawingContext(); |
663 } | 681 } |
664 | 682 |
665 ImageBuffer* HTMLCanvasElement::buffer() const | 683 ImageBuffer* HTMLCanvasElement::buffer() const |
666 { | 684 { |
| 685 ASSERT(m_context); |
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) | 686 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) |
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); | 687 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
669 return m_imageBuffer.get(); | 688 return m_imageBuffer.get(); |
670 } | 689 } |
671 | 690 |
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() | 691 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() |
673 { | 692 { |
| 693 ASSERT(m_context); |
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea
teImageBuffer) | 694 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea
teImageBuffer) |
675 return; | 695 return; |
676 discardImageBuffer(); | 696 discardImageBuffer(); |
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque :
Opaque; | 697 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque; |
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); | 698 m_imageBuffer = ImageBuffer::create(size(), opacityMode); |
679 m_didFailToCreateImageBuffer = !m_imageBuffer; | 699 m_didFailToCreateImageBuffer = !m_imageBuffer; |
680 } | 700 } |
681 | 701 |
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const | 702 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe
r) const |
683 { | 703 { |
| 704 if (!canCreateImageBuffer(size())) |
| 705 return nullptr; |
| 706 if (!m_context) |
| 707 return createTransparentImage(size()); |
| 708 |
684 if (!m_copiedImage && buffer()) { | 709 if (!m_copiedImage && buffer()) { |
685 if (m_context && m_context->is3d()) | 710 if (m_context && m_context->is3d()) |
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); | 711 m_context->paintRenderingResultsToCanvas(sourceBuffer); |
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 712 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
688 updateExternallyAllocatedMemory(); | 713 updateExternallyAllocatedMemory(); |
689 } | 714 } |
690 return m_copiedImage.get(); | 715 return m_copiedImage; |
691 } | 716 } |
692 | 717 |
693 void HTMLCanvasElement::discardImageBuffer() | 718 void HTMLCanvasElement::discardImageBuffer() |
694 { | 719 { |
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer | 720 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer |
696 m_imageBuffer.clear(); | 721 m_imageBuffer.clear(); |
697 resetDirtyRect(); | 722 resetDirtyRect(); |
698 updateExternallyAllocatedMemory(); | 723 updateExternallyAllocatedMemory(); |
699 } | 724 } |
700 | 725 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 HTMLElement::didMoveToNewDocument(oldDocument); | 762 HTMLElement::didMoveToNewDocument(oldDocument); |
738 } | 763 } |
739 | 764 |
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod
e, SourceImageStatus* status) const | 765 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod
e, SourceImageStatus* status) const |
741 { | 766 { |
742 if (!width() || !height()) { | 767 if (!width() || !height()) { |
743 *status = ZeroSizeCanvasSourceImageStatus; | 768 *status = ZeroSizeCanvasSourceImageStatus; |
744 return nullptr; | 769 return nullptr; |
745 } | 770 } |
746 | 771 |
747 if (!buffer()) { | 772 if (!isPaintable()) { |
748 *status = InvalidSourceImageStatus; | 773 *status = InvalidSourceImageStatus; |
749 return nullptr; | 774 return nullptr; |
750 } | 775 } |
751 | 776 |
752 if (m_context && m_context->is3d()) { | 777 if (!m_context) { |
| 778 *status = NormalSourceImageStatus; |
| 779 return createTransparentImage(size()); |
| 780 } |
| 781 |
| 782 if (m_context->is3d()) { |
753 m_context->paintRenderingResultsToCanvas(BackBuffer); | 783 m_context->paintRenderingResultsToCanvas(BackBuffer); |
754 *status = ExternalSourceImageStatus; | 784 *status = ExternalSourceImageStatus; |
755 | 785 |
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi
tmap) | 786 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi
tmap) |
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); | 787 return buffer()->copyImage(DontCopyBackingStore, Unscaled); |
758 } | 788 } |
759 | 789 |
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); | 790 RefPtr<SkImage> image = buffer()->newImageSnapshot(); |
761 if (image) { | 791 if (image) { |
762 *status = NormalSourceImageStatus; | 792 *status = NormalSourceImageStatus; |
763 | |
764 return StaticBitmapImage::create(image.release()); | 793 return StaticBitmapImage::create(image.release()); |
765 } | 794 } |
766 | 795 |
767 | |
768 *status = InvalidSourceImageStatus; | 796 *status = InvalidSourceImageStatus; |
769 | |
770 return nullptr; | 797 return nullptr; |
771 } | 798 } |
772 | 799 |
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const | 800 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const |
774 { | 801 { |
775 return !originClean(); | 802 return !originClean(); |
776 } | 803 } |
777 | 804 |
778 FloatSize HTMLCanvasElement::sourceSize() const | 805 FloatSize HTMLCanvasElement::sourceSize() const |
779 { | 806 { |
780 return FloatSize(width(), height()); | 807 return FloatSize(width(), height()); |
781 } | 808 } |
782 | 809 |
783 } | 810 } |
OLD | NEW |