| 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 | 67 |
| 68 HTMLCanvasElement::HTMLCanvasElement(Document& document) | 68 HTMLCanvasElement::HTMLCanvasElement(Document& document) |
| 69 : HTMLElement(canvasTag, document) | 69 : HTMLElement(canvasTag, document) |
| 70 , m_size(DefaultWidth, DefaultHeight) | 70 , m_size(DefaultWidth, DefaultHeight) |
| 71 , m_rendererIsCanvas(false) | 71 , m_rendererIsCanvas(false) |
| 72 , m_ignoreReset(false) | 72 , m_ignoreReset(false) |
| 73 , m_accelerationDisabled(false) | 73 , m_accelerationDisabled(false) |
| 74 , m_externallyAllocatedMemory(0) | 74 , m_externallyAllocatedMemory(0) |
| 75 , m_deviceScaleFactor(1) | 75 , m_deviceScaleFactor(1) |
| 76 , m_originClean(true) | 76 , m_originClean(true) |
| 77 , m_hasCreatedImageBuffer(false) | 77 , m_didFailToCreateImageBuffer(false) |
| 78 , m_didClearImageBuffer(false) | 78 , m_didClearImageBuffer(false) |
| 79 { | 79 { |
| 80 ScriptWrappable::init(this); | 80 ScriptWrappable::init(this); |
| 81 } | 81 } |
| 82 | 82 |
| 83 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) | 83 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) |
| 84 { | 84 { |
| 85 return adoptRef(new HTMLCanvasElement(document)); | 85 return adoptRef(new HTMLCanvasElement(document)); |
| 86 } | 86 } |
| 87 | 87 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end;
++it) | 224 for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end;
++it) |
| 225 (*it)->canvasChanged(this, rect); | 225 (*it)->canvasChanged(this, rect); |
| 226 } | 226 } |
| 227 | 227 |
| 228 void HTMLCanvasElement::reset() | 228 void HTMLCanvasElement::reset() |
| 229 { | 229 { |
| 230 if (m_ignoreReset) | 230 if (m_ignoreReset) |
| 231 return; | 231 return; |
| 232 | 232 |
| 233 bool ok; | 233 bool ok; |
| 234 bool hadImageBuffer = hasCreatedImageBuffer(); | 234 bool hadImageBuffer = hasImageBuffer(); |
| 235 | 235 |
| 236 int w = getAttribute(widthAttr).toInt(&ok); | 236 int w = getAttribute(widthAttr).toInt(&ok); |
| 237 if (!ok || w < 0) | 237 if (!ok || w < 0) |
| 238 w = DefaultWidth; | 238 w = DefaultWidth; |
| 239 | 239 |
| 240 int h = getAttribute(heightAttr).toInt(&ok); | 240 int h = getAttribute(heightAttr).toInt(&ok); |
| 241 if (!ok || h < 0) | 241 if (!ok || h < 0) |
| 242 h = DefaultHeight; | 242 h = DefaultHeight; |
| 243 | 243 |
| 244 if (m_contextStateSaver) { | 244 if (m_contextStateSaver) { |
| 245 // Reset to the initial graphics context state. | 245 // Reset to the initial graphics context state. |
| 246 m_contextStateSaver->restore(); | 246 m_contextStateSaver->restore(); |
| 247 m_contextStateSaver->save(); | 247 m_contextStateSaver->save(); |
| 248 } | 248 } |
| 249 | 249 |
| 250 if (m_context && m_context->is2d()) { | 250 if (m_context && m_context->is2d()) { |
| 251 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); | 251 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); |
| 252 context2D->reset(); | 252 context2D->reset(); |
| 253 } | 253 } |
| 254 | 254 |
| 255 IntSize oldSize = size(); | 255 IntSize oldSize = size(); |
| 256 IntSize newSize(w, h); | 256 IntSize newSize(w, h); |
| 257 float newDeviceScaleFactor = 1; | 257 float newDeviceScaleFactor = 1; |
| 258 | 258 |
| 259 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. | 259 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. |
| 260 // This optimization is only done for 2D canvases for now. | 260 // This optimization is only done for 2D canvases for now. |
| 261 if (m_hasCreatedImageBuffer && oldSize == newSize && m_deviceScaleFactor ==
newDeviceScaleFactor && m_context && m_context->is2d()) { | 261 if (hadImageBuffer && oldSize == newSize && m_deviceScaleFactor == newDevice
ScaleFactor && m_context && m_context->is2d()) { |
| 262 if (!m_didClearImageBuffer) | 262 if (!m_didClearImageBuffer) |
| 263 clearImageBuffer(); | 263 clearImageBuffer(); |
| 264 return; | 264 return; |
| 265 } | 265 } |
| 266 | 266 |
| 267 m_deviceScaleFactor = newDeviceScaleFactor; | 267 m_deviceScaleFactor = newDeviceScaleFactor; |
| 268 | 268 |
| 269 setSurfaceSize(newSize); | 269 setSurfaceSize(newSize); |
| 270 | 270 |
| 271 if (m_context && m_context->is3d() && oldSize != size()) | 271 if (m_context && m_context->is3d() && oldSize != size()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 | 309 |
| 310 if (context->paintingDisabled()) | 310 if (context->paintingDisabled()) |
| 311 return; | 311 return; |
| 312 | 312 |
| 313 if (m_context) { | 313 if (m_context) { |
| 314 if (!paintsIntoCanvasBuffer() && !document().printing()) | 314 if (!paintsIntoCanvasBuffer() && !document().printing()) |
| 315 return; | 315 return; |
| 316 m_context->paintRenderingResultsToCanvas(); | 316 m_context->paintRenderingResultsToCanvas(); |
| 317 } | 317 } |
| 318 | 318 |
| 319 if (hasCreatedImageBuffer()) { | 319 if (hasImageBuffer()) { |
| 320 ImageBuffer* imageBuffer = buffer(); | 320 ImageBuffer* imageBuffer = buffer(); |
| 321 if (imageBuffer) { | 321 if (imageBuffer) { |
| 322 CompositeOperator compositeOperator = !m_context || m_context->hasAl
pha() ? CompositeSourceOver : CompositeCopy; | 322 CompositeOperator compositeOperator = !m_context || m_context->hasAl
pha() ? CompositeSourceOver : CompositeCopy; |
| 323 if (m_presentedImage) | 323 if (m_presentedImage) |
| 324 context->drawImage(m_presentedImage.get(), pixelSnappedIntRect(r
), compositeOperator, DoNotRespectImageOrientation, useLowQualityScale); | 324 context->drawImage(m_presentedImage.get(), pixelSnappedIntRect(r
), compositeOperator, DoNotRespectImageOrientation, useLowQualityScale); |
| 325 else | 325 else |
| 326 context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), co
mpositeOperator, BlendModeNormal, useLowQualityScale); | 326 context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), co
mpositeOperator, BlendModeNormal, useLowQualityScale); |
| 327 } | 327 } |
| 328 } | 328 } |
| 329 | 329 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 345 } | 345 } |
| 346 | 346 |
| 347 void HTMLCanvasElement::clearPresentationCopy() | 347 void HTMLCanvasElement::clearPresentationCopy() |
| 348 { | 348 { |
| 349 m_presentedImage.clear(); | 349 m_presentedImage.clear(); |
| 350 } | 350 } |
| 351 | 351 |
| 352 void HTMLCanvasElement::setSurfaceSize(const IntSize& size) | 352 void HTMLCanvasElement::setSurfaceSize(const IntSize& size) |
| 353 { | 353 { |
| 354 m_size = size; | 354 m_size = size; |
| 355 m_hasCreatedImageBuffer = false; | 355 m_didFailToCreateImageBuffer = false; |
| 356 m_contextStateSaver.clear(); | 356 m_contextStateSaver.clear(); |
| 357 m_imageBuffer.clear(); | 357 m_imageBuffer.clear(); |
| 358 setExternallyAllocatedMemory(0); | 358 setExternallyAllocatedMemory(0); |
| 359 clearCopiedImage(); | 359 clearCopiedImage(); |
| 360 } | 360 } |
| 361 | 361 |
| 362 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType) | 362 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType) |
| 363 { | 363 { |
| 364 String lowercaseMimeType = mimeType.lower(); | 364 String lowercaseMimeType = mimeType.lower(); |
| 365 | 365 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 if (!m_context || !m_context->is3d()) | 399 if (!m_context || !m_context->is3d()) |
| 400 return 0; | 400 return 0; |
| 401 | 401 |
| 402 WebGLRenderingContext* ctx = static_cast<WebGLRenderingContext*>(m_context.g
et()); | 402 WebGLRenderingContext* ctx = static_cast<WebGLRenderingContext*>(m_context.g
et()); |
| 403 | 403 |
| 404 return ctx->paintRenderingResultsToImageData(); | 404 return ctx->paintRenderingResultsToImageData(); |
| 405 } | 405 } |
| 406 | 406 |
| 407 IntSize HTMLCanvasElement::convertLogicalToDevice(const IntSize& logicalSize) co
nst | 407 IntSize HTMLCanvasElement::convertLogicalToDevice(const IntSize& logicalSize) co
nst |
| 408 { | 408 { |
| 409 float width = ceilf(logicalSize.width() * m_deviceScaleFactor); | 409 FloatSize deviceSize = logicalSize * m_deviceScaleFactor; |
| 410 float height = ceilf(logicalSize.height() * m_deviceScaleFactor); | 410 return expandedIntSize(deviceSize); |
| 411 return IntSize(width, height); | |
| 412 } | 411 } |
| 413 | 412 |
| 414 SecurityOrigin* HTMLCanvasElement::securityOrigin() const | 413 SecurityOrigin* HTMLCanvasElement::securityOrigin() const |
| 415 { | 414 { |
| 416 return document().securityOrigin(); | 415 return document().securityOrigin(); |
| 417 } | 416 } |
| 418 | 417 |
| 419 StyleResolver* HTMLCanvasElement::styleResolver() | 418 StyleResolver* HTMLCanvasElement::styleResolver() |
| 420 { | 419 { |
| 421 return document().styleResolver(); | 420 return document().styleResolver(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 440 if (!blink::Platform::current()->canAccelerate2dCanvas()) | 439 if (!blink::Platform::current()->canAccelerate2dCanvas()) |
| 441 return false; | 440 return false; |
| 442 | 441 |
| 443 return true; | 442 return true; |
| 444 } | 443 } |
| 445 | 444 |
| 446 void HTMLCanvasElement::createImageBuffer() | 445 void HTMLCanvasElement::createImageBuffer() |
| 447 { | 446 { |
| 448 ASSERT(!m_imageBuffer); | 447 ASSERT(!m_imageBuffer); |
| 449 | 448 |
| 450 m_hasCreatedImageBuffer = true; | 449 m_didFailToCreateImageBuffer = true; |
| 451 m_didClearImageBuffer = true; | 450 m_didClearImageBuffer = true; |
| 452 | 451 |
| 453 IntSize deviceSize = convertLogicalToDevice(size()); | 452 IntSize deviceSize = convertLogicalToDevice(size()); |
| 454 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) | 453 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) |
| 455 return; | 454 return; |
| 456 | 455 |
| 457 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) | 456 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) |
| 458 return; | 457 return; |
| 459 | 458 |
| 460 if (!deviceSize.width() || !deviceSize.height()) | 459 if (!deviceSize.width() || !deviceSize.height()) |
| 461 return; | 460 return; |
| 462 | 461 |
| 463 RenderingMode renderingMode = is3D() ? TextureBacked : (shouldAccelerate(dev
iceSize) ? Accelerated : UnacceleratedNonPlatformBuffer); | 462 RenderingMode renderingMode = is3D() ? TextureBacked : (shouldAccelerate(dev
iceSize) ? Accelerated : UnacceleratedNonPlatformBuffer); |
| 464 int msaaSampleCount = 0; | 463 int msaaSampleCount = 0; |
| 465 if (document().settings()) | 464 if (document().settings()) |
| 466 msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCo
unt(); | 465 msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCo
unt(); |
| 467 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque :
Opaque; | 466 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque :
Opaque; |
| 468 m_imageBuffer = ImageBuffer::create(size(), m_deviceScaleFactor, renderingMo
de, opacityMode, msaaSampleCount); | 467 m_imageBuffer = ImageBuffer::create(size(), m_deviceScaleFactor, renderingMo
de, opacityMode, msaaSampleCount); |
| 469 if (!m_imageBuffer) | 468 if (!m_imageBuffer) |
| 470 return; | 469 return; |
| 470 m_didFailToCreateImageBuffer = false; |
| 471 setExternallyAllocatedMemory(4 * width() * height()); | 471 setExternallyAllocatedMemory(4 * width() * height()); |
| 472 m_imageBuffer->context()->setShouldClampToSourceRect(false); | 472 m_imageBuffer->context()->setShouldClampToSourceRect(false); |
| 473 m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQ
uality); | 473 m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQ
uality); |
| 474 // Enabling MSAA overrides a request to disable antialiasing. This is true r
egardless of whether the | 474 // Enabling MSAA overrides a request to disable antialiasing. This is true r
egardless of whether the |
| 475 // rendering mode is accelerated or not. For consistency, we don't want to a
pply AA in accelerated | 475 // rendering mode is accelerated or not. For consistency, we don't want to a
pply AA in accelerated |
| 476 // canvases but not in unaccelerated canvases. | 476 // canvases but not in unaccelerated canvases. |
| 477 if (!msaaSampleCount && document().settings() && !document().settings()->ant
ialiased2dCanvasEnabled()) | 477 if (!msaaSampleCount && document().settings() && !document().settings()->ant
ialiased2dCanvasEnabled()) |
| 478 m_imageBuffer->context()->setShouldAntialias(false); | 478 m_imageBuffer->context()->setShouldAntialias(false); |
| 479 // GraphicsContext's defaults don't always agree with the 2d canvas spec. | 479 // GraphicsContext's defaults don't always agree with the 2d canvas spec. |
| 480 // See CanvasRenderingContext2D::State::State() for more information. | 480 // See CanvasRenderingContext2D::State::State() for more information. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 493 m_externallyAllocatedMemory = externallyAllocatedMemory; | 493 m_externallyAllocatedMemory = externallyAllocatedMemory; |
| 494 } | 494 } |
| 495 | 495 |
| 496 GraphicsContext* HTMLCanvasElement::drawingContext() const | 496 GraphicsContext* HTMLCanvasElement::drawingContext() const |
| 497 { | 497 { |
| 498 return buffer() ? m_imageBuffer->context() : 0; | 498 return buffer() ? m_imageBuffer->context() : 0; |
| 499 } | 499 } |
| 500 | 500 |
| 501 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const | 501 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
| 502 { | 502 { |
| 503 if (!m_hasCreatedImageBuffer) | 503 if (m_didFailToCreateImageBuffer) { |
| 504 ASSERT(!hasImageBuffer()); |
| 504 return 0; | 505 return 0; |
| 506 } |
| 505 | 507 |
| 506 return drawingContext(); | 508 return drawingContext(); |
| 507 } | 509 } |
| 508 | 510 |
| 509 ImageBuffer* HTMLCanvasElement::buffer() const | 511 ImageBuffer* HTMLCanvasElement::buffer() const |
| 510 { | 512 { |
| 511 if (!m_hasCreatedImageBuffer) | 513 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) |
| 512 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); | 514 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
| 513 return m_imageBuffer.get(); | 515 return m_imageBuffer.get(); |
| 514 } | 516 } |
| 515 | 517 |
| 516 Image* HTMLCanvasElement::copiedImage() const | 518 Image* HTMLCanvasElement::copiedImage() const |
| 517 { | 519 { |
| 518 if (!m_copiedImage && buffer()) { | 520 if (!m_copiedImage && buffer()) { |
| 519 if (m_context) | 521 if (m_context) |
| 520 m_context->paintRenderingResultsToCanvas(); | 522 m_context->paintRenderingResultsToCanvas(); |
| 521 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 523 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
| 522 } | 524 } |
| 523 return m_copiedImage.get(); | 525 return m_copiedImage.get(); |
| 524 } | 526 } |
| 525 | 527 |
| 526 void HTMLCanvasElement::clearImageBuffer() | 528 void HTMLCanvasElement::clearImageBuffer() |
| 527 { | 529 { |
| 528 ASSERT(m_hasCreatedImageBuffer); | 530 ASSERT(hasImageBuffer() && !m_didFailToCreateImageBuffer); |
| 529 ASSERT(!m_didClearImageBuffer); | 531 ASSERT(!m_didClearImageBuffer); |
| 530 ASSERT(m_context); | 532 ASSERT(m_context); |
| 531 | 533 |
| 532 m_didClearImageBuffer = true; | 534 m_didClearImageBuffer = true; |
| 533 | 535 |
| 534 if (m_context->is2d()) { | 536 if (m_context->is2d()) { |
| 535 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); | 537 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); |
| 536 // No need to undo transforms/clip/etc. because we are called right afte
r the context is reset. | 538 // No need to undo transforms/clip/etc. because we are called right afte
r the context is reset. |
| 537 context2D->clearRect(0, 0, width(), height()); | 539 context2D->clearRect(0, 0, width(), height()); |
| 538 } | 540 } |
| 539 } | 541 } |
| 540 | 542 |
| 541 void HTMLCanvasElement::clearCopiedImage() | 543 void HTMLCanvasElement::clearCopiedImage() |
| 542 { | 544 { |
| 543 m_copiedImage.clear(); | 545 m_copiedImage.clear(); |
| 544 m_didClearImageBuffer = false; | 546 m_didClearImageBuffer = false; |
| 545 } | 547 } |
| 546 | 548 |
| 547 AffineTransform HTMLCanvasElement::baseTransform() const | 549 AffineTransform HTMLCanvasElement::baseTransform() const |
| 548 { | 550 { |
| 549 ASSERT(m_hasCreatedImageBuffer); | 551 ASSERT(hasImageBuffer() && !m_didFailToCreateImageBuffer); |
| 550 IntSize unscaledSize = size(); | 552 IntSize unscaledSize = size(); |
| 551 IntSize size = convertLogicalToDevice(unscaledSize); | 553 IntSize size = convertLogicalToDevice(unscaledSize); |
| 552 AffineTransform transform; | 554 AffineTransform transform; |
| 553 if (size.width() && size.height()) | 555 if (size.width() && size.height()) |
| 554 transform.scaleNonUniform(size.width() / unscaledSize.width(), size.heig
ht() / unscaledSize.height()); | 556 transform.scaleNonUniform(size.width() / unscaledSize.width(), size.heig
ht() / unscaledSize.height()); |
| 555 return m_imageBuffer->baseTransform() * transform; | 557 return m_imageBuffer->baseTransform() * transform; |
| 556 } | 558 } |
| 557 | 559 |
| 558 } | 560 } |
| OLD | NEW |