| 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 |