Chromium Code Reviews| 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 |