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 |