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::isDrawable() const | |
Justin Novosad
2014/12/02 15:48:16
I think isPaintable would be more consistent with
| |
221 { | |
222 if (!m_context) | |
223 return canCreateImageBuffer(size()); | |
224 return buffer(); | |
225 } | |
dshwang
2014/12/01 14:31:12
Introduce this class to replace buffer() in some c
| |
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 if (!m_context) |
358 if (!paintsIntoCanvasBuffer() && !document().printing()) | 375 return; |
Justin Novosad
2014/12/02 15:48:16
I think this is going to be a problem problem with
| |
359 return; | 376 if (!paintsIntoCanvasBuffer() && !document().printing()) |
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); | 377 return; |
361 } | |
362 | 378 |
379 m_context->paintRenderingResultsToCanvas(FrontBuffer); | |
363 if (hasImageBuffer()) { | 380 if (hasImageBuffer()) { |
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; | 381 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; |
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); | 382 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); |
366 } else { | 383 } else { |
367 // When alpha is false, we should draw to opaque black. | 384 // When alpha is false, we should draw to opaque black. |
368 if (m_context && !m_context->hasAlpha()) | 385 if (!m_context->hasAlpha()) |
369 context->fillRect(FloatRect(r), Color(0, 0, 0)); | 386 context->fillRect(FloatRect(r), Color(0, 0, 0)); |
370 } | 387 } |
371 | 388 |
372 if (is3D()) | 389 if (is3D()) |
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); | 390 toWebGLRenderingContext(m_context.get())->markLayerComposited(); |
374 } | 391 } |
375 | 392 |
376 bool HTMLCanvasElement::is3D() const | 393 bool HTMLCanvasElement::is3D() const |
377 { | 394 { |
378 return m_context && m_context->is3d(); | 395 return m_context && m_context->is3d(); |
(...skipping 24 matching lines...) Expand all Loading... | |
403 return lowercaseMimeType; | 420 return lowercaseMimeType; |
404 } | 421 } |
405 | 422 |
406 const AtomicString HTMLCanvasElement::imageSourceURL() const | 423 const AtomicString HTMLCanvasElement::imageSourceURL() const |
407 { | 424 { |
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); | 425 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); |
409 } | 426 } |
410 | 427 |
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const | 428 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const |
412 { | 429 { |
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) | 430 if (!canCreateImageBuffer(size())) |
414 return String("data:,"); | 431 return String("data:,"); |
415 | 432 |
416 String encodingMimeType = toEncodingMimeType(mimeType); | 433 String encodingMimeType = toEncodingMimeType(mimeType); |
417 if (!m_context) { | 434 if (!m_context) { |
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); | 435 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); |
419 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality); | 436 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality); |
420 } | 437 } |
421 | 438 |
422 if (m_context->is3d()) { | 439 if (m_context->is3d()) { |
423 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL(). | 440 // 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(); | 565 return surface.release(); |
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released | 566 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released |
550 } | 567 } |
551 | 568 |
552 return surfaceFactory->createSurface(deviceSize, opacityMode); | 569 return surfaceFactory->createSurface(deviceSize, opacityMode); |
553 } | 570 } |
554 | 571 |
555 void HTMLCanvasElement::createImageBuffer() | 572 void HTMLCanvasElement::createImageBuffer() |
556 { | 573 { |
557 createImageBufferInternal(); | 574 createImageBufferInternal(); |
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) | 575 if (m_didFailToCreateImageBuffer && m_context->is2d()) |
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); | 576 toCanvasRenderingContext2D(m_context.get())->loseContext(); |
560 } | 577 } |
561 | 578 |
562 void HTMLCanvasElement::createImageBufferInternal() | 579 void HTMLCanvasElement::createImageBufferInternal() |
563 { | 580 { |
564 ASSERT(!m_imageBuffer); | 581 ASSERT(!m_imageBuffer); |
565 ASSERT(!m_contextStateSaver); | 582 ASSERT(!m_contextStateSaver); |
566 | 583 |
567 m_didFailToCreateImageBuffer = true; | 584 m_didFailToCreateImageBuffer = true; |
568 m_imageBufferIsClear = true; | 585 m_imageBufferIsClear = true; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const | 674 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
658 { | 675 { |
659 if (!hasImageBuffer()) | 676 if (!hasImageBuffer()) |
660 return nullptr; | 677 return nullptr; |
661 | 678 |
662 return drawingContext(); | 679 return drawingContext(); |
663 } | 680 } |
664 | 681 |
665 ImageBuffer* HTMLCanvasElement::buffer() const | 682 ImageBuffer* HTMLCanvasElement::buffer() const |
666 { | 683 { |
684 ASSERT(m_context); | |
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) | 685 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) |
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); | 686 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
669 return m_imageBuffer.get(); | 687 return m_imageBuffer.get(); |
670 } | 688 } |
671 | 689 |
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() | 690 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() |
673 { | 691 { |
692 ASSERT(m_context); | |
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) | 693 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) |
675 return; | 694 return; |
676 discardImageBuffer(); | 695 discardImageBuffer(); |
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; | 696 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque; |
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); | 697 m_imageBuffer = ImageBuffer::create(size(), opacityMode); |
679 m_didFailToCreateImageBuffer = !m_imageBuffer; | 698 m_didFailToCreateImageBuffer = !m_imageBuffer; |
680 } | 699 } |
681 | 700 |
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const | 701 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe r) const |
683 { | 702 { |
703 if (!canCreateImageBuffer(size())) | |
704 return nullptr; | |
705 if (!m_context) | |
706 return createTransparentImage(size()); | |
707 | |
684 if (!m_copiedImage && buffer()) { | 708 if (!m_copiedImage && buffer()) { |
685 if (m_context && m_context->is3d()) | 709 if (m_context && m_context->is3d()) |
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); | 710 m_context->paintRenderingResultsToCanvas(sourceBuffer); |
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 711 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
688 updateExternallyAllocatedMemory(); | 712 updateExternallyAllocatedMemory(); |
689 } | 713 } |
690 return m_copiedImage.get(); | 714 return m_copiedImage; |
691 } | 715 } |
692 | 716 |
693 void HTMLCanvasElement::discardImageBuffer() | 717 void HTMLCanvasElement::discardImageBuffer() |
694 { | 718 { |
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer | 719 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer |
696 m_imageBuffer.clear(); | 720 m_imageBuffer.clear(); |
697 resetDirtyRect(); | 721 resetDirtyRect(); |
698 updateExternallyAllocatedMemory(); | 722 updateExternallyAllocatedMemory(); |
699 } | 723 } |
700 | 724 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
737 HTMLElement::didMoveToNewDocument(oldDocument); | 761 HTMLElement::didMoveToNewDocument(oldDocument); |
738 } | 762 } |
739 | 763 |
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const | 764 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const |
741 { | 765 { |
742 if (!width() || !height()) { | 766 if (!width() || !height()) { |
743 *status = ZeroSizeCanvasSourceImageStatus; | 767 *status = ZeroSizeCanvasSourceImageStatus; |
744 return nullptr; | 768 return nullptr; |
745 } | 769 } |
746 | 770 |
747 if (!buffer()) { | 771 if (!isDrawable()) { |
dshwang
2014/12/01 14:31:12
for example of using isDrawable()
| |
748 *status = InvalidSourceImageStatus; | 772 *status = InvalidSourceImageStatus; |
749 return nullptr; | 773 return nullptr; |
750 } | 774 } |
751 | 775 |
752 if (m_context && m_context->is3d()) { | 776 if (!m_context) { |
777 *status = NormalSourceImageStatus; | |
778 return createTransparentImage(size()); | |
779 } | |
780 | |
781 if (m_context->is3d()) { | |
753 m_context->paintRenderingResultsToCanvas(BackBuffer); | 782 m_context->paintRenderingResultsToCanvas(BackBuffer); |
754 *status = ExternalSourceImageStatus; | 783 *status = ExternalSourceImageStatus; |
755 | 784 |
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) | 785 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) |
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); | 786 return buffer()->copyImage(DontCopyBackingStore, Unscaled); |
758 } | 787 } |
759 | 788 |
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); | 789 RefPtr<SkImage> image = buffer()->newImageSnapshot(); |
761 if (image) { | 790 if (image) { |
762 *status = NormalSourceImageStatus; | 791 *status = NormalSourceImageStatus; |
763 | |
764 return StaticBitmapImage::create(image.release()); | 792 return StaticBitmapImage::create(image.release()); |
765 } | 793 } |
766 | 794 |
767 | |
768 *status = InvalidSourceImageStatus; | 795 *status = InvalidSourceImageStatus; |
769 | |
770 return nullptr; | 796 return nullptr; |
771 } | 797 } |
772 | 798 |
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const | 799 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const |
774 { | 800 { |
775 return !originClean(); | 801 return !originClean(); |
776 } | 802 } |
777 | 803 |
778 FloatSize HTMLCanvasElement::sourceSize() const | 804 FloatSize HTMLCanvasElement::sourceSize() const |
779 { | 805 { |
780 return FloatSize(width(), height()); | 806 return FloatSize(width(), height()); |
781 } | 807 } |
782 | 808 |
783 } | 809 } |
OLD | NEW |