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/ImageBuffer.h" | 52 #include "platform/graphics/ImageBuffer.h" |
52 #include "platform/graphics/RecordingImageBufferSurface.h" | 53 #include "platform/graphics/RecordingImageBufferSurface.h" |
53 #include "platform/graphics/StaticBitmapImage.h" | 54 #include "platform/graphics/StaticBitmapImage.h" |
54 #include "platform/graphics/UnacceleratedImageBufferSurface.h" | 55 #include "platform/graphics/UnacceleratedImageBufferSurface.h" |
55 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" | 56 #include "platform/graphics/gpu/WebGLImageBufferSurface.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 PassRefPtr<Image> createTransparentImage(const IntSize& size) |
80 { | 81 { |
81 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) | 82 SkBitmap bitmap; |
82 return false; | 83 bitmap.allocN32Pixels(size.width(), size.height()); |
83 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) | 84 bitmap.eraseColor(SK_ColorTRANSPARENT); |
84 return false; | 85 return BitmapImage::create(NativeImageSkia::create(bitmap)); |
85 if (!deviceSize.width() || !deviceSize.height()) | |
86 return false; | |
87 return true; | |
88 } | 86 } |
89 | 87 |
90 } // namespace | 88 } // namespace |
91 | 89 |
92 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); | 90 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); |
93 | 91 |
94 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) | 92 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) |
95 : HTMLElement(canvasTag, document) | 93 : HTMLElement(canvasTag, document) |
96 , DocumentVisibilityObserver(document) | 94 , DocumentVisibilityObserver(document) |
97 , m_size(DefaultWidth, DefaultHeight) | 95 , m_size(DefaultWidth, DefaultHeight) |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 | 345 |
348 if (renderBox() && renderBox()->hasAcceleratedCompositing()) | 346 if (renderBox() && renderBox()->hasAcceleratedCompositing()) |
349 return false; | 347 return false; |
350 | 348 |
351 return true; | 349 return true; |
352 } | 350 } |
353 | 351 |
354 | 352 |
355 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) | 353 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) |
356 { | 354 { |
357 if (m_context) { | 355 if (!m_context) |
358 if (!paintsIntoCanvasBuffer() && !document().printing()) | 356 return; |
359 return; | 357 if (!paintsIntoCanvasBuffer() && !document().printing()) |
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); | 358 return; |
359 if (!canCreateImageBuffer()) { | |
Justin Novosad
2014/11/27 00:49:31
I disagree with this part. We should not create an
dshwang
2014/11/27 15:12:11
Thank you for explaining. I rollback this code in
| |
360 // When alpha is false, we should draw to opaque black. | |
361 if (!m_context->hasAlpha()) | |
362 context->fillRect(FloatRect(r), Color(0, 0, 0)); | |
363 return; | |
361 } | 364 } |
362 | 365 |
363 if (hasImageBuffer()) { | 366 m_context->paintRenderingResultsToCanvas(FrontBuffer); |
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; | 367 CompositeOperator compositeOperator = m_context->hasAlpha() ? CompositeSourc eOver : CompositeCopy; |
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); | 368 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeOpera tor); |
366 } else { | |
367 // When alpha is false, we should draw to opaque black. | |
368 if (m_context && !m_context->hasAlpha()) | |
369 context->fillRect(FloatRect(r), Color(0, 0, 0)); | |
370 } | |
371 | 369 |
372 if (is3D()) | 370 if (is3D()) |
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); | 371 toWebGLRenderingContext(m_context.get())->markLayerComposited(); |
374 } | 372 } |
375 | 373 |
376 bool HTMLCanvasElement::is3D() const | 374 bool HTMLCanvasElement::is3D() const |
377 { | 375 { |
378 return m_context && m_context->is3d(); | 376 return m_context && m_context->is3d(); |
379 } | 377 } |
380 | 378 |
(...skipping 22 matching lines...) Expand all Loading... | |
403 return lowercaseMimeType; | 401 return lowercaseMimeType; |
404 } | 402 } |
405 | 403 |
406 const AtomicString HTMLCanvasElement::imageSourceURL() const | 404 const AtomicString HTMLCanvasElement::imageSourceURL() const |
407 { | 405 { |
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); | 406 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); |
409 } | 407 } |
410 | 408 |
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const | 409 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const |
412 { | 410 { |
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) | 411 if (!canCreateImageBuffer()) |
414 return String("data:,"); | 412 return String("data:,"); |
415 | 413 |
416 String encodingMimeType = toEncodingMimeType(mimeType); | 414 String encodingMimeType = toEncodingMimeType(mimeType); |
417 if (!m_context) { | 415 if (!m_context) { |
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); | 416 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); |
419 return ImageDataToDataURL(ImageDataBuffer(imageData->size(), imageData-> data()), encodingMimeType, quality); | 417 return ImageDataToDataURL(ImageDataBuffer(imageData->size(), imageData-> data()), encodingMimeType, quality); |
420 } | 418 } |
421 | 419 |
422 if (m_context->is3d()) { | 420 if (m_context->is3d()) { |
423 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL(). | 421 // 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(); | 546 return surface.release(); |
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released | 547 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released |
550 } | 548 } |
551 | 549 |
552 return surfaceFactory->createSurface(deviceSize, opacityMode); | 550 return surfaceFactory->createSurface(deviceSize, opacityMode); |
553 } | 551 } |
554 | 552 |
555 void HTMLCanvasElement::createImageBuffer() | 553 void HTMLCanvasElement::createImageBuffer() |
556 { | 554 { |
557 createImageBufferInternal(); | 555 createImageBufferInternal(); |
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) | 556 if (m_didFailToCreateImageBuffer && m_context->is2d()) |
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); | 557 toCanvasRenderingContext2D(m_context.get())->loseContext(); |
560 } | 558 } |
561 | 559 |
562 void HTMLCanvasElement::createImageBufferInternal() | 560 void HTMLCanvasElement::createImageBufferInternal() |
563 { | 561 { |
564 ASSERT(!m_imageBuffer); | 562 ASSERT(!m_imageBuffer); |
565 ASSERT(!m_contextStateSaver); | 563 ASSERT(!m_contextStateSaver); |
566 | 564 |
567 m_didFailToCreateImageBuffer = true; | 565 m_didFailToCreateImageBuffer = true; |
568 m_imageBufferIsClear = true; | 566 m_imageBufferIsClear = true; |
569 | 567 |
570 if (!canCreateImageBuffer(size())) | 568 if (!canCreateImageBuffer()) |
571 return; | 569 return; |
572 | 570 |
573 int msaaSampleCount; | 571 int msaaSampleCount; |
574 OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(size(), &msaaS ampleCount); | 572 OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(size(), &msaaS ampleCount); |
575 if (!surface->isValid()) | 573 if (!surface->isValid()) |
576 return; | 574 return; |
577 | 575 |
578 m_imageBuffer = ImageBuffer::create(surface.release()); | 576 m_imageBuffer = ImageBuffer::create(surface.release()); |
579 m_imageBuffer->setClient(this); | 577 m_imageBuffer->setClient(this); |
580 | 578 |
(...skipping 21 matching lines...) Expand all Loading... | |
602 m_imageBuffer->context()->setStrokeThickness(1); | 600 m_imageBuffer->context()->setStrokeThickness(1); |
603 #if ENABLE(ASSERT) | 601 #if ENABLE(ASSERT) |
604 m_imageBuffer->context()->disableDestructionChecks(); // 2D canvas is allowe d to leave context in an unfinalized state. | 602 m_imageBuffer->context()->disableDestructionChecks(); // 2D canvas is allowe d to leave context in an unfinalized state. |
605 #endif | 603 #endif |
606 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer- >context())); | 604 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer- >context())); |
607 | 605 |
608 if (m_context) | 606 if (m_context) |
609 setNeedsCompositingUpdate(); | 607 setNeedsCompositingUpdate(); |
610 } | 608 } |
611 | 609 |
610 bool HTMLCanvasElement::canCreateImageBuffer() const | |
611 { | |
612 if (m_size.isEmpty()) | |
613 return false; | |
614 if (m_size.width() * m_size.height() > MaxCanvasArea) | |
615 return false; | |
616 if (m_size.width() > MaxSkiaDim || m_size.height() > MaxSkiaDim) | |
617 return false; | |
618 return true; | |
619 } | |
620 | |
612 void HTMLCanvasElement::notifySurfaceInvalid() | 621 void HTMLCanvasElement::notifySurfaceInvalid() |
613 { | 622 { |
614 if (m_context && m_context->is2d()) { | 623 if (m_context && m_context->is2d()) { |
615 CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_conte xt.get()); | 624 CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_conte xt.get()); |
616 context2d->loseContext(); | 625 context2d->loseContext(); |
617 } | 626 } |
618 } | 627 } |
619 | 628 |
620 void HTMLCanvasElement::trace(Visitor* visitor) | 629 void HTMLCanvasElement::trace(Visitor* visitor) |
621 { | 630 { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const | 666 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
658 { | 667 { |
659 if (!hasImageBuffer()) | 668 if (!hasImageBuffer()) |
660 return nullptr; | 669 return nullptr; |
661 | 670 |
662 return drawingContext(); | 671 return drawingContext(); |
663 } | 672 } |
664 | 673 |
665 ImageBuffer* HTMLCanvasElement::buffer() const | 674 ImageBuffer* HTMLCanvasElement::buffer() const |
666 { | 675 { |
676 ASSERT(m_context); | |
dshwang
2014/11/26 21:36:54
It means that we can move imageBuffer to CanvasRen
| |
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) | 677 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) |
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); | 678 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
669 return m_imageBuffer.get(); | 679 return m_imageBuffer.get(); |
670 } | 680 } |
671 | 681 |
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() | 682 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() |
673 { | 683 { |
684 ASSERT(m_context); | |
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) | 685 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) |
675 return; | 686 return; |
676 discardImageBuffer(); | 687 discardImageBuffer(); |
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; | 688 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque; |
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); | 689 m_imageBuffer = ImageBuffer::create(size(), opacityMode); |
679 m_didFailToCreateImageBuffer = !m_imageBuffer; | 690 m_didFailToCreateImageBuffer = !m_imageBuffer; |
680 } | 691 } |
681 | 692 |
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const | 693 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe r) const |
683 { | 694 { |
695 if (!canCreateImageBuffer()) | |
696 return nullptr; | |
697 if (!m_context) | |
698 return createTransparentImage(size()); | |
699 | |
684 if (!m_copiedImage && buffer()) { | 700 if (!m_copiedImage && buffer()) { |
685 if (m_context && m_context->is3d()) | 701 if (m_context && m_context->is3d()) |
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); | 702 m_context->paintRenderingResultsToCanvas(sourceBuffer); |
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 703 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
688 updateExternallyAllocatedMemory(); | 704 updateExternallyAllocatedMemory(); |
689 } | 705 } |
690 return m_copiedImage.get(); | 706 return m_copiedImage; |
691 } | 707 } |
692 | 708 |
693 void HTMLCanvasElement::discardImageBuffer() | 709 void HTMLCanvasElement::discardImageBuffer() |
694 { | 710 { |
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer | 711 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer |
696 m_imageBuffer.clear(); | 712 m_imageBuffer.clear(); |
697 resetDirtyRect(); | 713 resetDirtyRect(); |
698 updateExternallyAllocatedMemory(); | 714 updateExternallyAllocatedMemory(); |
699 } | 715 } |
700 | 716 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
737 HTMLElement::didMoveToNewDocument(oldDocument); | 753 HTMLElement::didMoveToNewDocument(oldDocument); |
738 } | 754 } |
739 | 755 |
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const | 756 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const |
741 { | 757 { |
742 if (!width() || !height()) { | 758 if (!width() || !height()) { |
743 *status = ZeroSizeCanvasSourceImageStatus; | 759 *status = ZeroSizeCanvasSourceImageStatus; |
744 return nullptr; | 760 return nullptr; |
745 } | 761 } |
746 | 762 |
747 if (!buffer()) { | 763 if (!canCreateImageBuffer()) { |
748 *status = InvalidSourceImageStatus; | 764 *status = InvalidSourceImageStatus; |
749 return nullptr; | 765 return nullptr; |
750 } | 766 } |
751 | 767 |
752 if (m_context && m_context->is3d()) { | 768 if (!m_context) { |
769 *status = NormalSourceImageStatus; | |
770 return createTransparentImage(size()); | |
771 } | |
772 | |
773 if (m_context->is3d()) { | |
753 m_context->paintRenderingResultsToCanvas(BackBuffer); | 774 m_context->paintRenderingResultsToCanvas(BackBuffer); |
754 *status = ExternalSourceImageStatus; | 775 *status = ExternalSourceImageStatus; |
755 | 776 |
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) | 777 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) |
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); | 778 return buffer()->copyImage(DontCopyBackingStore, Unscaled); |
Justin Novosad
2014/11/27 00:49:31
Here: not safe to assume buffer is non-null
dshwang
2014/11/27 15:12:11
Yes, true
In next patch set, above "if statement"
| |
758 } | 779 } |
759 | 780 |
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); | 781 RefPtr<SkImage> image = buffer()->newImageSnapshot(); |
Justin Novosad
2014/11/27 00:49:30
here too
| |
761 if (image) { | 782 if (image) { |
762 *status = NormalSourceImageStatus; | 783 *status = NormalSourceImageStatus; |
763 | |
764 return StaticBitmapImage::create(image.release()); | 784 return StaticBitmapImage::create(image.release()); |
765 } | 785 } |
766 | 786 |
767 | |
768 *status = InvalidSourceImageStatus; | 787 *status = InvalidSourceImageStatus; |
769 | |
770 return nullptr; | 788 return nullptr; |
771 } | 789 } |
772 | 790 |
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const | 791 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const |
774 { | 792 { |
775 return !originClean(); | 793 return !originClean(); |
776 } | 794 } |
777 | 795 |
778 FloatSize HTMLCanvasElement::sourceSize() const | 796 FloatSize HTMLCanvasElement::sourceSize() const |
779 { | 797 { |
780 return FloatSize(width(), height()); | 798 return FloatSize(width(), height()); |
781 } | 799 } |
782 | 800 |
783 } | 801 } |
OLD | NEW |