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 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 | 455 |
456 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this
method to be used on a worker thread). | 456 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this
method to be used on a worker thread). |
457 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod
ing(lowercaseMimeType)) | 457 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod
ing(lowercaseMimeType)) |
458 lowercaseMimeType = "image/png"; | 458 lowercaseMimeType = "image/png"; |
459 | 459 |
460 return lowercaseMimeType; | 460 return lowercaseMimeType; |
461 } | 461 } |
462 | 462 |
463 const AtomicString HTMLCanvasElement::imageSourceURL() const | 463 const AtomicString HTMLCanvasElement::imageSourceURL() const |
464 { | 464 { |
465 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); | 465 NonThrowableExceptionState exceptionState; |
| 466 AtomicString dataURL(toDataURLInternal("image/png", 0, FrontBuffer, exceptio
nState)); |
| 467 if (exceptionState.hadException()) |
| 468 return AtomicString("data:,"); |
| 469 return dataURL; |
466 } | 470 } |
467 | 471 |
468 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const | 472 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const |
469 { | 473 { |
470 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d
context | 474 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d
context |
471 if (buffer()) | 475 if (buffer()) |
472 m_imageBuffer->prepareSurfaceForPaintingIfNeeded(); | 476 m_imageBuffer->prepareSurfaceForPaintingIfNeeded(); |
473 } | 477 } |
474 | 478 |
475 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer) cons
t | 479 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer, Exce
ptionState& exceptionState) const |
476 { | 480 { |
477 ImageData* imageData; | 481 ImageData* imageData; |
478 if (is3D()) { | 482 if (is3D()) { |
479 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). | 483 // Get non-premultiplied data because of inaccurate premultiplied alpha
conversion of buffer()->toDataURL(). |
480 imageData = m_context->paintRenderingResultsToImageData(sourceBuffer); | 484 imageData = m_context->paintRenderingResultsToImageData(sourceBuffer); |
481 if (imageData) | 485 if (imageData) |
482 return imageData; | 486 return imageData; |
483 | 487 |
484 m_context->paintRenderingResultsToCanvas(sourceBuffer); | 488 m_context->paintRenderingResultsToCanvas(sourceBuffer); |
485 imageData = ImageData::create(m_size); | 489 imageData = ImageData::create(m_size, exceptionState); |
| 490 // Note: we rethrow exceptions from ImageData creation, which is not |
| 491 // mandated by the specification because using an ImageData intermediate |
| 492 // for toBlob and toDataURL is an implementation choice. As a result of |
| 493 // this rethrow, a RangeError exception may be thrown when there is |
| 494 // insufficient available memory. Even though the exception is unspec'ed
, |
| 495 // it was ascertained that to throw from here will generally result in a |
| 496 // better outcome than to crash the process. |
| 497 if (exceptionState.hadException()) |
| 498 return nullptr; |
486 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAccelera
tion); | 499 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAccelera
tion); |
487 if (snapshot) { | 500 if (snapshot) { |
488 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8
888_SkColorType, kUnpremul_SkAlphaType); | 501 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8
888_SkColorType, kUnpremul_SkAlphaType); |
489 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo
.minRowBytes(), 0, 0); | 502 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo
.minRowBytes(), 0, 0); |
490 } | 503 } |
491 return imageData; | 504 return imageData; |
492 } | 505 } |
493 | 506 |
494 imageData = ImageData::create(m_size); | 507 imageData = ImageData::create(m_size, exceptionState); |
| 508 if (exceptionState.hadException()) |
| 509 return nullptr; |
495 | 510 |
496 if (!m_context) | 511 if (!m_context) |
497 return imageData; | 512 return imageData; |
498 | 513 |
499 ASSERT(m_context->is2d()); | 514 ASSERT(m_context->is2d()); |
500 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration
); | 515 RefPtr<SkImage> snapshot = buffer()->newSkImageSnapshot(PreferNoAcceleration
); |
501 if (snapshot) { | 516 if (snapshot) { |
502 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_
SkColorType, kUnpremul_SkAlphaType); | 517 SkImageInfo imageInfo = SkImageInfo::Make(width(), height(), kRGBA_8888_
SkColorType, kUnpremul_SkAlphaType); |
503 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min
RowBytes(), 0, 0); | 518 snapshot->readPixels(imageInfo, imageData->data()->data(), imageInfo.min
RowBytes(), 0, 0); |
504 } | 519 } |
505 | 520 |
506 return imageData; | 521 return imageData; |
507 } | 522 } |
508 | 523 |
509 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
& quality, SourceDrawingBuffer sourceBuffer) const | 524 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double
& quality, SourceDrawingBuffer sourceBuffer, ExceptionState& exceptionState) con
st |
510 { | 525 { |
511 if (!isPaintable()) | 526 if (!isPaintable()) |
512 return String("data:,"); | 527 return String("data:,"); |
513 | 528 |
514 String encodingMimeType = toEncodingMimeType(mimeType); | 529 String encodingMimeType = toEncodingMimeType(mimeType); |
515 | 530 |
516 ImageData* imageData = toImageData(sourceBuffer); | 531 ImageData* imageData = toImageData(sourceBuffer, exceptionState); |
| 532 if (exceptionState.hadException()) |
| 533 return String(); |
| 534 |
517 ScopedDisposal<ImageData> disposer(imageData); | 535 ScopedDisposal<ImageData> disposer(imageData); |
518 | 536 |
519 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU
RL(encodingMimeType, quality); | 537 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU
RL(encodingMimeType, quality); |
520 } | 538 } |
521 | 539 |
522 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q
ualityArgument, ExceptionState& exceptionState) const | 540 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q
ualityArgument, ExceptionState& exceptionState) const |
523 { | 541 { |
524 if (!originClean()) { | 542 if (!originClean()) { |
525 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); | 543 exceptionState.throwSecurityError("Tainted canvases may not be exported.
"); |
526 return String(); | 544 return String(); |
527 } | 545 } |
528 double quality = UndefinedQualityValue; | 546 double quality = UndefinedQualityValue; |
529 if (!qualityArgument.isEmpty()) { | 547 if (!qualityArgument.isEmpty()) { |
530 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 548 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
531 if (v8Value->IsNumber()) { | 549 if (v8Value->IsNumber()) { |
532 quality = v8Value.As<v8::Number>()->Value(); | 550 quality = v8Value.As<v8::Number>()->Value(); |
533 } | 551 } |
534 } | 552 } |
535 return toDataURLInternal(mimeType, quality, BackBuffer); | 553 return toDataURLInternal(mimeType, quality, BackBuffer, exceptionState); |
536 } | 554 } |
537 | 555 |
538 void HTMLCanvasElement::encodeImageAsync(DOMUint8ClampedArray* imageData, IntSiz
e imageSize, FileCallback* callback, const String& mimeType, double quality) | 556 void HTMLCanvasElement::encodeImageAsync(DOMUint8ClampedArray* imageData, IntSiz
e imageSize, FileCallback* callback, const String& mimeType, double quality) |
539 { | 557 { |
540 OwnPtr<Vector<char>> encodedImage(adoptPtr(new Vector<char>())); | 558 OwnPtr<Vector<char>> encodedImage(adoptPtr(new Vector<char>())); |
541 | 559 |
542 if (!ImageDataBuffer(imageSize, imageData->data()).encodeImage(mimeType, qua
lity, encodedImage.get())) { | 560 if (!ImageDataBuffer(imageSize, imageData->data()).encodeImage(mimeType, qua
lity, encodedImage.get())) { |
543 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, bind(&FileCallback::handleEvent, callback, nullptr)); | 561 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, bind(&FileCallback::handleEvent, callback, nullptr)); |
544 } else { | 562 } else { |
545 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, threadSafeBind(&HTMLCanvasElement::createBlobAndCall, encodedImage.release(),
mimeType, AllowCrossThreadAccess(callback))); | 563 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER
E, threadSafeBind(&HTMLCanvasElement::createBlobAndCall, encodedImage.release(),
mimeType, AllowCrossThreadAccess(callback))); |
(...skipping 25 matching lines...) Expand all Loading... |
571 double quality = UndefinedQualityValue; | 589 double quality = UndefinedQualityValue; |
572 if (!qualityArgument.isEmpty()) { | 590 if (!qualityArgument.isEmpty()) { |
573 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); | 591 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); |
574 if (v8Value->IsNumber()) { | 592 if (v8Value->IsNumber()) { |
575 quality = v8Value.As<v8::Number>()->Value(); | 593 quality = v8Value.As<v8::Number>()->Value(); |
576 } | 594 } |
577 } | 595 } |
578 | 596 |
579 String encodingMimeType = toEncodingMimeType(mimeType); | 597 String encodingMimeType = toEncodingMimeType(mimeType); |
580 | 598 |
581 ImageData* imageData = toImageData(BackBuffer); | 599 ImageData* imageData = toImageData(BackBuffer, exceptionState); |
582 // imageData unref its data, which we still keep alive for the async toBlob
thread | 600 if (exceptionState.hadException()) |
| 601 return; |
| 602 |
| 603 // ImageData unrefs its data, which we still keep alive for the async toBlob
thread |
583 ScopedDisposal<ImageData> disposer(imageData); | 604 ScopedDisposal<ImageData> disposer(imageData); |
584 | 605 |
585 // Add a ref to keep image data alive until completion of encoding | 606 // Add a ref to keep image data alive until completion of encoding |
586 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); | 607 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); |
587 | 608 |
588 getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new Task(
threadSafeBind(&HTMLCanvasElement::encodeImageAsync, AllowCrossThreadAccess(imag
eDataRef.release().leakRef()), imageData->size(), AllowCrossThreadAccess(callbac
k), encodingMimeType, quality))); | 609 getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new Task(
threadSafeBind(&HTMLCanvasElement::encodeImageAsync, AllowCrossThreadAccess(imag
eDataRef.release().leakRef()), imageData->size(), AllowCrossThreadAccess(callbac
k), encodingMimeType, quality))); |
589 } | 610 } |
590 | 611 |
591 SecurityOrigin* HTMLCanvasElement::securityOrigin() const | 612 SecurityOrigin* HTMLCanvasElement::securityOrigin() const |
592 { | 613 { |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
943 { | 964 { |
944 return FloatSize(width(), height()); | 965 return FloatSize(width(), height()); |
945 } | 966 } |
946 | 967 |
947 bool HTMLCanvasElement::isOpaque() const | 968 bool HTMLCanvasElement::isOpaque() const |
948 { | 969 { |
949 return m_context && !m_context->hasAlpha(); | 970 return m_context && !m_context->hasAlpha(); |
950 } | 971 } |
951 | 972 |
952 } // blink | 973 } // blink |
OLD | NEW |