HTMLCanvasElement.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/HTMLCanvasElement.h"
  6. #include "ImageEncoder.h"
  7. #include "jsapi.h"
  8. #include "jsfriendapi.h"
  9. #include "Layers.h"
  10. #include "MediaSegment.h"
  11. #include "mozilla/Assertions.h"
  12. #include "mozilla/Base64.h"
  13. #include "mozilla/CheckedInt.h"
  14. #include "mozilla/dom/CanvasCaptureMediaStream.h"
  15. #include "mozilla/dom/CanvasRenderingContext2D.h"
  16. #include "mozilla/dom/File.h"
  17. #include "mozilla/dom/HTMLCanvasElementBinding.h"
  18. #include "mozilla/dom/MediaStreamTrack.h"
  19. #include "mozilla/dom/MouseEvent.h"
  20. #include "mozilla/dom/OffscreenCanvas.h"
  21. #include "mozilla/EventDispatcher.h"
  22. #include "mozilla/gfx/Rect.h"
  23. #include "mozilla/layers/AsyncCanvasRenderer.h"
  24. #include "mozilla/MouseEvents.h"
  25. #include "mozilla/Preferences.h"
  26. #include "mozilla/Telemetry.h"
  27. #include "nsAttrValueInlines.h"
  28. #include "nsContentUtils.h"
  29. #include "nsDisplayList.h"
  30. #include "nsDOMJSUtils.h"
  31. #include "nsIScriptSecurityManager.h"
  32. #include "nsITimer.h"
  33. #include "nsIWritablePropertyBag2.h"
  34. #include "nsIXPConnect.h"
  35. #include "nsJSUtils.h"
  36. #include "nsLayoutUtils.h"
  37. #include "nsMathUtils.h"
  38. #include "nsNetUtil.h"
  39. #include "nsRefreshDriver.h"
  40. #include "nsStreamUtils.h"
  41. #include "ActiveLayerTracker.h"
  42. #include "WebGL1Context.h"
  43. #include "WebGL2Context.h"
  44. using namespace mozilla::layers;
  45. using namespace mozilla::gfx;
  46. NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
  47. namespace mozilla {
  48. namespace dom {
  49. class RequestedFrameRefreshObserver : public nsARefreshObserver
  50. {
  51. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestedFrameRefreshObserver, override)
  52. public:
  53. RequestedFrameRefreshObserver(HTMLCanvasElement* const aOwningElement,
  54. nsRefreshDriver* aRefreshDriver)
  55. : mRegistered(false),
  56. mOwningElement(aOwningElement),
  57. mRefreshDriver(aRefreshDriver)
  58. {
  59. MOZ_ASSERT(mOwningElement);
  60. }
  61. static already_AddRefed<DataSourceSurface>
  62. CopySurface(const RefPtr<SourceSurface>& aSurface)
  63. {
  64. RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
  65. if (!data) {
  66. return nullptr;
  67. }
  68. DataSourceSurface::ScopedMap read(data, DataSourceSurface::READ);
  69. if (!read.IsMapped()) {
  70. return nullptr;
  71. }
  72. RefPtr<DataSourceSurface> copy =
  73. Factory::CreateDataSourceSurfaceWithStride(data->GetSize(),
  74. data->GetFormat(),
  75. read.GetStride());
  76. if (!copy) {
  77. return nullptr;
  78. }
  79. DataSourceSurface::ScopedMap write(copy, DataSourceSurface::WRITE);
  80. if (!write.IsMapped()) {
  81. return nullptr;
  82. }
  83. MOZ_ASSERT(read.GetStride() == write.GetStride());
  84. MOZ_ASSERT(data->GetSize() == copy->GetSize());
  85. MOZ_ASSERT(data->GetFormat() == copy->GetFormat());
  86. memcpy(write.GetData(), read.GetData(),
  87. write.GetStride() * copy->GetSize().height);
  88. return copy.forget();
  89. }
  90. void WillRefresh(TimeStamp aTime) override
  91. {
  92. MOZ_ASSERT(NS_IsMainThread());
  93. if (!mOwningElement) {
  94. return;
  95. }
  96. if (mOwningElement->IsWriteOnly()) {
  97. return;
  98. }
  99. if (mOwningElement->IsContextCleanForFrameCapture()) {
  100. return;
  101. }
  102. mOwningElement->ProcessDestroyedFrameListeners();
  103. if (!mOwningElement->IsFrameCaptureRequested()) {
  104. return;
  105. }
  106. RefPtr<SourceSurface> snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
  107. if (!snapshot) {
  108. return;
  109. }
  110. RefPtr<DataSourceSurface> copy = CopySurface(snapshot);
  111. if (!copy) {
  112. return;
  113. }
  114. mOwningElement->SetFrameCapture(copy.forget());
  115. mOwningElement->MarkContextCleanForFrameCapture();
  116. }
  117. void DetachFromRefreshDriver()
  118. {
  119. MOZ_ASSERT(mOwningElement);
  120. MOZ_ASSERT(mRefreshDriver);
  121. Unregister();
  122. mRefreshDriver = nullptr;
  123. }
  124. void Register()
  125. {
  126. if (mRegistered) {
  127. return;
  128. }
  129. MOZ_ASSERT(mRefreshDriver);
  130. if (mRefreshDriver) {
  131. mRefreshDriver->AddRefreshObserver(this, Flush_Display);
  132. mRegistered = true;
  133. }
  134. }
  135. void Unregister()
  136. {
  137. if (!mRegistered) {
  138. return;
  139. }
  140. MOZ_ASSERT(mRefreshDriver);
  141. if (mRefreshDriver) {
  142. mRefreshDriver->RemoveRefreshObserver(this, Flush_Display);
  143. mRegistered = false;
  144. }
  145. }
  146. private:
  147. virtual ~RequestedFrameRefreshObserver()
  148. {
  149. MOZ_ASSERT(!mRefreshDriver);
  150. MOZ_ASSERT(!mRegistered);
  151. }
  152. bool mRegistered;
  153. HTMLCanvasElement* const mOwningElement;
  154. RefPtr<nsRefreshDriver> mRefreshDriver;
  155. };
  156. // ---------------------------------------------------------------------------
  157. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState, mCanvas,
  158. mContext, mCallback)
  159. NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
  160. NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
  161. HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
  162. nsICanvasRenderingContextInternal* aContext,
  163. nsITimerCallback* aCallback)
  164. : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
  165. mContext(aContext), mCallback(aCallback)
  166. {
  167. }
  168. HTMLCanvasPrintState::~HTMLCanvasPrintState()
  169. {
  170. }
  171. /* virtual */ JSObject*
  172. HTMLCanvasPrintState::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  173. {
  174. return MozCanvasPrintStateBinding::Wrap(aCx, this, aGivenProto);
  175. }
  176. nsISupports*
  177. HTMLCanvasPrintState::Context() const
  178. {
  179. return mContext;
  180. }
  181. void
  182. HTMLCanvasPrintState::Done()
  183. {
  184. if (!mPendingNotify && !mIsDone) {
  185. // The canvas needs to be invalidated for printing reftests on linux to
  186. // work.
  187. if (mCanvas) {
  188. mCanvas->InvalidateCanvas();
  189. }
  190. RefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
  191. NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
  192. if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
  193. mPendingNotify = true;
  194. }
  195. }
  196. }
  197. void
  198. HTMLCanvasPrintState::NotifyDone()
  199. {
  200. mIsDone = true;
  201. mPendingNotify = false;
  202. if (mCallback) {
  203. mCallback->Notify(nullptr);
  204. }
  205. }
  206. // ---------------------------------------------------------------------------
  207. HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement)
  208. : mElement(aElement)
  209. {
  210. RegisterVisibilityChangeEvent();
  211. RegisterMemoryPressureEvent();
  212. }
  213. HTMLCanvasElementObserver::~HTMLCanvasElementObserver()
  214. {
  215. Destroy();
  216. }
  217. void
  218. HTMLCanvasElementObserver::Destroy()
  219. {
  220. UnregisterMemoryPressureEvent();
  221. UnregisterVisibilityChangeEvent();
  222. mElement = nullptr;
  223. }
  224. void
  225. HTMLCanvasElementObserver::RegisterVisibilityChangeEvent()
  226. {
  227. if (!mElement) {
  228. return;
  229. }
  230. nsIDocument* document = mElement->OwnerDoc();
  231. document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
  232. this, true, false);
  233. }
  234. void
  235. HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent()
  236. {
  237. if (!mElement) {
  238. return;
  239. }
  240. nsIDocument* document = mElement->OwnerDoc();
  241. document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
  242. this, true);
  243. }
  244. void
  245. HTMLCanvasElementObserver::RegisterMemoryPressureEvent()
  246. {
  247. if (!mElement) {
  248. return;
  249. }
  250. nsCOMPtr<nsIObserverService> observerService =
  251. mozilla::services::GetObserverService();
  252. MOZ_ASSERT(observerService);
  253. if (observerService)
  254. observerService->AddObserver(this, "memory-pressure", false);
  255. }
  256. void
  257. HTMLCanvasElementObserver::UnregisterMemoryPressureEvent()
  258. {
  259. if (!mElement) {
  260. return;
  261. }
  262. nsCOMPtr<nsIObserverService> observerService =
  263. mozilla::services::GetObserverService();
  264. // Do not assert on observerService here. This might be triggered by
  265. // the cycle collector at a late enough time, that XPCOM services are
  266. // no longer available. See bug 1029504.
  267. if (observerService)
  268. observerService->RemoveObserver(this, "memory-pressure");
  269. }
  270. NS_IMETHODIMP
  271. HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*)
  272. {
  273. if (!mElement || strcmp(aTopic, "memory-pressure")) {
  274. return NS_OK;
  275. }
  276. mElement->OnMemoryPressure();
  277. return NS_OK;
  278. }
  279. NS_IMETHODIMP
  280. HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent)
  281. {
  282. nsAutoString type;
  283. aEvent->GetType(type);
  284. if (!mElement || !type.EqualsLiteral("visibilitychange")) {
  285. return NS_OK;
  286. }
  287. mElement->OnVisibilityChange();
  288. return NS_OK;
  289. }
  290. NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
  291. // ---------------------------------------------------------------------------
  292. HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
  293. : nsGenericHTMLElement(aNodeInfo),
  294. mResetLayer(true) ,
  295. mWriteOnly(false)
  296. {}
  297. HTMLCanvasElement::~HTMLCanvasElement()
  298. {
  299. if (mContextObserver) {
  300. mContextObserver->Destroy();
  301. mContextObserver = nullptr;
  302. }
  303. ResetPrintCallback();
  304. if (mRequestedFrameRefreshObserver) {
  305. mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
  306. }
  307. if (mAsyncCanvasRenderer) {
  308. mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
  309. }
  310. }
  311. NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
  312. mCurrentContext, mPrintCallback,
  313. mPrintState, mOriginalCanvas,
  314. mOffscreenCanvas)
  315. NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element)
  316. NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element)
  317. NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement)
  318. NS_INTERFACE_TABLE_INHERITED(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
  319. NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
  320. NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
  321. /* virtual */ JSObject*
  322. HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  323. {
  324. return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
  325. }
  326. already_AddRefed<nsICanvasRenderingContextInternal>
  327. HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
  328. {
  329. // Note that the compositor backend will be LAYERS_NONE if there is no widget.
  330. RefPtr<nsICanvasRenderingContextInternal> ret =
  331. CreateContextHelper(aContextType, GetCompositorBackendType());
  332. // Add Observer for webgl canvas.
  333. if (aContextType == CanvasContextType::WebGL1 ||
  334. aContextType == CanvasContextType::WebGL2) {
  335. if (!mContextObserver) {
  336. mContextObserver = new HTMLCanvasElementObserver(this);
  337. }
  338. }
  339. ret->SetCanvasElement(this);
  340. return ret.forget();
  341. }
  342. nsIntSize
  343. HTMLCanvasElement::GetWidthHeight()
  344. {
  345. nsIntSize size(DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT);
  346. const nsAttrValue* value;
  347. if ((value = GetParsedAttr(nsGkAtoms::width)) &&
  348. value->Type() == nsAttrValue::eInteger)
  349. {
  350. size.width = value->GetIntegerValue();
  351. }
  352. if ((value = GetParsedAttr(nsGkAtoms::height)) &&
  353. value->Type() == nsAttrValue::eInteger)
  354. {
  355. size.height = value->GetIntegerValue();
  356. }
  357. MOZ_ASSERT(size.width >= 0 && size.height >= 0,
  358. "we should've required <canvas> width/height attrs to be "
  359. "unsigned (non-negative) values");
  360. return size;
  361. }
  362. NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH)
  363. NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT)
  364. NS_IMPL_BOOL_ATTR(HTMLCanvasElement, MozOpaque, moz_opaque)
  365. nsresult
  366. HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
  367. const nsAttrValue* aValue,
  368. const nsAttrValue* aOldValue, bool aNotify)
  369. {
  370. AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
  371. return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
  372. aOldValue, aNotify);
  373. }
  374. nsresult
  375. HTMLCanvasElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
  376. const nsAttrValueOrString& aValue,
  377. bool aNotify)
  378. {
  379. AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
  380. return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
  381. aValue, aNotify);
  382. }
  383. void
  384. HTMLCanvasElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
  385. bool aNotify)
  386. {
  387. if (mCurrentContext && aNamespaceID == kNameSpaceID_None &&
  388. (aName == nsGkAtoms::width || aName == nsGkAtoms::height ||
  389. aName == nsGkAtoms::moz_opaque)) {
  390. ErrorResult dummy;
  391. UpdateContext(nullptr, JS::NullHandleValue, dummy);
  392. }
  393. }
  394. void
  395. HTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
  396. {
  397. // Only call the print callback here if 1) we're in a print testing mode or
  398. // print preview mode, 2) the canvas has a print callback and 3) the callback
  399. // hasn't already been called. For real printing the callback is handled in
  400. // nsSimplePageSequenceFrame::PrePrintNextPage.
  401. if ((aType == nsPresContext::eContext_PageLayout ||
  402. aType == nsPresContext::eContext_PrintPreview) &&
  403. !mPrintState && GetMozPrintCallback()) {
  404. DispatchPrintCallback(nullptr);
  405. }
  406. }
  407. nsresult
  408. HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
  409. {
  410. // For print reftests the context may not be initialized yet, so get a context
  411. // so mCurrentContext is set.
  412. if (!mCurrentContext) {
  413. nsresult rv;
  414. nsCOMPtr<nsISupports> context;
  415. rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
  416. NS_ENSURE_SUCCESS(rv, rv);
  417. }
  418. mPrintState = new HTMLCanvasPrintState(this, mCurrentContext, aCallback);
  419. RefPtr<nsRunnableMethod<HTMLCanvasElement> > renderEvent =
  420. NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback);
  421. return NS_DispatchToCurrentThread(renderEvent);
  422. }
  423. void
  424. HTMLCanvasElement::CallPrintCallback()
  425. {
  426. ErrorResult rv;
  427. GetMozPrintCallback()->Call(*mPrintState, rv);
  428. }
  429. void
  430. HTMLCanvasElement::ResetPrintCallback()
  431. {
  432. if (mPrintState) {
  433. mPrintState = nullptr;
  434. }
  435. }
  436. bool
  437. HTMLCanvasElement::IsPrintCallbackDone()
  438. {
  439. if (mPrintState == nullptr) {
  440. return true;
  441. }
  442. return mPrintState->mIsDone;
  443. }
  444. HTMLCanvasElement*
  445. HTMLCanvasElement::GetOriginalCanvas()
  446. {
  447. return mOriginalCanvas ? mOriginalCanvas.get() : this;
  448. }
  449. nsresult
  450. HTMLCanvasElement::CopyInnerTo(Element* aDest)
  451. {
  452. nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
  453. NS_ENSURE_SUCCESS(rv, rv);
  454. if (aDest->OwnerDoc()->IsStaticDocument()) {
  455. HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest);
  456. dest->mOriginalCanvas = this;
  457. // We make sure that the canvas is not zero sized since that would cause
  458. // the DrawImage call below to return an error, which would cause printing
  459. // to fail.
  460. nsIntSize size = GetWidthHeight();
  461. if (size.height > 0 && size.width > 0) {
  462. nsCOMPtr<nsISupports> cxt;
  463. dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
  464. RefPtr<CanvasRenderingContext2D> context2d =
  465. static_cast<CanvasRenderingContext2D*>(cxt.get());
  466. if (context2d && !mPrintCallback) {
  467. CanvasImageSource source;
  468. source.SetAsHTMLCanvasElement() = this;
  469. ErrorResult err;
  470. context2d->DrawImage(source,
  471. 0.0, 0.0, err);
  472. rv = err.StealNSResult();
  473. }
  474. }
  475. }
  476. return rv;
  477. }
  478. nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
  479. {
  480. if (aVisitor.mEvent->mClass == eMouseEventClass) {
  481. WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
  482. if (mCurrentContext) {
  483. nsIFrame *frame = GetPrimaryFrame();
  484. if (!frame)
  485. return NS_OK;
  486. nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(evt, frame);
  487. nsRect paddingRect = frame->GetContentRectRelativeToSelf();
  488. Point hitpoint;
  489. hitpoint.x = (ptInRoot.x - paddingRect.x) / AppUnitsPerCSSPixel();
  490. hitpoint.y = (ptInRoot.y - paddingRect.y) / AppUnitsPerCSSPixel();
  491. evt->region = mCurrentContext->GetHitRegion(hitpoint);
  492. aVisitor.mCanHandle = true;
  493. }
  494. }
  495. return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
  496. }
  497. nsChangeHint
  498. HTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
  499. int32_t aModType) const
  500. {
  501. nsChangeHint retval =
  502. nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
  503. if (aAttribute == nsGkAtoms::width ||
  504. aAttribute == nsGkAtoms::height)
  505. {
  506. retval |= NS_STYLE_HINT_REFLOW;
  507. } else if (aAttribute == nsGkAtoms::moz_opaque)
  508. {
  509. retval |= NS_STYLE_HINT_VISUAL;
  510. }
  511. return retval;
  512. }
  513. bool
  514. HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID,
  515. nsIAtom* aAttribute,
  516. const nsAString& aValue,
  517. nsAttrValue& aResult)
  518. {
  519. if (aNamespaceID == kNameSpaceID_None &&
  520. (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
  521. return aResult.ParseNonNegativeIntValue(aValue);
  522. }
  523. return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
  524. aResult);
  525. }
  526. // HTMLCanvasElement::toDataURL
  527. NS_IMETHODIMP
  528. HTMLCanvasElement::ToDataURL(const nsAString& aType, JS::Handle<JS::Value> aParams,
  529. JSContext* aCx, nsAString& aDataURL)
  530. {
  531. // do a trust check if this is a write-only canvas
  532. if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
  533. return NS_ERROR_DOM_SECURITY_ERR;
  534. }
  535. return ToDataURLImpl(aCx, aType, aParams, aDataURL);
  536. }
  537. void
  538. HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
  539. {
  540. mPrintCallback = aCallback;
  541. }
  542. PrintCallback*
  543. HTMLCanvasElement::GetMozPrintCallback() const
  544. {
  545. if (mOriginalCanvas) {
  546. return mOriginalCanvas->GetMozPrintCallback();
  547. }
  548. return mPrintCallback;
  549. }
  550. class CanvasCaptureTrackSource : public MediaStreamTrackSource
  551. {
  552. public:
  553. NS_DECL_ISUPPORTS_INHERITED
  554. NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CanvasCaptureTrackSource,
  555. MediaStreamTrackSource)
  556. CanvasCaptureTrackSource(nsIPrincipal* aPrincipal,
  557. CanvasCaptureMediaStream* aCaptureStream)
  558. : MediaStreamTrackSource(aPrincipal, nsString())
  559. , mCaptureStream(aCaptureStream) {}
  560. MediaSourceEnum GetMediaSource() const override
  561. {
  562. return MediaSourceEnum::Other;
  563. }
  564. void Stop() override
  565. {
  566. if (!mCaptureStream) {
  567. NS_ERROR("No stream");
  568. return;
  569. }
  570. mCaptureStream->StopCapture();
  571. }
  572. private:
  573. virtual ~CanvasCaptureTrackSource() {}
  574. RefPtr<CanvasCaptureMediaStream> mCaptureStream;
  575. };
  576. NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource,
  577. MediaStreamTrackSource)
  578. NS_IMPL_RELEASE_INHERITED(CanvasCaptureTrackSource,
  579. MediaStreamTrackSource)
  580. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource)
  581. NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSource)
  582. NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource,
  583. MediaStreamTrackSource,
  584. mCaptureStream)
  585. already_AddRefed<CanvasCaptureMediaStream>
  586. HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
  587. ErrorResult& aRv)
  588. {
  589. if (IsWriteOnly()) {
  590. aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  591. return nullptr;
  592. }
  593. nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
  594. if (!window) {
  595. aRv.Throw(NS_ERROR_FAILURE);
  596. return nullptr;
  597. }
  598. if (!mCurrentContext) {
  599. aRv.Throw(NS_ERROR_NOT_INITIALIZED);
  600. return nullptr;
  601. }
  602. RefPtr<CanvasCaptureMediaStream> stream =
  603. CanvasCaptureMediaStream::CreateSourceStream(window, this);
  604. if (!stream) {
  605. aRv.Throw(NS_ERROR_FAILURE);
  606. return nullptr;
  607. }
  608. TrackID videoTrackId = 1;
  609. nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
  610. nsresult rv =
  611. stream->Init(aFrameRate, videoTrackId, principal);
  612. if (NS_FAILED(rv)) {
  613. aRv.Throw(rv);
  614. return nullptr;
  615. }
  616. RefPtr<MediaStreamTrack> track =
  617. stream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
  618. new CanvasCaptureTrackSource(principal, stream));
  619. stream->AddTrackInternal(track);
  620. rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
  621. if (NS_FAILED(rv)) {
  622. aRv.Throw(rv);
  623. return nullptr;
  624. }
  625. return stream.forget();
  626. }
  627. nsresult
  628. HTMLCanvasElement::ExtractData(nsAString& aType,
  629. const nsAString& aOptions,
  630. nsIInputStream** aStream)
  631. {
  632. return ImageEncoder::ExtractData(aType,
  633. aOptions,
  634. GetSize(),
  635. mCurrentContext,
  636. mAsyncCanvasRenderer,
  637. aStream);
  638. }
  639. nsresult
  640. HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
  641. const nsAString& aMimeType,
  642. const JS::Value& aEncoderOptions,
  643. nsAString& aDataURL)
  644. {
  645. nsIntSize size = GetWidthHeight();
  646. if (size.height == 0 || size.width == 0) {
  647. aDataURL = NS_LITERAL_STRING("data:,");
  648. return NS_OK;
  649. }
  650. nsAutoString type;
  651. nsContentUtils::ASCIIToLower(aMimeType, type);
  652. nsAutoString params;
  653. bool usingCustomParseOptions;
  654. nsresult rv =
  655. ParseParams(aCx, type, aEncoderOptions, params, &usingCustomParseOptions);
  656. if (NS_FAILED(rv)) {
  657. return rv;
  658. }
  659. nsCOMPtr<nsIInputStream> stream;
  660. rv = ExtractData(type, params, getter_AddRefs(stream));
  661. // If there are unrecognized custom parse options, we should fall back to
  662. // the default values for the encoder without any options at all.
  663. if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
  664. rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
  665. }
  666. NS_ENSURE_SUCCESS(rv, rv);
  667. // build data URL string
  668. aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
  669. uint64_t count;
  670. rv = stream->Available(&count);
  671. NS_ENSURE_SUCCESS(rv, rv);
  672. NS_ENSURE_TRUE(count <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
  673. return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
  674. }
  675. void
  676. HTMLCanvasElement::ToBlob(JSContext* aCx,
  677. BlobCallback& aCallback,
  678. const nsAString& aType,
  679. JS::Handle<JS::Value> aParams,
  680. ErrorResult& aRv)
  681. {
  682. // do a trust check if this is a write-only canvas
  683. if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
  684. aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  685. return;
  686. }
  687. nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
  688. MOZ_ASSERT(global);
  689. CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
  690. aParams, aRv);
  691. }
  692. OffscreenCanvas*
  693. HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
  694. {
  695. if (mCurrentContext) {
  696. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  697. return nullptr;
  698. }
  699. if (!mOffscreenCanvas) {
  700. nsIntSize sz = GetWidthHeight();
  701. RefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
  702. renderer->SetWidth(sz.width);
  703. renderer->SetHeight(sz.height);
  704. nsCOMPtr<nsIGlobalObject> global =
  705. do_QueryInterface(OwnerDoc()->GetInnerWindow());
  706. mOffscreenCanvas = new OffscreenCanvas(global,
  707. sz.width,
  708. sz.height,
  709. GetCompositorBackendType(),
  710. renderer);
  711. if (mWriteOnly) {
  712. mOffscreenCanvas->SetWriteOnly();
  713. }
  714. if (!mContextObserver) {
  715. mContextObserver = new HTMLCanvasElementObserver(this);
  716. }
  717. } else {
  718. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  719. }
  720. return mOffscreenCanvas;
  721. }
  722. already_AddRefed<File>
  723. HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
  724. const nsAString& aType,
  725. ErrorResult& aRv)
  726. {
  727. nsCOMPtr<nsISupports> file;
  728. aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
  729. if (NS_WARN_IF(aRv.Failed())) {
  730. return nullptr;
  731. }
  732. nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(file);
  733. RefPtr<Blob> domBlob = static_cast<Blob*>(blob.get());
  734. MOZ_ASSERT(domBlob->IsFile());
  735. return domBlob->ToFile();
  736. }
  737. NS_IMETHODIMP
  738. HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
  739. const nsAString& aType,
  740. nsISupports** aResult)
  741. {
  742. OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
  743. // do a trust check if this is a write-only canvas
  744. if ((mWriteOnly) &&
  745. !nsContentUtils::IsCallerChrome()) {
  746. return NS_ERROR_DOM_SECURITY_ERR;
  747. }
  748. return MozGetAsBlobImpl(aName, aType, aResult);
  749. }
  750. nsresult
  751. HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
  752. const nsAString& aType,
  753. nsISupports** aResult)
  754. {
  755. nsCOMPtr<nsIInputStream> stream;
  756. nsAutoString type(aType);
  757. nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
  758. NS_ENSURE_SUCCESS(rv, rv);
  759. uint64_t imgSize;
  760. rv = stream->Available(&imgSize);
  761. NS_ENSURE_SUCCESS(rv, rv);
  762. NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
  763. void* imgData = nullptr;
  764. rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
  765. NS_ENSURE_SUCCESS(rv, rv);
  766. JSContext* cx = nsContentUtils::GetCurrentJSContext();
  767. if (cx) {
  768. JS_updateMallocCounter(cx, imgSize);
  769. }
  770. nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
  771. // The File takes ownership of the buffer
  772. nsCOMPtr<nsIDOMBlob> file =
  773. File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
  774. PR_Now());
  775. file.forget(aResult);
  776. return NS_OK;
  777. }
  778. nsresult
  779. HTMLCanvasElement::GetContext(const nsAString& aContextId,
  780. nsISupports** aContext)
  781. {
  782. ErrorResult rv;
  783. *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
  784. return rv.StealNSResult();
  785. }
  786. already_AddRefed<nsISupports>
  787. HTMLCanvasElement::GetContext(JSContext* aCx,
  788. const nsAString& aContextId,
  789. JS::Handle<JS::Value> aContextOptions,
  790. ErrorResult& aRv)
  791. {
  792. if (mOffscreenCanvas) {
  793. return nullptr;
  794. }
  795. return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
  796. aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
  797. aRv);
  798. }
  799. NS_IMETHODIMP
  800. HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
  801. nsISupports **aContext)
  802. {
  803. if(!nsContentUtils::IsCallerChrome()) {
  804. // XXX ERRMSG we need to report an error to developers here! (bug 329026)
  805. return NS_ERROR_DOM_SECURITY_ERR;
  806. }
  807. // We only support 2d shmem contexts for now.
  808. if (!aContextId.EqualsLiteral("2d"))
  809. return NS_ERROR_INVALID_ARG;
  810. CanvasContextType contextType = CanvasContextType::Canvas2D;
  811. if (!mCurrentContext) {
  812. // This canvas doesn't have a context yet.
  813. RefPtr<nsICanvasRenderingContextInternal> context;
  814. context = CreateContext(contextType);
  815. if (!context) {
  816. *aContext = nullptr;
  817. return NS_OK;
  818. }
  819. mCurrentContext = context;
  820. mCurrentContext->SetIsIPC(true);
  821. mCurrentContextType = contextType;
  822. ErrorResult dummy;
  823. nsresult rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
  824. NS_ENSURE_SUCCESS(rv, rv);
  825. } else {
  826. // We already have a context of some type.
  827. if (contextType != mCurrentContextType)
  828. return NS_ERROR_INVALID_ARG;
  829. }
  830. NS_ADDREF (*aContext = mCurrentContext);
  831. return NS_OK;
  832. }
  833. nsIntSize
  834. HTMLCanvasElement::GetSize()
  835. {
  836. return GetWidthHeight();
  837. }
  838. bool
  839. HTMLCanvasElement::IsWriteOnly() const
  840. {
  841. return mWriteOnly;
  842. }
  843. void
  844. HTMLCanvasElement::SetWriteOnly()
  845. {
  846. mWriteOnly = true;
  847. }
  848. void
  849. HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
  850. {
  851. // We don't need to flush anything here; if there's no frame or if
  852. // we plan to reframe we don't need to invalidate it anyway.
  853. nsIFrame *frame = GetPrimaryFrame();
  854. if (!frame)
  855. return;
  856. ActiveLayerTracker::NotifyContentChange(frame);
  857. Layer* layer = nullptr;
  858. if (damageRect) {
  859. nsIntSize size = GetWidthHeight();
  860. if (size.width != 0 && size.height != 0) {
  861. gfx::IntRect invalRect = gfx::IntRect::Truncate(*damageRect);
  862. layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
  863. }
  864. } else {
  865. layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
  866. }
  867. if (layer) {
  868. static_cast<CanvasLayer*>(layer)->Updated();
  869. }
  870. /*
  871. * Treat canvas invalidations as animation activity for JS. Frequently
  872. * invalidating a canvas will feed into heuristics and cause JIT code to be
  873. * kept around longer, for smoother animations.
  874. */
  875. nsCOMPtr<nsIGlobalObject> global =
  876. do_QueryInterface(OwnerDoc()->GetInnerWindow());
  877. if (global) {
  878. if (JSObject *obj = global->GetGlobalJSObject()) {
  879. js::NotifyAnimationActivity(obj);
  880. }
  881. }
  882. }
  883. void
  884. HTMLCanvasElement::InvalidateCanvas()
  885. {
  886. // We don't need to flush anything here; if there's no frame or if
  887. // we plan to reframe we don't need to invalidate it anyway.
  888. nsIFrame *frame = GetPrimaryFrame();
  889. if (!frame)
  890. return;
  891. frame->InvalidateFrame();
  892. }
  893. int32_t
  894. HTMLCanvasElement::CountContexts()
  895. {
  896. if (mCurrentContext)
  897. return 1;
  898. return 0;
  899. }
  900. nsICanvasRenderingContextInternal *
  901. HTMLCanvasElement::GetContextAtIndex(int32_t index)
  902. {
  903. if (mCurrentContext && index == 0)
  904. return mCurrentContext;
  905. return nullptr;
  906. }
  907. bool
  908. HTMLCanvasElement::GetIsOpaque()
  909. {
  910. if (mCurrentContext) {
  911. return mCurrentContext->GetIsOpaque();
  912. }
  913. return GetOpaqueAttr();
  914. }
  915. bool
  916. HTMLCanvasElement::GetOpaqueAttr()
  917. {
  918. return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
  919. }
  920. already_AddRefed<Layer>
  921. HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
  922. Layer *aOldLayer,
  923. LayerManager *aManager)
  924. {
  925. // The address of sOffscreenCanvasLayerUserDataDummy is used as the user
  926. // data key for retained LayerManagers managed by FrameLayerBuilder.
  927. // We don't much care about what value in it, so just assign a dummy
  928. // value for it.
  929. static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
  930. if (mCurrentContext) {
  931. return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
  932. }
  933. if (mOffscreenCanvas) {
  934. if (!mResetLayer &&
  935. aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
  936. RefPtr<Layer> ret = aOldLayer;
  937. return ret.forget();
  938. }
  939. RefPtr<CanvasLayer> layer = aManager->CreateCanvasLayer();
  940. if (!layer) {
  941. NS_WARNING("CreateCanvasLayer failed!");
  942. return nullptr;
  943. }
  944. LayerUserData* userData = nullptr;
  945. layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
  946. CanvasLayer::Data data;
  947. data.mRenderer = GetAsyncCanvasRenderer();
  948. data.mSize = GetWidthHeight();
  949. layer->Initialize(data);
  950. layer->Updated();
  951. return layer.forget();
  952. }
  953. return nullptr;
  954. }
  955. bool
  956. HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
  957. {
  958. if (mCurrentContext) {
  959. return mCurrentContext->ShouldForceInactiveLayer(aManager);
  960. }
  961. if (mOffscreenCanvas) {
  962. // TODO: We should handle offscreen canvas case.
  963. return false;
  964. }
  965. return true;
  966. }
  967. void
  968. HTMLCanvasElement::MarkContextClean()
  969. {
  970. if (!mCurrentContext)
  971. return;
  972. mCurrentContext->MarkContextClean();
  973. }
  974. void
  975. HTMLCanvasElement::MarkContextCleanForFrameCapture()
  976. {
  977. if (!mCurrentContext)
  978. return;
  979. mCurrentContext->MarkContextCleanForFrameCapture();
  980. }
  981. bool
  982. HTMLCanvasElement::IsContextCleanForFrameCapture()
  983. {
  984. return mCurrentContext && mCurrentContext->IsContextCleanForFrameCapture();
  985. }
  986. nsresult
  987. HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
  988. {
  989. WeakPtr<FrameCaptureListener> listener = aListener;
  990. if (mRequestedFrameListeners.Contains(listener)) {
  991. return NS_OK;
  992. }
  993. if (!mRequestedFrameRefreshObserver) {
  994. nsIDocument* doc = OwnerDoc();
  995. if (!doc) {
  996. return NS_ERROR_FAILURE;
  997. }
  998. while (doc->GetParentDocument()) {
  999. doc = doc->GetParentDocument();
  1000. }
  1001. nsIPresShell* shell = doc->GetShell();
  1002. if (!shell) {
  1003. return NS_ERROR_FAILURE;
  1004. }
  1005. nsPresContext* context = shell->GetPresContext();
  1006. if (!context) {
  1007. return NS_ERROR_FAILURE;
  1008. }
  1009. context = context->GetRootPresContext();
  1010. if (!context) {
  1011. return NS_ERROR_FAILURE;
  1012. }
  1013. nsRefreshDriver* driver = context->RefreshDriver();
  1014. if (!driver) {
  1015. return NS_ERROR_FAILURE;
  1016. }
  1017. mRequestedFrameRefreshObserver =
  1018. new RequestedFrameRefreshObserver(this, driver);
  1019. }
  1020. mRequestedFrameListeners.AppendElement(listener);
  1021. mRequestedFrameRefreshObserver->Register();
  1022. return NS_OK;
  1023. }
  1024. bool
  1025. HTMLCanvasElement::IsFrameCaptureRequested() const
  1026. {
  1027. for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
  1028. if (!listener) {
  1029. continue;
  1030. }
  1031. if (listener->FrameCaptureRequested()) {
  1032. return true;
  1033. }
  1034. }
  1035. return false;
  1036. }
  1037. void
  1038. HTMLCanvasElement::ProcessDestroyedFrameListeners()
  1039. {
  1040. // Loop backwards to allow removing elements in the loop.
  1041. for (int i = mRequestedFrameListeners.Length() - 1; i >= 0; --i) {
  1042. WeakPtr<FrameCaptureListener> listener = mRequestedFrameListeners[i];
  1043. if (!listener) {
  1044. // listener was destroyed. Remove it from the list.
  1045. mRequestedFrameListeners.RemoveElementAt(i);
  1046. continue;
  1047. }
  1048. }
  1049. if (mRequestedFrameListeners.IsEmpty()) {
  1050. mRequestedFrameRefreshObserver->Unregister();
  1051. }
  1052. }
  1053. void
  1054. HTMLCanvasElement::SetFrameCapture(already_AddRefed<SourceSurface> aSurface)
  1055. {
  1056. RefPtr<SourceSurface> surface = aSurface;
  1057. RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), surface);
  1058. for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
  1059. if (!listener) {
  1060. continue;
  1061. }
  1062. RefPtr<Image> imageRefCopy = image.get();
  1063. listener->NewFrame(imageRefCopy.forget());
  1064. }
  1065. }
  1066. already_AddRefed<SourceSurface>
  1067. HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
  1068. {
  1069. if (!mCurrentContext)
  1070. return nullptr;
  1071. return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
  1072. }
  1073. AsyncCanvasRenderer*
  1074. HTMLCanvasElement::GetAsyncCanvasRenderer()
  1075. {
  1076. if (!mAsyncCanvasRenderer) {
  1077. mAsyncCanvasRenderer = new AsyncCanvasRenderer();
  1078. mAsyncCanvasRenderer->mHTMLCanvasElement = this;
  1079. }
  1080. return mAsyncCanvasRenderer;
  1081. }
  1082. layers::LayersBackend
  1083. HTMLCanvasElement::GetCompositorBackendType() const
  1084. {
  1085. nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
  1086. if (docWidget) {
  1087. layers::LayerManager* layerManager = docWidget->GetLayerManager();
  1088. if (layerManager) {
  1089. return layerManager->GetCompositorBackendType();
  1090. }
  1091. }
  1092. return LayersBackend::LAYERS_NONE;
  1093. }
  1094. void
  1095. HTMLCanvasElement::OnVisibilityChange()
  1096. {
  1097. if (OwnerDoc()->Hidden()) {
  1098. return;
  1099. }
  1100. if (mOffscreenCanvas) {
  1101. class Runnable final : public CancelableRunnable
  1102. {
  1103. public:
  1104. explicit Runnable(AsyncCanvasRenderer* aRenderer)
  1105. : mRenderer(aRenderer)
  1106. {}
  1107. NS_IMETHOD Run() override
  1108. {
  1109. if (mRenderer && mRenderer->mContext) {
  1110. mRenderer->mContext->OnVisibilityChange();
  1111. }
  1112. return NS_OK;
  1113. }
  1114. void Revoke()
  1115. {
  1116. mRenderer = nullptr;
  1117. }
  1118. private:
  1119. RefPtr<AsyncCanvasRenderer> mRenderer;
  1120. };
  1121. RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
  1122. nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
  1123. if (activeThread) {
  1124. activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
  1125. }
  1126. return;
  1127. }
  1128. if (mCurrentContext) {
  1129. mCurrentContext->OnVisibilityChange();
  1130. }
  1131. }
  1132. void
  1133. HTMLCanvasElement::OnMemoryPressure()
  1134. {
  1135. if (mOffscreenCanvas) {
  1136. class Runnable final : public CancelableRunnable
  1137. {
  1138. public:
  1139. explicit Runnable(AsyncCanvasRenderer* aRenderer)
  1140. : mRenderer(aRenderer)
  1141. {}
  1142. NS_IMETHOD Run() override
  1143. {
  1144. if (mRenderer && mRenderer->mContext) {
  1145. mRenderer->mContext->OnMemoryPressure();
  1146. }
  1147. return NS_OK;
  1148. }
  1149. void Revoke()
  1150. {
  1151. mRenderer = nullptr;
  1152. }
  1153. private:
  1154. RefPtr<AsyncCanvasRenderer> mRenderer;
  1155. };
  1156. RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
  1157. nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
  1158. if (activeThread) {
  1159. activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
  1160. }
  1161. return;
  1162. }
  1163. if (mCurrentContext) {
  1164. mCurrentContext->OnMemoryPressure();
  1165. }
  1166. }
  1167. /* static */ void
  1168. HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
  1169. {
  1170. HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
  1171. if (!element) {
  1172. return;
  1173. }
  1174. if (element->GetWidthHeight() == aRenderer->GetSize()) {
  1175. return;
  1176. }
  1177. gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
  1178. ErrorResult rv;
  1179. element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width,
  1180. DEFAULT_CANVAS_WIDTH, rv);
  1181. if (rv.Failed()) {
  1182. NS_WARNING("Failed to set width attribute to a canvas element asynchronously.");
  1183. }
  1184. element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height,
  1185. DEFAULT_CANVAS_HEIGHT, rv);
  1186. if (rv.Failed()) {
  1187. NS_WARNING("Failed to set height attribute to a canvas element asynchronously.");
  1188. }
  1189. element->mResetLayer = true;
  1190. }
  1191. /* static */ void
  1192. HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
  1193. {
  1194. HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
  1195. if (!element) {
  1196. return;
  1197. }
  1198. element->InvalidateCanvasContent(nullptr);
  1199. }
  1200. } // namespace dom
  1201. } // namespace mozilla