| 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 //In Skia, we will also limit width/height to 32767. | 66 //In Skia, we will also limit width/height to 32767. |
| 67 static const float MaxSkiaDim = 32767.0F; // Maximum width/height in CSS pixels. | 67 static const float MaxSkiaDim = 32767.0F; // Maximum width/height in CSS pixels. |
| 68 | 68 |
| 69 HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& doc
ument) | 69 HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& doc
ument) |
| 70 : HTMLElement(tagName, document) | 70 : HTMLElement(tagName, document) |
| 71 , m_size(DefaultWidth, DefaultHeight) | 71 , m_size(DefaultWidth, DefaultHeight) |
| 72 , m_rendererIsCanvas(false) | 72 , m_rendererIsCanvas(false) |
| 73 , m_ignoreReset(false) | 73 , m_ignoreReset(false) |
| 74 , m_deviceScaleFactor(1) | 74 , m_deviceScaleFactor(1) |
| 75 , m_originClean(true) | 75 , m_originClean(true) |
| 76 , m_hasCreatedImageBuffer(false) | |
| 77 , m_didClearImageBuffer(false) | 76 , m_didClearImageBuffer(false) |
| 78 , m_accelerationDisabled(false) | 77 , m_accelerationDisabled(false) |
| 79 , m_externallyAllocatedMemory(0) | 78 , m_externallyAllocatedMemory(0) |
| 80 { | 79 { |
| 81 ASSERT(hasTagName(canvasTag)); | 80 ASSERT(hasTagName(canvasTag)); |
| 82 ScriptWrappable::init(this); | 81 ScriptWrappable::init(this); |
| 83 } | 82 } |
| 84 | 83 |
| 85 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) | 84 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) |
| 86 { | 85 { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end;
++it) | 230 for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end;
++it) |
| 232 (*it)->canvasChanged(this, rect); | 231 (*it)->canvasChanged(this, rect); |
| 233 } | 232 } |
| 234 | 233 |
| 235 void HTMLCanvasElement::reset() | 234 void HTMLCanvasElement::reset() |
| 236 { | 235 { |
| 237 if (m_ignoreReset) | 236 if (m_ignoreReset) |
| 238 return; | 237 return; |
| 239 | 238 |
| 240 bool ok; | 239 bool ok; |
| 241 bool hadImageBuffer = hasCreatedImageBuffer(); | 240 bool hadImageBuffer = m_imageBuffer.get(); |
| 242 | 241 |
| 243 int w = getAttribute(widthAttr).toInt(&ok); | 242 int w = getAttribute(widthAttr).toInt(&ok); |
| 244 if (!ok || w < 0) | 243 if (!ok || w < 0) |
| 245 w = DefaultWidth; | 244 w = DefaultWidth; |
| 246 | 245 |
| 247 int h = getAttribute(heightAttr).toInt(&ok); | 246 int h = getAttribute(heightAttr).toInt(&ok); |
| 248 if (!ok || h < 0) | 247 if (!ok || h < 0) |
| 249 h = DefaultHeight; | 248 h = DefaultHeight; |
| 250 | 249 |
| 251 if (m_contextStateSaver) { | 250 if (m_contextStateSaver) { |
| 252 // Reset to the initial graphics context state. | 251 // Reset to the initial graphics context state. |
| 253 m_contextStateSaver->restore(); | 252 m_contextStateSaver->restore(); |
| 254 m_contextStateSaver->save(); | 253 m_contextStateSaver->save(); |
| 255 } | 254 } |
| 256 | 255 |
| 257 if (m_context && m_context->is2d()) { | 256 if (m_context && m_context->is2d()) { |
| 258 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); | 257 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); |
| 259 context2D->reset(); | 258 context2D->reset(); |
| 260 } | 259 } |
| 261 | 260 |
| 262 IntSize oldSize = size(); | 261 IntSize oldSize = size(); |
| 263 IntSize newSize(w, h); | 262 IntSize newSize(w, h); |
| 264 float newDeviceScaleFactor = 1; | 263 float newDeviceScaleFactor = 1; |
| 265 | 264 |
| 266 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. | 265 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. |
| 267 // This optimization is only done for 2D canvases for now. | 266 // This optimization is only done for 2D canvases for now. |
| 268 if (m_hasCreatedImageBuffer && oldSize == newSize && m_deviceScaleFactor ==
newDeviceScaleFactor && m_context && m_context->is2d()) { | 267 if (m_imageBuffer && oldSize == newSize && m_deviceScaleFactor == newDeviceS
caleFactor && m_context && m_context->is2d()) { |
| 269 if (!m_didClearImageBuffer) | 268 if (!m_didClearImageBuffer) |
| 270 clearImageBuffer(); | 269 clearImageBuffer(); |
| 271 return; | 270 return; |
| 272 } | 271 } |
| 273 | 272 |
| 274 m_deviceScaleFactor = newDeviceScaleFactor; | 273 m_deviceScaleFactor = newDeviceScaleFactor; |
| 275 | 274 |
| 276 setSurfaceSize(newSize); | 275 setSurfaceSize(newSize); |
| 277 | 276 |
| 278 if (m_context && m_context->is3d() && oldSize != size()) | 277 if (m_context && m_context->is3d() && oldSize != size()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 | 315 |
| 317 if (context->paintingDisabled()) | 316 if (context->paintingDisabled()) |
| 318 return; | 317 return; |
| 319 | 318 |
| 320 if (m_context) { | 319 if (m_context) { |
| 321 if (!paintsIntoCanvasBuffer() && !document().printing()) | 320 if (!paintsIntoCanvasBuffer() && !document().printing()) |
| 322 return; | 321 return; |
| 323 m_context->paintRenderingResultsToCanvas(); | 322 m_context->paintRenderingResultsToCanvas(); |
| 324 } | 323 } |
| 325 | 324 |
| 326 if (hasCreatedImageBuffer()) { | 325 ImageBuffer* imageBuffer = buffer(); |
| 327 ImageBuffer* imageBuffer = buffer(); | 326 if (imageBuffer) { |
| 328 if (imageBuffer) { | 327 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha(
) ? CompositeSourceOver : CompositeCopy; |
| 329 CompositeOperator compositeOperator = !m_context || m_context->hasAl
pha() ? CompositeSourceOver : CompositeCopy; | 328 if (m_presentedImage) |
| 330 if (m_presentedImage) | 329 context->drawImage(m_presentedImage.get(), pixelSnappedIntRect(r), c
ompositeOperator, DoNotRespectImageOrientation, useLowQualityScale); |
| 331 context->drawImage(m_presentedImage.get(), pixelSnappedIntRect(r
), compositeOperator, DoNotRespectImageOrientation, useLowQualityScale); | 330 else |
| 332 else | 331 context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), compos
iteOperator, BlendModeNormal, useLowQualityScale); |
| 333 context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), co
mpositeOperator, BlendModeNormal, useLowQualityScale); | |
| 334 } | |
| 335 } | 332 } |
| 336 | 333 |
| 337 if (is3D()) | 334 if (is3D()) |
| 338 static_cast<WebGLRenderingContext*>(m_context.get())->markLayerComposite
d(); | 335 static_cast<WebGLRenderingContext*>(m_context.get())->markLayerComposite
d(); |
| 339 } | 336 } |
| 340 | 337 |
| 341 bool HTMLCanvasElement::is3D() const | 338 bool HTMLCanvasElement::is3D() const |
| 342 { | 339 { |
| 343 return m_context && m_context->is3d(); | 340 return m_context && m_context->is3d(); |
| 344 } | 341 } |
| 345 | 342 |
| 346 void HTMLCanvasElement::makePresentationCopy() | 343 void HTMLCanvasElement::makePresentationCopy() |
| 347 { | 344 { |
| 348 if (!m_presentedImage) { | 345 if (!m_presentedImage) { |
| 349 // The buffer contains the last presented data, so save a copy of it. | 346 // The buffer contains the last presented data, so save a copy of it. |
| 350 m_presentedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 347 m_presentedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
| 351 } | 348 } |
| 352 } | 349 } |
| 353 | 350 |
| 354 void HTMLCanvasElement::clearPresentationCopy() | 351 void HTMLCanvasElement::clearPresentationCopy() |
| 355 { | 352 { |
| 356 m_presentedImage.clear(); | 353 m_presentedImage.clear(); |
| 357 } | 354 } |
| 358 | 355 |
| 359 void HTMLCanvasElement::setSurfaceSize(const IntSize& size) | 356 void HTMLCanvasElement::setSurfaceSize(const IntSize& size) |
| 360 { | 357 { |
| 361 m_size = size; | 358 m_size = size; |
| 362 m_hasCreatedImageBuffer = false; | |
| 363 m_contextStateSaver.clear(); | 359 m_contextStateSaver.clear(); |
| 364 m_imageBuffer.clear(); | 360 m_imageBuffer.clear(); |
| 365 setExternallyAllocatedMemory(0); | 361 setExternallyAllocatedMemory(0); |
| 366 clearCopiedImage(); | 362 clearCopiedImage(); |
| 367 } | 363 } |
| 368 | 364 |
| 369 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType) | 365 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType) |
| 370 { | 366 { |
| 371 String lowercaseMimeType = mimeType.lower(); | 367 String lowercaseMimeType = mimeType.lower(); |
| 372 | 368 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 if (!WebKit::Platform::current()->canAccelerate2dCanvas()) | 467 if (!WebKit::Platform::current()->canAccelerate2dCanvas()) |
| 472 return false; | 468 return false; |
| 473 | 469 |
| 474 return true; | 470 return true; |
| 475 } | 471 } |
| 476 | 472 |
| 477 void HTMLCanvasElement::createImageBuffer() | 473 void HTMLCanvasElement::createImageBuffer() |
| 478 { | 474 { |
| 479 ASSERT(!m_imageBuffer); | 475 ASSERT(!m_imageBuffer); |
| 480 | 476 |
| 481 m_hasCreatedImageBuffer = true; | |
| 482 m_didClearImageBuffer = true; | 477 m_didClearImageBuffer = true; |
| 483 | 478 |
| 484 FloatSize logicalSize = size(); | 479 FloatSize logicalSize = size(); |
| 485 FloatSize deviceSize = convertLogicalToDevice(logicalSize); | 480 FloatSize deviceSize = convertLogicalToDevice(logicalSize); |
| 486 if (!deviceSize.isExpressibleAsIntSize()) | 481 if (!deviceSize.isExpressibleAsIntSize()) |
| 487 return; | 482 return; |
| 488 | 483 |
| 489 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) | 484 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) |
| 490 return; | 485 return; |
| 491 | 486 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 m_externallyAllocatedMemory = externallyAllocatedMemory; | 521 m_externallyAllocatedMemory = externallyAllocatedMemory; |
| 527 } | 522 } |
| 528 | 523 |
| 529 GraphicsContext* HTMLCanvasElement::drawingContext() const | 524 GraphicsContext* HTMLCanvasElement::drawingContext() const |
| 530 { | 525 { |
| 531 return buffer() ? m_imageBuffer->context() : 0; | 526 return buffer() ? m_imageBuffer->context() : 0; |
| 532 } | 527 } |
| 533 | 528 |
| 534 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const | 529 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
| 535 { | 530 { |
| 536 if (!m_hasCreatedImageBuffer) | 531 if (!m_imageBuffer) |
| 537 return 0; | 532 return 0; |
| 538 | 533 |
| 539 return drawingContext(); | 534 return drawingContext(); |
| 540 } | 535 } |
| 541 | 536 |
| 542 ImageBuffer* HTMLCanvasElement::buffer() const | 537 ImageBuffer* HTMLCanvasElement::buffer() const |
| 543 { | 538 { |
| 544 if (!m_hasCreatedImageBuffer) | 539 if (!m_imageBuffer) |
| 545 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); | 540 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
| 546 return m_imageBuffer.get(); | 541 return m_imageBuffer.get(); |
| 547 } | 542 } |
| 548 | 543 |
| 549 Image* HTMLCanvasElement::copiedImage() const | 544 Image* HTMLCanvasElement::copiedImage() const |
| 550 { | 545 { |
| 551 if (!m_copiedImage && buffer()) { | 546 if (!m_copiedImage && buffer()) { |
| 552 if (m_context) | 547 if (m_context) |
| 553 m_context->paintRenderingResultsToCanvas(); | 548 m_context->paintRenderingResultsToCanvas(); |
| 554 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); | 549 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); |
| 555 } | 550 } |
| 556 return m_copiedImage.get(); | 551 return m_copiedImage.get(); |
| 557 } | 552 } |
| 558 | 553 |
| 559 void HTMLCanvasElement::clearImageBuffer() | 554 void HTMLCanvasElement::clearImageBuffer() |
| 560 { | 555 { |
| 561 ASSERT(m_hasCreatedImageBuffer); | 556 ASSERT(m_imageBuffer); |
| 562 ASSERT(!m_didClearImageBuffer); | 557 ASSERT(!m_didClearImageBuffer); |
| 563 ASSERT(m_context); | 558 ASSERT(m_context); |
| 564 | 559 |
| 565 m_didClearImageBuffer = true; | 560 m_didClearImageBuffer = true; |
| 566 | 561 |
| 567 if (m_context->is2d()) { | 562 if (m_context->is2d()) { |
| 568 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); | 563 CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext
2D*>(m_context.get()); |
| 569 // No need to undo transforms/clip/etc. because we are called right afte
r the context is reset. | 564 // No need to undo transforms/clip/etc. because we are called right afte
r the context is reset. |
| 570 context2D->clearRect(0, 0, width(), height()); | 565 context2D->clearRect(0, 0, width(), height()); |
| 571 } | 566 } |
| 572 } | 567 } |
| 573 | 568 |
| 574 void HTMLCanvasElement::clearCopiedImage() | 569 void HTMLCanvasElement::clearCopiedImage() |
| 575 { | 570 { |
| 576 m_copiedImage.clear(); | 571 m_copiedImage.clear(); |
| 577 m_didClearImageBuffer = false; | 572 m_didClearImageBuffer = false; |
| 578 } | 573 } |
| 579 | 574 |
| 580 AffineTransform HTMLCanvasElement::baseTransform() const | 575 AffineTransform HTMLCanvasElement::baseTransform() const |
| 581 { | 576 { |
| 582 ASSERT(m_hasCreatedImageBuffer); | 577 ASSERT(m_imageBuffer); |
| 583 FloatSize unscaledSize = size(); | 578 FloatSize unscaledSize = size(); |
| 584 FloatSize deviceSize = convertLogicalToDevice(unscaledSize); | 579 FloatSize deviceSize = convertLogicalToDevice(unscaledSize); |
| 585 IntSize size(deviceSize.width(), deviceSize.height()); | 580 IntSize size(deviceSize.width(), deviceSize.height()); |
| 586 AffineTransform transform; | 581 AffineTransform transform; |
| 587 if (size.width() && size.height()) | 582 if (size.width() && size.height()) |
| 588 transform.scaleNonUniform(size.width() / unscaledSize.width(), size.heig
ht() / unscaledSize.height()); | 583 transform.scaleNonUniform(size.width() / unscaledSize.width(), size.heig
ht() / unscaledSize.height()); |
| 589 return m_imageBuffer->baseTransform() * transform; | 584 return m_imageBuffer->baseTransform() * transform; |
| 590 } | 585 } |
| 591 | 586 |
| 592 } | 587 } |
| OLD | NEW |