Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp

Issue 1482363004: Fixing laggy chrome on a multitude of accelerated canvases (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes based on feedbacks from danakj Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLCanvasElement.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 #include <math.h> 62 #include <math.h>
63 #include <v8.h> 63 #include <v8.h>
64 64
65 namespace blink { 65 namespace blink {
66 66
67 using namespace HTMLNames; 67 using namespace HTMLNames;
68 68
69 namespace { 69 namespace {
70 70
71 // These values come from the WhatWG spec. 71 // These values come from the WhatWG spec.
72 const int DefaultWidth = 300; 72 const int kDefaultWidth = 300;
Justin Novosad 2015/12/02 16:33:33 The k prefix is a skia thing. In Blink use Capital
danakj 2015/12/02 18:23:40 It's also a chromium thing, I didn't know blink ha
danakj 2015/12/02 18:31:09 FWIW I only see a blink-specific rule for enums: "
73 const int DefaultHeight = 150; 73 const int kDefaultHeight = 150;
74 74
75 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it 75 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it
76 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions, 76 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions,
77 // in exchange for a smaller maximum canvas size. 77 // in exchange for a smaller maximum canvas size.
78 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels 78 const int kMaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
79 79
80 // In Skia, we will also limit width/height to 32767. 80 // In Skia, we will also limit width/height to 32767.
81 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. 81 const int kMaxSkiaDim = 32767; // Maximum width/height in CSS pixels.
82
83 // We estimate the max limit of GPU allocated memory for canvases before Chrome becomes laggy by setting the
84 // total allocated memory for accelerated canvases to be equivalent to memory us ed by 80 accelerated
85 // canvases, each has a size of 1000*500 and 2d context.
86 // Each such canvas occupies 6000000 = 1000 * 500 * 3 * 4 bytes, where 3 is the bufferCount in
87 // updateExternallyAllocatedMemory() and 4 means four bytes per pixel per buffer .
88 #if !OS(ANDROID)
89 const int kMaxTotalExternallyAllocatedMemory = 6000000 * 80;
90 #else
91 // We estimate that the max limit for android phones is half of that for desktop s based on local
92 // experimental results on Android One; though a very slight lagginess on Androi d One is still expected,
93 // other Android devices should work fine.
94 const int kMaxTotalExternallyAllocatedMemory = 6000000 * 40;
95 #endif
82 96
83 // A default value of quality argument for toDataURL and toBlob 97 // A default value of quality argument for toDataURL and toBlob
84 // It is in an invalid range (outside 0.0 - 1.0) so that it will not be misinter preted as a user-input value 98 // It is in an invalid range (outside 0.0 - 1.0) so that it will not be misinter preted as a user-input value
85 const int UndefinedQualityValue = -1.0; 99 const int kUndefinedQualityValue = -1.0;
86 100
87 // Default image mime type for toDataURL and toBlob functions 101 // Default image mime type for toDataURL and toBlob functions
88 const char DefaultMimeType[] = "image/png"; 102 const char kDefaultMimeType[] = "image/png";
89 103
90 bool canCreateImageBuffer(const IntSize& size) 104 bool canCreateImageBuffer(const IntSize& size)
91 { 105 {
92 if (size.isEmpty()) 106 if (size.isEmpty())
93 return false; 107 return false;
94 if (size.width() * size.height() > MaxCanvasArea) 108 if (size.width() * size.height() > kMaxCanvasArea)
95 return false; 109 return false;
96 if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim) 110 if (size.width() > kMaxSkiaDim || size.height() > kMaxSkiaDim)
97 return false; 111 return false;
98 return true; 112 return true;
99 } 113 }
100 114
101 PassRefPtr<Image> createTransparentImage(const IntSize& size) 115 PassRefPtr<Image> createTransparentImage(const IntSize& size)
102 { 116 {
103 ASSERT(canCreateImageBuffer(size)); 117 ASSERT(canCreateImageBuffer(size));
104 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(size.widt h(), size.height())); 118 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(size.widt h(), size.height()));
105 surface->getCanvas()->clear(SK_ColorTRANSPARENT); 119 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
106 return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); 120 return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot()));
107 } 121 }
108 122
109 } // namespace 123 } // namespace
110 124
111 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) 125 inline HTMLCanvasElement::HTMLCanvasElement(Document& document)
112 : HTMLElement(canvasTag, document) 126 : HTMLElement(canvasTag, document)
113 , DocumentVisibilityObserver(document) 127 , DocumentVisibilityObserver(document)
114 , m_size(DefaultWidth, DefaultHeight) 128 , m_size(kDefaultWidth, kDefaultHeight)
115 , m_ignoreReset(false) 129 , m_ignoreReset(false)
116 , m_externallyAllocatedMemory(0) 130 , m_externallyAllocatedMemory(0)
117 , m_originClean(true) 131 , m_originClean(true)
118 , m_didFailToCreateImageBuffer(false) 132 , m_didFailToCreateImageBuffer(false)
119 , m_imageBufferIsClear(false) 133 , m_imageBufferIsClear(false)
120 { 134 {
121 setHasCustomStyleCallbacks(); 135 setHasCustomStyleCallbacks();
122 CanvasMetrics::countCanvasContextUsage(CanvasMetrics::CanvasCreated); 136 CanvasMetrics::countCanvasContextUsage(CanvasMetrics::CanvasCreated);
123 } 137 }
124 138
125 DEFINE_NODE_FACTORY(HTMLCanvasElement) 139 DEFINE_NODE_FACTORY(HTMLCanvasElement)
126 140
141 intptr_t HTMLCanvasElement::s_totalMemoryForAcceleratedCanvases = 0;
142
127 HTMLCanvasElement::~HTMLCanvasElement() 143 HTMLCanvasElement::~HTMLCanvasElement()
128 { 144 {
129 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_external lyAllocatedMemory); 145 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_external lyAllocatedMemory);
146 if (m_imageBuffer && m_imageBuffer->isAccelerated())
147 updateTotalMemoryForAcceleratedCanvases(-m_externallyAllocatedMemory);
130 #if !ENABLE(OILPAN) 148 #if !ENABLE(OILPAN)
131 // Ensure these go away before the ImageBuffer. 149 // Ensure these go away before the ImageBuffer.
132 m_context.clear(); 150 m_context.clear();
133 #endif 151 #endif
134 } 152 }
135 153
136 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicSt ring& value) 154 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicSt ring& value)
137 { 155 {
138 if (name == widthAttr || name == heightAttr) 156 if (name == widthAttr || name == heightAttr)
139 reset(); 157 reset();
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 if (m_ignoreReset) 358 if (m_ignoreReset)
341 return; 359 return;
342 360
343 m_dirtyRect = FloatRect(); 361 m_dirtyRect = FloatRect();
344 362
345 bool ok; 363 bool ok;
346 bool hadImageBuffer = hasImageBuffer(); 364 bool hadImageBuffer = hasImageBuffer();
347 365
348 int w = getAttribute(widthAttr).toInt(&ok); 366 int w = getAttribute(widthAttr).toInt(&ok);
349 if (!ok || w < 0) 367 if (!ok || w < 0)
350 w = DefaultWidth; 368 w = kDefaultWidth;
351 369
352 int h = getAttribute(heightAttr).toInt(&ok); 370 int h = getAttribute(heightAttr).toInt(&ok);
353 if (!ok || h < 0) 371 if (!ok || h < 0)
354 h = DefaultHeight; 372 h = kDefaultHeight;
355 373
356 if (m_context && m_context->is2d()) 374 if (m_context && m_context->is2d())
357 m_context->reset(); 375 m_context->reset();
358 376
359 IntSize oldSize = size(); 377 IntSize oldSize = size();
360 IntSize newSize(w, h); 378 IntSize newSize(w, h);
361 379
362 // If the size of an existing buffer matches, we can just clear it instead o f reallocating. 380 // If the size of an existing buffer matches, we can just clear it instead o f reallocating.
363 // This optimization is only done for 2D canvases for now. 381 // This optimization is only done for 2D canvases for now.
364 if (hadImageBuffer && oldSize == newSize && m_context && m_context->is2d() & & !buffer()->isRecording()) { 382 if (hadImageBuffer && oldSize == newSize && m_context && m_context->is2d() & & !buffer()->isRecording()) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 m_context->didSetSurfaceSize(); 462 m_context->didSetSurfaceSize();
445 } 463 }
446 } 464 }
447 465
448 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType) 466 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType)
449 { 467 {
450 String lowercaseMimeType = mimeType.lower(); 468 String lowercaseMimeType = mimeType.lower();
451 469
452 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this method to be used on a worker thread). 470 // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this method to be used on a worker thread).
453 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod ing(lowercaseMimeType)) 471 if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncod ing(lowercaseMimeType))
454 lowercaseMimeType = DefaultMimeType; 472 lowercaseMimeType = kDefaultMimeType;
455 473
456 return lowercaseMimeType; 474 return lowercaseMimeType;
457 } 475 }
458 476
459 const AtomicString HTMLCanvasElement::imageSourceURL() const 477 const AtomicString HTMLCanvasElement::imageSourceURL() const
460 { 478 {
461 return AtomicString(toDataURLInternal(DefaultMimeType, 0, FrontBuffer)); 479 return AtomicString(toDataURLInternal(kDefaultMimeType, 0, FrontBuffer));
462 } 480 }
463 481
464 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const 482 void HTMLCanvasElement::prepareSurfaceForPaintingIfNeeded() const
465 { 483 {
466 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d context 484 ASSERT(m_context && m_context->is2d()); // This function is called by the 2d context
467 if (buffer()) 485 if (buffer())
468 m_imageBuffer->prepareSurfaceForPaintingIfNeeded(); 486 m_imageBuffer->prepareSurfaceForPaintingIfNeeded();
469 } 487 }
470 488
471 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer) cons t 489 ImageData* HTMLCanvasElement::toImageData(SourceDrawingBuffer sourceBuffer) cons t
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 532
515 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU RL(encodingMimeType, quality); 533 return ImageDataBuffer(imageData->size(), imageData->data()->data()).toDataU RL(encodingMimeType, quality);
516 } 534 }
517 535
518 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q ualityArgument, ExceptionState& exceptionState) const 536 String HTMLCanvasElement::toDataURL(const String& mimeType, const ScriptValue& q ualityArgument, ExceptionState& exceptionState) const
519 { 537 {
520 if (!originClean()) { 538 if (!originClean()) {
521 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); 539 exceptionState.throwSecurityError("Tainted canvases may not be exported. ");
522 return String(); 540 return String();
523 } 541 }
524 double quality = UndefinedQualityValue; 542 double quality = kUndefinedQualityValue;
525 if (!qualityArgument.isEmpty()) { 543 if (!qualityArgument.isEmpty()) {
526 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); 544 v8::Local<v8::Value> v8Value = qualityArgument.v8Value();
527 if (v8Value->IsNumber()) { 545 if (v8Value->IsNumber()) {
528 quality = v8Value.As<v8::Number>()->Value(); 546 quality = v8Value.As<v8::Number>()->Value();
529 } 547 }
530 } 548 }
531 return toDataURLInternal(mimeType, quality, BackBuffer); 549 return toDataURLInternal(mimeType, quality, BackBuffer);
532 } 550 }
533 551
534 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c onst ScriptValue& qualityArgument, ExceptionState& exceptionState) 552 void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, c onst ScriptValue& qualityArgument, ExceptionState& exceptionState)
535 { 553 {
536 if (!originClean()) { 554 if (!originClean()) {
537 exceptionState.throwSecurityError("Tainted canvases may not be exported. "); 555 exceptionState.throwSecurityError("Tainted canvases may not be exported. ");
538 return; 556 return;
539 } 557 }
540 558
541 if (!isPaintable()) { 559 if (!isPaintable()) {
542 // If the canvas element's bitmap has no pixels 560 // If the canvas element's bitmap has no pixels
543 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER E, bind(&FileCallback::handleEvent, callback, nullptr)); 561 Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HER E, bind(&FileCallback::handleEvent, callback, nullptr));
544 return; 562 return;
545 } 563 }
546 564
547 double quality = UndefinedQualityValue; 565 double quality = kUndefinedQualityValue;
548 if (!qualityArgument.isEmpty()) { 566 if (!qualityArgument.isEmpty()) {
549 v8::Local<v8::Value> v8Value = qualityArgument.v8Value(); 567 v8::Local<v8::Value> v8Value = qualityArgument.v8Value();
550 if (v8Value->IsNumber()) { 568 if (v8Value->IsNumber()) {
551 quality = v8Value.As<v8::Number>()->Value(); 569 quality = v8Value.As<v8::Number>()->Value();
552 } 570 }
553 } 571 }
554 572
555 String encodingMimeType = toEncodingMimeType(mimeType); 573 String encodingMimeType = toEncodingMimeType(mimeType);
556 574
557 ImageData* imageData = toImageData(BackBuffer); 575 ImageData* imageData = toImageData(BackBuffer);
558 // imageData unref its data, which we still keep alive for the async toBlob thread 576 // imageData unref its data, which we still keep alive for the async toBlob thread
559 ScopedDisposal<ImageData> disposer(imageData); 577 ScopedDisposal<ImageData> disposer(imageData);
560 // Add a ref to keep image data alive until completion of encoding 578 // Add a ref to keep image data alive until completion of encoding
561 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); 579 RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data());
562 580
563 RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::cre ate(imageDataRef.release(), encodingMimeType, imageData->size(), callback); 581 RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::cre ate(imageDataRef.release(), encodingMimeType, imageData->size(), callback);
564 if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == DefaultMimeType)) { 582 if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == kDefaultMimeType)) {
565 asyncCreatorRef->scheduleAsyncBlobCreation(true); 583 asyncCreatorRef->scheduleAsyncBlobCreation(true);
566 } else { 584 } else {
567 asyncCreatorRef->scheduleAsyncBlobCreation(false, quality); 585 asyncCreatorRef->scheduleAsyncBlobCreation(false, quality);
568 } 586 }
569 } 587 }
570 588
571 SecurityOrigin* HTMLCanvasElement::securityOrigin() const 589 SecurityOrigin* HTMLCanvasElement::securityOrigin() const
572 { 590 {
573 return document().securityOrigin(); 591 return document().securityOrigin();
574 } 592 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 return false; 627 return false;
610 } 628 }
611 629
612 // Do not use acceleration for small canvas. 630 // Do not use acceleration for small canvas.
613 if (canvasPixelCount < settings->minimumAccelerated2dCanvasSize()) 631 if (canvasPixelCount < settings->minimumAccelerated2dCanvasSize())
614 return false; 632 return false;
615 633
616 if (!Platform::current()->canAccelerate2dCanvas()) 634 if (!Platform::current()->canAccelerate2dCanvas())
617 return false; 635 return false;
618 636
637 // When GPU allocated memory runs low (due to having created too many accele rated canvases), the
638 // compositor starves and browser becomes laggy. Thus, we should stop alloca ting more GPU memory to
639 // new canvases created when the current memory usage exceeds the threshold.
640 if (s_totalMemoryForAcceleratedCanvases >= kMaxTotalExternallyAllocatedMemor y)
Justin Novosad 2015/12/02 16:33:34 Constant should be named in a way that reflects th
641 return false;
642
619 return true; 643 return true;
620 } 644 }
621 645
622 class UnacceleratedSurfaceFactory : public RecordingImageBufferFallbackSurfaceFa ctory { 646 class UnacceleratedSurfaceFactory : public RecordingImageBufferFallbackSurfaceFa ctory {
623 public: 647 public:
624 virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize& size, Op acityMode opacityMode) 648 virtual PassOwnPtr<ImageBufferSurface> createSurface(const IntSize& size, Op acityMode opacityMode)
625 { 649 {
626 return adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode)); 650 return adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode));
627 } 651 }
628 652
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 if (is3D()) 793 if (is3D())
770 checkedExternallyAllocatedMemory += m_context->externallyAllocatedBytesP erPixel(); 794 checkedExternallyAllocatedMemory += m_context->externallyAllocatedBytesP erPixel();
771 795
772 checkedExternallyAllocatedMemory *= width(); 796 checkedExternallyAllocatedMemory *= width();
773 checkedExternallyAllocatedMemory *= height(); 797 checkedExternallyAllocatedMemory *= height();
774 intptr_t externallyAllocatedMemory; 798 intptr_t externallyAllocatedMemory;
775 if (checkedExternallyAllocatedMemory.safeGet(externallyAllocatedMemory) == C heckedState::DidOverflow) 799 if (checkedExternallyAllocatedMemory.safeGet(externallyAllocatedMemory) == C heckedState::DidOverflow)
776 externallyAllocatedMemory = std::numeric_limits<intptr_t>::max(); 800 externallyAllocatedMemory = std::numeric_limits<intptr_t>::max();
777 801
778 // Subtracting two intptr_t that are known to be positive will never underfl ow. 802 // Subtracting two intptr_t that are known to be positive will never underfl ow.
779 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(externallyA llocatedMemory - m_externallyAllocatedMemory); 803 intptr_t diffFromCurrAllocatedMemory = externallyAllocatedMemory - m_externa llyAllocatedMemory;
804 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(diffFromCur rAllocatedMemory);
780 m_externallyAllocatedMemory = externallyAllocatedMemory; 805 m_externallyAllocatedMemory = externallyAllocatedMemory;
806
807 if (m_imageBuffer && m_imageBuffer->isAccelerated())
808 updateTotalMemoryForAcceleratedCanvases(diffFromCurrAllocatedMemory);
Justin Novosad 2015/12/02 16:33:34 This is wrong. You need to track gpu allocated mem
809 }
810
811 void HTMLCanvasElement::updateTotalMemoryForAcceleratedCanvases(intptr_t diffFro mCurrAllocatedMemory)
812 {
813 ASSERT(isMainThread());
814
815 Checked<intptr_t, RecordOverflow> checkedExternallyAllocatedMemory = s_total MemoryForAcceleratedCanvases;
Justin Novosad 2015/12/02 16:33:33 Don't use the term "ExternallyAllocated" here, it
816 checkedExternallyAllocatedMemory += diffFromCurrAllocatedMemory;
817 intptr_t externallyAllocatedMemory;
818 if (checkedExternallyAllocatedMemory.safeGet(externallyAllocatedMemory) == C heckedState::DidOverflow)
819 externallyAllocatedMemory = std::numeric_limits<intptr_t>::max();
820
821 s_totalMemoryForAcceleratedCanvases = externallyAllocatedMemory;
781 } 822 }
782 823
783 SkCanvas* HTMLCanvasElement::drawingCanvas() const 824 SkCanvas* HTMLCanvasElement::drawingCanvas() const
784 { 825 {
785 return buffer() ? m_imageBuffer->canvas() : nullptr; 826 return buffer() ? m_imageBuffer->canvas() : nullptr;
786 } 827 }
787 828
788 void HTMLCanvasElement::disableDeferral() const 829 void HTMLCanvasElement::disableDeferral() const
789 { 830 {
790 if (buffer()) 831 if (buffer())
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
952 } 993 }
953 return ImageBitmapSource::fulfillImageBitmap(scriptState, isPaintable() ? Im ageBitmap::create(this, IntRect(sx, sy, sw, sh)) : nullptr); 994 return ImageBitmapSource::fulfillImageBitmap(scriptState, isPaintable() ? Im ageBitmap::create(this, IntRect(sx, sy, sw, sh)) : nullptr);
954 } 995 }
955 996
956 bool HTMLCanvasElement::isOpaque() const 997 bool HTMLCanvasElement::isOpaque() const
957 { 998 {
958 return m_context && !m_context->hasAlpha(); 999 return m_context && !m_context->hasAlpha();
959 } 1000 }
960 1001
961 } // blink 1002 } // blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLCanvasElement.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698