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/frame/Settings.h" | 39 #include "core/frame/Settings.h" |
| 40 #include "core/html/ImageData.h" | 40 #include "core/html/ImageData.h" |
| 41 #include "core/html/canvas/CanvasContextCreationAttributes.h" | 41 #include "core/html/canvas/CanvasContextCreationAttributes.h" |
| 42 #include "core/html/canvas/CanvasFontCache.h" | 42 #include "core/html/canvas/CanvasFontCache.h" |
| 43 #include "core/html/canvas/CanvasRenderingContext.h" | 43 #include "core/html/canvas/CanvasRenderingContext.h" |
| 44 #include "core/html/canvas/CanvasRenderingContextFactory.h" | 44 #include "core/html/canvas/CanvasRenderingContextFactory.h" |
| 45 #include "core/layout/LayoutHTMLCanvas.h" | 45 #include "core/layout/LayoutHTMLCanvas.h" |
| 46 #include "core/paint/DeprecatedPaintLayer.h" | 46 #include "core/paint/DeprecatedPaintLayer.h" |
| 47 #include "platform/MIMETypeRegistry.h" | 47 #include "platform/MIMETypeRegistry.h" |
| 48 #include "platform/RuntimeEnabledFeatures.h" | 48 #include "platform/RuntimeEnabledFeatures.h" |
| 49 #include "platform/Task.h" | |
| 50 #include "platform/ThreadSafeFunctional.h" | |
| 49 #include "platform/graphics/Canvas2DImageBufferSurface.h" | 51 #include "platform/graphics/Canvas2DImageBufferSurface.h" |
| 50 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h" | 52 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h" |
| 51 #include "platform/graphics/ImageBuffer.h" | 53 #include "platform/graphics/ImageBuffer.h" |
| 52 #include "platform/graphics/RecordingImageBufferSurface.h" | 54 #include "platform/graphics/RecordingImageBufferSurface.h" |
| 53 #include "platform/graphics/StaticBitmapImage.h" | 55 #include "platform/graphics/StaticBitmapImage.h" |
| 54 #include "platform/graphics/UnacceleratedImageBufferSurface.h" | 56 #include "platform/graphics/UnacceleratedImageBufferSurface.h" |
| 55 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" | 57 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" |
| 56 #include "platform/transforms/AffineTransform.h" | 58 #include "platform/transforms/AffineTransform.h" |
| 57 #include "public/platform/Platform.h" | 59 #include "public/platform/Platform.h" |
| 58 #include "public/platform/WebTraceLocation.h" | 60 #include "public/platform/WebTraceLocation.h" |
| 59 #include "wtf/Functional.h" | |
| 60 #include <math.h> | 61 #include <math.h> |
| 61 #include <v8.h> | 62 #include <v8.h> |
| 62 | 63 |
| 63 namespace blink { | 64 namespace blink { |
| 64 | 65 |
| 65 using namespace HTMLNames; | 66 using namespace HTMLNames; |
| 66 | 67 |
| 67 namespace { | 68 namespace { |
| 68 | 69 |
| 69 // These values come from the WhatWG spec. | 70 // These values come from the WhatWG spec. |
| 70 const int DefaultWidth = 300; | 71 const int DefaultWidth = 300; |
| 71 const int DefaultHeight = 150; | 72 const int DefaultHeight = 150; |
| 72 | 73 |
| 73 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it | 74 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it |
| 74 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions, | 75 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions, |
| 75 // in exchange for a smaller maximum canvas size. | 76 // in exchange for a smaller maximum canvas size. |
| 76 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels | 77 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels |
| 77 | 78 |
| 78 // In Skia, we will also limit width/height to 32767. | 79 // In Skia, we will also limit width/height to 32767. |
| 79 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. | 80 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. |
| 80 | 81 |
| 82 // A default value of quality argument for toDataURL and toBlob | |
| 83 // It is in an invalid range (outside 0.0 - 1.0) so that it will not be misinter preted as a user-input value | |
| 84 const int UndefinedQualityValue = -1.0; | |
| 85 | |
| 81 bool canCreateImageBuffer(const IntSize& size) | 86 bool canCreateImageBuffer(const IntSize& size) |
| 82 { | 87 { |
| 83 if (size.isEmpty()) | 88 if (size.isEmpty()) |
| 84 return false; | 89 return false; |
| 85 if (size.width() * size.height() > MaxCanvasArea) | 90 if (size.width() * size.height() > MaxCanvasArea) |
| 86 return false; | 91 return false; |
| 87 if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim) | 92 if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim) |
| 88 return false; | 93 return false; |
| 89 return true; | 94 return true; |
| 90 } | 95 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 121 { | 126 { |
| 122 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_external lyAllocatedMemory); | 127 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_external lyAllocatedMemory); |
| 123 #if !ENABLE(OILPAN) | 128 #if !ENABLE(OILPAN) |
| 124 for (CanvasObserver* canvasObserver : m_observers) | 129 for (CanvasObserver* canvasObserver : m_observers) |
| 125 canvasObserver->canvasDestroyed(this); | 130 canvasObserver->canvasDestroyed(this); |
| 126 // Ensure these go away before the ImageBuffer. | 131 // Ensure these go away before the ImageBuffer. |
| 127 m_context.clear(); | 132 m_context.clear(); |
| 128 #endif | 133 #endif |
| 129 } | 134 } |
| 130 | 135 |
| 136 OwnPtr<WebThread>& HTMLCanvasElement::getToBlobThreadInstance() | |
| 137 { | |
| 138 DEFINE_STATIC_LOCAL(OwnPtr<WebThread>, s_toBlobThread, ()); | |
| 139 if (!s_toBlobThread) { | |
| 140 s_toBlobThread = adoptPtr(Platform::current()->createThread("Async toBlo b")); | |
| 141 } | |
| 142 return s_toBlobThread; | |
|
Justin Novosad
2015/09/25 16:47:33
Returning an "OwnPtr<WebThread>&" is not appropria
| |
| 143 } | |
| 144 | |
| 131 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicSt ring& value) | 145 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicSt ring& value) |
| 132 { | 146 { |
| 133 if (name == widthAttr || name == heightAttr) | 147 if (name == widthAttr || name == heightAttr) |
| 134 reset(); | 148 reset(); |
| 135 HTMLElement::parseAttribute(name, value); | 149 HTMLElement::parseAttribute(name, value); |
| 136 } | 150 } |
| 137 | 151 |
| 138 LayoutObject* HTMLCanvasElement::createLayoutObject(const ComputedStyle& style) | 152 LayoutObject* HTMLCanvasElement::createLayoutObject(const ComputedStyle& style) |
| 139 { | 153 { |
| 140 LocalFrame* frame = document().frame(); | 154 LocalFrame* frame = document().frame(); |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 ASSERT(m_context->is2d()); | 524 ASSERT(m_context->is2d()); |
| 511 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration ); | 525 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration ); |
| 512 if (snapshot) { | 526 if (snapshot) { |
| 513 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_ SkColorType, kUnpremul_SkAlphaType); | 527 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_ SkColorType, kUnpremul_SkAlphaType); |
| 514 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min RowBytes(), 0, 0); | 528 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min RowBytes(), 0, 0); |
| 515 } | 529 } |
| 516 | 530 |
| 517 return imageData; | 531 return imageData; |
| 518 } | 532 } |
| 519 | 533 |
| 520 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const | 534 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double & quality, SourceDrawingBuffer sourceBuffer) const |
| 521 { | 535 { |
| 522 if (!isPaintable()) | 536 if (!isPaintable()) |
| 523 return String("data:,"); | 537 return String("data:,"); |
| 524 | 538 |
| 525 String encodingMimeType = toEncodingMimeType(mimeType); | 539 String encodingMimeType = toEncodingMimeType(mimeType); |
| 526 | 540 |
| 527 ImageData* imageData = toImageData(sourceBuffer); | 541 ImageData* imageData = toImageData(sourceBuffer); |
| 528 ScopedDisposal<ImageData> disposer(imageData); | 542 ScopedDisposal<ImageData> disposer(imageData); |
| 529 | 543 |
| 530 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU RL(encodingMimeType, quality); | 544 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU RL(encodingMimeType, quality); |
| 531 } | 545 } |
| 532 | 546 |
| 533 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q ualityArgument, ExceptionState& exceptionState) const | 547 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q ualityArgument, ExceptionState& exceptionState) const |
| 534 { | 548 { |
| 535 if (!originClean()) { | 549 if (!originClean()) { |
| 536 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); | 550 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); |
| 537 return String(); | 551 return String(); |
| 538 } | 552 } |
| 539 double quality; | 553 double quality = UndefinedQualityValue; |
| 540 double* qualityPtr = nullptr; | |
| 541 if (!qualityArgument.isEmpty()) { | 554 if (!qualityArgument.isEmpty()) { |
| 542 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 555 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
| 543 if (v8Value->IsNumber()) { | 556 if (v8Value->IsNumber()) { |
| 544 quality = v8Value.As<v8::Number>()->Value(); | 557 quality = v8Value.As<v8::Number>()->Value(); |
| 545 qualityPtr = &quality; | |
| 546 } | 558 } |
| 547 } | 559 } |
| 548 return toDataURLInternal(mimeType, qualityPtr, BackBuffer); | 560 return toDataURLInternal(mimeType, quality, BackBuffer); |
| 549 } | 561 } |
| 550 | 562 |
| 551 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c onst ScriptValue& qualityArgument, ExceptionState& exceptionState) const | 563 void HTMLCanvasElement::encodeImageAsync(DOMUint8ClampedArray* imageData, IntSiz e imageSize, FileCallback* callback, const String& mimeType, double quality) |
| 564 { | |
| 565 OwnPtr<Vector<char>> encodedImage(adoptPtr(new Vector<char>())); | |
| 566 | |
| 567 if (!ImageDataBuffer(imageSize, imageData->data()).encodeImage(mimeType, qua lity, encodedImage.get())) { | |
| 568 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, bin d(&FileCallback::handleEvent, callback, nullptr)); | |
| 569 } else { | |
| 570 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, thr eadSafeBind(&HTMLCanvasElement::createBlobAndCall, AllowCrossThreadAccess(this), encodedImage.release(), mimeType, AllowCrossThreadAccess(callback))); | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 void HTMLCanvasElement::createBlobAndCall(PassOwnPtr<Vector<char>> encodedImage, const String& mimeType, FileCallback* callback) | |
| 575 { | |
| 576 // The main thread takes ownership of encoded image vector | |
| 577 OwnPtr<Vector<char>> enc(encodedImage); | |
| 578 | |
| 579 File* resultBlob = File::create(enc->data(), enc->size(), mimeType); | |
| 580 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, bind(&F ileCallback::handleEvent, callback, resultBlob)); | |
| 581 } | |
| 582 | |
| 583 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c onst ScriptValue& qualityArgument, ExceptionState& exceptionState) | |
| 552 { | 584 { |
| 553 if (!originClean()) { | 585 if (!originClean()) { |
| 554 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); | 586 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); |
| 555 return; | 587 return; |
| 556 } | 588 } |
| 557 | 589 |
| 558 File* resultBlob = nullptr; | |
| 559 if (!isPaintable()) { | 590 if (!isPaintable()) { |
| 560 // If the canvas element's bitmap has no pixels | 591 // If the canvas element's bitmap has no pixels |
| 592 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, bin d(&FileCallback::handleEvent, callback, nullptr)); | |
| 561 return; | 593 return; |
| 562 } | 594 } |
| 563 | 595 |
| 564 double quality; | 596 double quality = UndefinedQualityValue; |
| 565 double* qualityPtr = nullptr; | |
| 566 if (!qualityArgument.isEmpty()) { | 597 if (!qualityArgument.isEmpty()) { |
| 567 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 598 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
| 568 if (v8Value->IsNumber()) { | 599 if (v8Value->IsNumber()) { |
| 569 quality = v8Value.As<v8::Number>()->Value(); | 600 quality = v8Value.As<v8::Number>()->Value(); |
| 570 qualityPtr = &quality; | |
| 571 } | 601 } |
| 572 } | 602 } |
| 573 | 603 |
| 574 String encodingMimeType = toEncodingMimeType(mimeType); | 604 String encodingMimeType = toEncodingMimeType(mimeType); |
| 575 | 605 |
| 576 ImageData* imageData = toImageData(BackBuffer); | 606 ImageData* imageData = toImageData(BackBuffer); |
| 607 // imageData unref its data, which we still keep alive for the async toBlob thread | |
| 577 ScopedDisposal<ImageData> disposer(imageData); | 608 ScopedDisposal<ImageData> disposer(imageData); |
| 578 | 609 |
| 579 // Perform image encoding | 610 // Add a ref to keep image data alive until completion of encoding |
| 580 Vector<char> encodedImage; | 611 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); |
| 581 ImageDataBuffer(imageData->size(), imageData->data()->data()).encodeImage(en codingMimeType, qualityPtr, &encodedImage); | |
| 582 resultBlob = File::create(encodedImage.data(), encodedImage.size(), encoding MimeType); | |
| 583 | 612 |
| 584 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, bind(&F ileCallback::handleEvent, callback, resultBlob)); | 613 // TODO: We cannot guarantee that 'this' will stay alive long enough. |
| 614 getToBlobThreadInstance()->taskRunner()->postTask(FROM_HERE, new Task(thread SafeBind(&HTMLCanvasElement::encodeImageAsync, AllowCrossThreadAccess(this), All owCrossThreadAccess(imageDataRef.release().leakRef()), imageData->size(), AllowC rossThreadAccess(callback), encodingMimeType, quality))); | |
| 585 } | 615 } |
| 586 | 616 |
| 587 SecurityOrigin* HTMLCanvasElement::securityOrigin() const | 617 SecurityOrigin* HTMLCanvasElement::securityOrigin() const |
| 588 { | 618 { |
| 589 return document().securityOrigin(); | 619 return document().securityOrigin(); |
| 590 } | 620 } |
| 591 | 621 |
| 592 bool HTMLCanvasElement::originClean() const | 622 bool HTMLCanvasElement::originClean() const |
| 593 { | 623 { |
| 594 if (document().settings() && document().settings()->disableReadingFromCanvas ()) | 624 if (document().settings() && document().settings()->disableReadingFromCanvas ()) |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 950 { | 980 { |
| 951 return FloatSize(width(), height()); | 981 return FloatSize(width(), height()); |
| 952 } | 982 } |
| 953 | 983 |
| 954 bool HTMLCanvasElement::isOpaque() const | 984 bool HTMLCanvasElement::isOpaque() const |
| 955 { | 985 { |
| 956 return m_context && !m_context->hasAlpha(); | 986 return m_context && !m_context->hasAlpha(); |
| 957 } | 987 } |
| 958 | 988 |
| 959 } // blink | 989 } // blink |
| OLD | NEW |