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 |