| 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 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 | 448 |
| 449 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this
method to be used on a worker thread). | 449 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this
method to be used on a worker thread). |
| 450 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod
ing(lowercaseMimeType)) | 450 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod
ing(lowercaseMimeType)) |
| 451 lowercaseMimeType = DefaultMimeType; | 451 lowercaseMimeType = DefaultMimeType; |
| 452 | 452 |
| 453 return lowercaseMimeType; | 453 return lowercaseMimeType; |
| 454 } | 454 } |
| 455 | 455 |
| 456 const AtomicString HTMLCanvasElement::imageSourceURL() const | 456 const AtomicString HTMLCanvasElement::imageSourceURL() const |
| 457 { | 457 { |
| 458 return AtomicString(toDataURLInternal(DefaultMimeType, 0, FrontBuffer)); | 458 NonThrowableExceptionState exceptionState; |
| 459 AtomicString dataURL(toDataURLInternal(DefaultMimeType, 0, FrontBuffer, exce
ptionState)); |
| 460 if (exceptionState.hadException()) |
| 461 return AtomicString("data:,"); |
| 462 return dataURL; |
| 459 } | 463 } |
| 460 | 464 |
| 461 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const | 465 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const |
| 462 { | 466 { |
| 463 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d
context | 467 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d
context |
| 464 if (buffer()) | 468 if (buffer()) |
| 465 m_imageBuffer->prepareSurfaceForPaintingIfNeeded(); | 469 m_imageBuffer->prepareSurfaceForPaintingIfNeeded(); |
| 466 } | 470 } |
| 467 | 471 |
| 468 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer) cons
t | 472 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer, Exce
ptionState& exceptionState) const |
| 469 { | 473 { |
| 470 ImageData* imageData; | 474 ImageData* imageData; |
| 471 if (is3D()) { | 475 if (is3D()) { |
| 472 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). | 476 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). |
| 473 imageData = m_context->paintRenderingResultsToImageData(sourceBuffer); | 477 imageData = m_context->paintRenderingResultsToImageData(sourceBuffer); |
| 474 if (imageData) | 478 if (imageData) |
| 475 return imageData; | 479 return imageData; |
| 476 | 480 |
| 477 m_context->paintRenderingResultsToCanvas(sourceBuffer); | 481 m_context->paintRenderingResultsToCanvas(sourceBuffer); |
| 478 imageData = ImageData::create(m_size); | 482 imageData = ImageData::create(m_size, exceptionState); |
| 483 // Note: we rethrow exceptions from ImageData creation, which is not |
| 484 // mandated by the specification because using an ImageData intermediate |
| 485 // for toBlob and toDataURL is an implementation choice. As a result of |
| 486 // this rethrow, a RangeError exception may be thrown when there is |
| 487 // insufficient available memory. Even though the exception is unspec'ed
, |
| 488 // it was ascertained that to throw from here will generally result in a |
| 489 // better outcome than to crash the process. |
| 490 if (exceptionState.hadException()) |
| 491 return nullptr; |
| 479 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAccelera
tion); | 492 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAccelera
tion); |
| 480 if (snapshot) { | 493 if (snapshot) { |
| 481 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8
888_SkColorType, kUnpremul_SkAlphaType); | 494 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8
888_SkColorType, kUnpremul_SkAlphaType); |
| 482 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo
.minRowBytes(), 0, 0); | 495 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo
.minRowBytes(), 0, 0); |
| 483 } | 496 } |
| 484 return imageData; | 497 return imageData; |
| 485 } | 498 } |
| 486 | 499 |
| 487 imageData = ImageData::create(m_size); | 500 imageData = ImageData::create(m_size, exceptionState); |
| 501 if (exceptionState.hadException()) |
| 502 return nullptr; |
| 488 | 503 |
| 489 if (!m_context) | 504 if (!m_context) |
| 490 return imageData; | 505 return imageData; |
| 491 | 506 |
| 492 ASSERT(m_context->is2d()); | 507 ASSERT(m_context->is2d()); |
| 493 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration
); | 508 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration
); |
| 494 if (snapshot) { | 509 if (snapshot) { |
| 495 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_
SkColorType, kUnpremul_SkAlphaType); | 510 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_
SkColorType, kUnpremul_SkAlphaType); |
| 496 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min
RowBytes(), 0, 0); | 511 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min
RowBytes(), 0, 0); |
| 497 } | 512 } |
| 498 | 513 |
| 499 return imageData; | 514 return imageData; |
| 500 } | 515 } |
| 501 | 516 |
| 502 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
& quality, SourceDrawingBuffer sourceBuffer) const | 517 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
& quality, SourceDrawingBuffer sourceBuffer, ExceptionState& exceptionState) con
st |
| 503 { | 518 { |
| 504 if (!isPaintable()) | 519 if (!isPaintable()) |
| 505 return String("data:,"); | 520 return String("data:,"); |
| 506 | 521 |
| 507 String encodingMimeType = toEncodingMimeType(mimeType); | 522 String encodingMimeType = toEncodingMimeType(mimeType); |
| 508 | 523 |
| 509 ImageData* imageData = toImageData(sourceBuffer); | 524 ImageData* imageData = toImageData(sourceBuffer, exceptionState); |
| 525 if (exceptionState.hadException()) |
| 526 return String(); |
| 527 |
| 510 ScopedDisposal<ImageData> disposer(imageData); | 528 ScopedDisposal<ImageData> disposer(imageData); |
| 511 | 529 |
| 512 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU
RL(encodingMimeType, quality); | 530 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU
RL(encodingMimeType, quality); |
| 513 } | 531 } |
| 514 | 532 |
| 515 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q
ualityArgument, ExceptionState& exceptionState) const | 533 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q
ualityArgument, ExceptionState& exceptionState) const |
| 516 { | 534 { |
| 517 if (!originClean()) { | 535 if (!originClean()) { |
| 518 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); | 536 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); |
| 519 return String(); | 537 return String(); |
| 520 } | 538 } |
| 521 double quality = UndefinedQualityValue; | 539 double quality = UndefinedQualityValue; |
| 522 if (!qualityArgument.isEmpty()) { | 540 if (!qualityArgument.isEmpty()) { |
| 523 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 541 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
| 524 if (v8Value->IsNumber()) { | 542 if (v8Value->IsNumber()) { |
| 525 quality = v8Value.As<v8::Number>()->Value(); | 543 quality = v8Value.As<v8::Number>()->Value(); |
| 526 } | 544 } |
| 527 } | 545 } |
| 528 return toDataURLInternal(mimeType, quality, BackBuffer); | 546 return toDataURLInternal(mimeType, quality, BackBuffer, exceptionState); |
| 529 } | 547 } |
| 530 | 548 |
| 531 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c
onst ScriptValue& qualityArgument, ExceptionState& exceptionState) | 549 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c
onst ScriptValue& qualityArgument, ExceptionState& exceptionState) |
| 532 { | 550 { |
| 533 if (!originClean()) { | 551 if (!originClean()) { |
| 534 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); | 552 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); |
| 535 return; | 553 return; |
| 536 } | 554 } |
| 537 | 555 |
| 538 if (!isPaintable()) { | 556 if (!isPaintable()) { |
| 539 // If the canvas element's bitmap has no pixels | 557 // If the canvas element's bitmap has no pixels |
| 540 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, bind(&FileCallback::handleEvent, callback, nullptr)); | 558 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, bind(&FileCallback::handleEvent, callback, nullptr)); |
| 541 return; | 559 return; |
| 542 } | 560 } |
| 543 | 561 |
| 544 double quality = UndefinedQualityValue; | 562 double quality = UndefinedQualityValue; |
| 545 if (!qualityArgument.isEmpty()) { | 563 if (!qualityArgument.isEmpty()) { |
| 546 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 564 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
| 547 if (v8Value->IsNumber()) { | 565 if (v8Value->IsNumber()) { |
| 548 quality = v8Value.As<v8::Number>()->Value(); | 566 quality = v8Value.As<v8::Number>()->Value(); |
| 549 } | 567 } |
| 550 } | 568 } |
| 551 | 569 |
| 552 String encodingMimeType = toEncodingMimeType(mimeType); | 570 String encodingMimeType = toEncodingMimeType(mimeType); |
| 553 | 571 |
| 554 ImageData* imageData = toImageData(BackBuffer); | 572 ImageData* imageData = toImageData(BackBuffer, exceptionState); |
| 555 // imageData unref its data, which we still keep alive for the async toBlob
thread | 573 if (exceptionState.hadException()) |
| 574 return; |
| 575 |
| 576 // ImageData unrefs its data, which we still keep alive for the async toBlob
thread |
| 556 ScopedDisposal<ImageData> disposer(imageData); | 577 ScopedDisposal<ImageData> disposer(imageData); |
| 557 // Add a ref to keep image data alive until completion of encoding | 578 // Add a ref to keep image data alive until completion of encoding |
| 558 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); | 579 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); |
| 559 | 580 |
| 560 RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::cre
ate(imageDataRef.release(), encodingMimeType, imageData->size(), callback); | 581 RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::cre
ate(imageDataRef.release(), encodingMimeType, imageData->size(), callback); |
| 561 if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType
== DefaultMimeType)) { | 582 if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType
== DefaultMimeType)) { |
| 562 asyncCreatorRef->scheduleAsyncBlobCreation(true); | 583 asyncCreatorRef->scheduleAsyncBlobCreation(true); |
| 563 } else { | 584 } else { |
| 564 asyncCreatorRef->scheduleAsyncBlobCreation(false, quality); | 585 asyncCreatorRef->scheduleAsyncBlobCreation(false, quality); |
| 565 } | 586 } |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 920 { | 941 { |
| 921 return FloatSize(width(), height()); | 942 return FloatSize(width(), height()); |
| 922 } | 943 } |
| 923 | 944 |
| 924 bool HTMLCanvasElement::isOpaque() const | 945 bool HTMLCanvasElement::isOpaque() const |
| 925 { | 946 { |
| 926 return m_context && !m_context->hasAlpha(); | 947 return m_context && !m_context->hasAlpha(); |
| 927 } | 948 } |
| 928 | 949 |
| 929 } // blink | 950 } // blink |
| OLD | NEW |