| 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 27 matching lines...) Expand all Loading... |
| 38 #include "core/dom/ExceptionCode.h" | 38 #include "core/dom/ExceptionCode.h" |
| 39 #include "core/html/ImageData.h" | 39 #include "core/html/ImageData.h" |
| 40 #include "core/html/canvas/Canvas2DContextAttributes.h" | 40 #include "core/html/canvas/Canvas2DContextAttributes.h" |
| 41 #include "core/html/canvas/CanvasRenderingContext2D.h" | 41 #include "core/html/canvas/CanvasRenderingContext2D.h" |
| 42 #include "core/html/canvas/WebGLContextAttributes.h" | 42 #include "core/html/canvas/WebGLContextAttributes.h" |
| 43 #include "core/html/canvas/WebGLRenderingContext.h" | 43 #include "core/html/canvas/WebGLRenderingContext.h" |
| 44 #include "core/frame/Frame.h" | 44 #include "core/frame/Frame.h" |
| 45 #include "core/page/Settings.h" | 45 #include "core/page/Settings.h" |
| 46 #include "core/rendering/RenderHTMLCanvas.h" | 46 #include "core/rendering/RenderHTMLCanvas.h" |
| 47 #include "platform/MIMETypeRegistry.h" | 47 #include "platform/MIMETypeRegistry.h" |
| 48 #include "platform/graphics/Canvas2DImageBufferSurface.h" |
| 48 #include "platform/graphics/GraphicsContextStateSaver.h" | 49 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 49 #include "platform/graphics/ImageBuffer.h" | 50 #include "platform/graphics/ImageBuffer.h" |
| 51 #include "platform/graphics/UnacceleratedImageBufferSurface.h" |
| 52 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" |
| 50 #include "public/platform/Platform.h" | 53 #include "public/platform/Platform.h" |
| 51 | 54 |
| 52 namespace WebCore { | 55 namespace WebCore { |
| 53 | 56 |
| 54 using namespace HTMLNames; | 57 using namespace HTMLNames; |
| 55 | 58 |
| 56 // These values come from the WhatWG spec. | 59 // These values come from the WhatWG spec. |
| 57 static const int DefaultWidth = 300; | 60 static const int DefaultWidth = 300; |
| 58 static const int DefaultHeight = 150; | 61 static const int DefaultHeight = 150; |
| 59 | 62 |
| 60 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo
re it | 63 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo
re it |
| 61 // reaches that limit. We limit by area instead, giving us larger maximum dimens
ions, | 64 // reaches that limit. We limit by area instead, giving us larger maximum dimens
ions, |
| 62 // in exchange for a smaller maximum canvas size. | 65 // in exchange for a smaller maximum canvas size. |
| 63 static const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pix
els | 66 static const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pix
els |
| 64 | 67 |
| 65 //In Skia, we will also limit width/height to 32767. | 68 //In Skia, we will also limit width/height to 32767. |
| 66 static const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. | 69 static const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. |
| 67 | 70 |
| 68 HTMLCanvasElement::HTMLCanvasElement(Document& document) | 71 HTMLCanvasElement::HTMLCanvasElement(Document& document) |
| 69 : HTMLElement(canvasTag, document) | 72 : HTMLElement(canvasTag, document) |
| 70 , m_size(DefaultWidth, DefaultHeight) | 73 , m_size(DefaultWidth, DefaultHeight) |
| 71 , m_rendererIsCanvas(false) | 74 , m_rendererIsCanvas(false) |
| 72 , m_ignoreReset(false) | 75 , m_ignoreReset(false) |
| 73 , m_accelerationDisabled(false) | 76 , m_accelerationDisabled(false) |
| 74 , m_externallyAllocatedMemory(0) | 77 , m_externallyAllocatedMemory(0) |
| 75 , m_deviceScaleFactor(1) | |
| 76 , m_originClean(true) | 78 , m_originClean(true) |
| 77 , m_didFailToCreateImageBuffer(false) | 79 , m_didFailToCreateImageBuffer(false) |
| 78 , m_didClearImageBuffer(false) | 80 , m_didClearImageBuffer(false) |
| 79 { | 81 { |
| 80 ScriptWrappable::init(this); | 82 ScriptWrappable::init(this); |
| 81 } | 83 } |
| 82 | 84 |
| 83 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) | 85 PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document) |
| 84 { | 86 { |
| 85 return adoptRef(new HTMLCanvasElement(document)); | 87 return adoptRef(new HTMLCanvasElement(document)); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 // Reset to the initial graphics context state. | 247 // Reset to the initial graphics context state. |
| 246 m_contextStateSaver->restore(); | 248 m_contextStateSaver->restore(); |
| 247 m_contextStateSaver->save(); | 249 m_contextStateSaver->save(); |
| 248 } | 250 } |
| 249 | 251 |
| 250 if (m_context && m_context->is2d()) | 252 if (m_context && m_context->is2d()) |
| 251 toCanvasRenderingContext2D(m_context.get())->reset(); | 253 toCanvasRenderingContext2D(m_context.get())->reset(); |
| 252 | 254 |
| 253 IntSize oldSize = size(); | 255 IntSize oldSize = size(); |
| 254 IntSize newSize(w, h); | 256 IntSize newSize(w, h); |
| 255 float newDeviceScaleFactor = 1; | |
| 256 | 257 |
| 257 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. | 258 // If the size of an existing buffer matches, we can just clear it instead o
f reallocating. |
| 258 // This optimization is only done for 2D canvases for now. | 259 // This optimization is only done for 2D canvases for now. |
| 259 if (hadImageBuffer && oldSize == newSize && m_deviceScaleFactor == newDevice
ScaleFactor && m_context && m_context->is2d()) { | 260 if (hadImageBuffer && oldSize == newSize && m_context && m_context->is2d())
{ |
| 260 if (!m_didClearImageBuffer) | 261 if (!m_didClearImageBuffer) |
| 261 clearImageBuffer(); | 262 clearImageBuffer(); |
| 262 return; | 263 return; |
| 263 } | 264 } |
| 264 | 265 |
| 265 m_deviceScaleFactor = newDeviceScaleFactor; | |
| 266 | |
| 267 setSurfaceSize(newSize); | 266 setSurfaceSize(newSize); |
| 268 | 267 |
| 269 if (m_context && m_context->is3d() && oldSize != size()) | 268 if (m_context && m_context->is3d() && oldSize != size()) |
| 270 toWebGLRenderingContext(m_context.get())->reshape(width(), height()); | 269 toWebGLRenderingContext(m_context.get())->reshape(width(), height()); |
| 271 | 270 |
| 272 if (RenderObject* renderer = this->renderer()) { | 271 if (RenderObject* renderer = this->renderer()) { |
| 273 if (m_rendererIsCanvas) { | 272 if (m_rendererIsCanvas) { |
| 274 if (oldSize != size()) { | 273 if (oldSize != size()) { |
| 275 toRenderHTMLCanvas(renderer)->canvasSizeChanged(); | 274 toRenderHTMLCanvas(renderer)->canvasSizeChanged(); |
| 276 if (renderBox() && renderBox()->hasAcceleratedCompositing()) | 275 if (renderBox() && renderBox()->hasAcceleratedCompositing()) |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 return buffer()->toDataURL(encodingMimeType, quality); | 391 return buffer()->toDataURL(encodingMimeType, quality); |
| 393 } | 392 } |
| 394 | 393 |
| 395 PassRefPtr<ImageData> HTMLCanvasElement::getImageData() | 394 PassRefPtr<ImageData> HTMLCanvasElement::getImageData() |
| 396 { | 395 { |
| 397 if (!m_context || !m_context->is3d()) | 396 if (!m_context || !m_context->is3d()) |
| 398 return 0; | 397 return 0; |
| 399 return toWebGLRenderingContext(m_context.get())->paintRenderingResultsToImag
eData(); | 398 return toWebGLRenderingContext(m_context.get())->paintRenderingResultsToImag
eData(); |
| 400 } | 399 } |
| 401 | 400 |
| 402 IntSize HTMLCanvasElement::convertLogicalToDevice(const IntSize& logicalSize) co
nst | |
| 403 { | |
| 404 FloatSize deviceSize = logicalSize * m_deviceScaleFactor; | |
| 405 return expandedIntSize(deviceSize); | |
| 406 } | |
| 407 | |
| 408 SecurityOrigin* HTMLCanvasElement::securityOrigin() const | 401 SecurityOrigin* HTMLCanvasElement::securityOrigin() const |
| 409 { | 402 { |
| 410 return document().securityOrigin(); | 403 return document().securityOrigin(); |
| 411 } | 404 } |
| 412 | 405 |
| 413 bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const | 406 bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const |
| 414 { | 407 { |
| 415 if (m_context && !m_context->is2d()) | 408 if (m_context && !m_context->is2d()) |
| 416 return false; | 409 return false; |
| 417 | 410 |
| 418 if (m_accelerationDisabled) | 411 if (m_accelerationDisabled) |
| 419 return false; | 412 return false; |
| 420 | 413 |
| 421 Settings* settings = document().settings(); | 414 Settings* settings = document().settings(); |
| 422 if (!settings || !settings->accelerated2dCanvasEnabled()) | 415 if (!settings || !settings->accelerated2dCanvasEnabled()) |
| 423 return false; | 416 return false; |
| 424 | 417 |
| 425 // Do not use acceleration for small canvas. | 418 // Do not use acceleration for small canvas. |
| 426 if (size.width() * size.height() < settings->minimumAccelerated2dCanvasSize(
)) | 419 if (size.width() * size.height() < settings->minimumAccelerated2dCanvasSize(
)) |
| 427 return false; | 420 return false; |
| 428 | 421 |
| 429 if (!blink::Platform::current()->canAccelerate2dCanvas()) | 422 if (!blink::Platform::current()->canAccelerate2dCanvas()) |
| 430 return false; | 423 return false; |
| 431 | 424 |
| 432 return true; | 425 return true; |
| 433 } | 426 } |
| 434 | 427 |
| 428 PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const
IntSize& deviceSize, int* msaaSampleCount) |
| 429 { |
| 430 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque :
Opaque; |
| 431 |
| 432 *msaaSampleCount = 0; |
| 433 if (is3D()) |
| 434 return adoptPtr(new WebGLImageBufferSurface(size(), opacityMode)); |
| 435 |
| 436 if (shouldAccelerate(deviceSize)) { |
| 437 if (document().settings()) |
| 438 *msaaSampleCount = document().settings()->accelerated2dCanvasMSAASam
pleCount(); |
| 439 OwnPtr<ImageBufferSurface> surface = adoptPtr(new Canvas2DImageBufferSur
face(size(), opacityMode, *msaaSampleCount)); |
| 440 if (surface->isValid()) |
| 441 return surface.release(); |
| 442 } |
| 443 |
| 444 return adoptPtr(new UnacceleratedImageBufferSurface(size(), opacityMode)); |
| 445 } |
| 446 |
| 435 void HTMLCanvasElement::createImageBuffer() | 447 void HTMLCanvasElement::createImageBuffer() |
| 436 { | 448 { |
| 437 ASSERT(!m_imageBuffer); | 449 ASSERT(!m_imageBuffer); |
| 438 | 450 |
| 439 m_didFailToCreateImageBuffer = true; | 451 m_didFailToCreateImageBuffer = true; |
| 440 m_didClearImageBuffer = true; | 452 m_didClearImageBuffer = true; |
| 441 | 453 |
| 442 IntSize deviceSize = convertLogicalToDevice(size()); | 454 IntSize deviceSize = size(); |
| 443 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) | 455 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) |
| 444 return; | 456 return; |
| 445 | 457 |
| 446 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) | 458 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) |
| 447 return; | 459 return; |
| 448 | 460 |
| 449 if (!deviceSize.width() || !deviceSize.height()) | 461 if (!deviceSize.width() || !deviceSize.height()) |
| 450 return; | 462 return; |
| 451 | 463 |
| 452 RenderingMode renderingMode = is3D() ? TextureBacked : (shouldAccelerate(dev
iceSize) ? Accelerated : UnacceleratedNonPlatformBuffer); | 464 int msaaSampleCount; |
| 453 int msaaSampleCount = 0; | 465 OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(deviceSize, &m
saaSampleCount); |
| 454 if (document().settings()) | 466 if (!surface->isValid()) |
| 455 msaaSampleCount = document().settings()->accelerated2dCanvasMSAASampleCo
unt(); | |
| 456 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque :
Opaque; | |
| 457 m_imageBuffer = ImageBuffer::create(size(), m_deviceScaleFactor, renderingMo
de, opacityMode, msaaSampleCount); | |
| 458 if (!m_imageBuffer) | |
| 459 return; | 467 return; |
| 468 m_imageBuffer = ImageBuffer::create(surface.release()); |
| 469 |
| 460 m_didFailToCreateImageBuffer = false; | 470 m_didFailToCreateImageBuffer = false; |
| 471 |
| 461 setExternallyAllocatedMemory(4 * width() * height()); | 472 setExternallyAllocatedMemory(4 * width() * height()); |
| 473 |
| 474 if (is3D()) { |
| 475 // Early out for WebGL canvases |
| 476 m_contextStateSaver.clear(); |
| 477 return; |
| 478 } |
| 479 |
| 462 m_imageBuffer->context()->setShouldClampToSourceRect(false); | 480 m_imageBuffer->context()->setShouldClampToSourceRect(false); |
| 463 m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQ
uality); | 481 m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQ
uality); |
| 464 // Enabling MSAA overrides a request to disable antialiasing. This is true r
egardless of whether the | 482 // Enabling MSAA overrides a request to disable antialiasing. This is true r
egardless of whether the |
| 465 // rendering mode is accelerated or not. For consistency, we don't want to a
pply AA in accelerated | 483 // rendering mode is accelerated or not. For consistency, we don't want to a
pply AA in accelerated |
| 466 // canvases but not in unaccelerated canvases. | 484 // canvases but not in unaccelerated canvases. |
| 467 if (!msaaSampleCount && document().settings() && !document().settings()->ant
ialiased2dCanvasEnabled()) | 485 if (!msaaSampleCount && document().settings() && !document().settings()->ant
ialiased2dCanvasEnabled()) |
| 468 m_imageBuffer->context()->setShouldAntialias(false); | 486 m_imageBuffer->context()->setShouldAntialias(false); |
| 469 // GraphicsContext's defaults don't always agree with the 2d canvas spec. | 487 // GraphicsContext's defaults don't always agree with the 2d canvas spec. |
| 470 // See CanvasRenderingContext2D::State::State() for more information. | 488 // See CanvasRenderingContext2D::State::State() for more information. |
| 471 m_imageBuffer->context()->setMiterLimit(10); | 489 m_imageBuffer->context()->setMiterLimit(10); |
| 472 m_imageBuffer->context()->setStrokeThickness(1); | 490 m_imageBuffer->context()->setStrokeThickness(1); |
| 473 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer-
>context())); | 491 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer-
>context())); |
| 474 | 492 |
| 475 // Recalculate compositing requirements if acceleration state changed. | 493 // Recalculate compositing requirements if acceleration state changed. |
| 476 if (m_context && m_context->is2d()) | 494 if (m_context) |
| 477 scheduleLayerUpdate(); | 495 scheduleLayerUpdate(); |
| 478 } | 496 } |
| 479 | 497 |
| 480 void HTMLCanvasElement::setExternallyAllocatedMemory(intptr_t externallyAllocate
dMemory) | 498 void HTMLCanvasElement::setExternallyAllocatedMemory(intptr_t externallyAllocate
dMemory) |
| 481 { | 499 { |
| 482 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(externallyA
llocatedMemory - m_externallyAllocatedMemory); | 500 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(externallyA
llocatedMemory - m_externallyAllocatedMemory); |
| 483 m_externallyAllocatedMemory = externallyAllocatedMemory; | 501 m_externallyAllocatedMemory = externallyAllocatedMemory; |
| 484 } | 502 } |
| 485 | 503 |
| 486 GraphicsContext* HTMLCanvasElement::drawingContext() const | 504 GraphicsContext* HTMLCanvasElement::drawingContext() const |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 | 550 |
| 533 void HTMLCanvasElement::clearCopiedImage() | 551 void HTMLCanvasElement::clearCopiedImage() |
| 534 { | 552 { |
| 535 m_copiedImage.clear(); | 553 m_copiedImage.clear(); |
| 536 m_didClearImageBuffer = false; | 554 m_didClearImageBuffer = false; |
| 537 } | 555 } |
| 538 | 556 |
| 539 AffineTransform HTMLCanvasElement::baseTransform() const | 557 AffineTransform HTMLCanvasElement::baseTransform() const |
| 540 { | 558 { |
| 541 ASSERT(hasImageBuffer() && !m_didFailToCreateImageBuffer); | 559 ASSERT(hasImageBuffer() && !m_didFailToCreateImageBuffer); |
| 542 IntSize unscaledSize = size(); | 560 return m_imageBuffer->baseTransform(); |
| 543 IntSize size = convertLogicalToDevice(unscaledSize); | |
| 544 AffineTransform transform; | |
| 545 if (size.width() && size.height()) | |
| 546 transform.scaleNonUniform(size.width() / unscaledSize.width(), size.heig
ht() / unscaledSize.height()); | |
| 547 return m_imageBuffer->baseTransform() * transform; | |
| 548 } | 561 } |
| 549 | 562 |
| 550 } | 563 } |
| OLD | NEW |