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 |