ImageBitmapRenderingContext.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* -*- Mode: C++; tab-width: 2; 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 "ImageBitmapRenderingContext.h"
  6. #include "mozilla/dom/ImageBitmapRenderingContextBinding.h"
  7. #include "mozilla/gfx/2D.h"
  8. #include "mozilla/gfx/DataSurfaceHelpers.h"
  9. #include "ImageBitmap.h"
  10. #include "ImageContainer.h"
  11. #include "ImageEncoder.h"
  12. #include "ImageLayers.h"
  13. #include "imgIEncoder.h"
  14. #include "Layers.h"
  15. using namespace mozilla::gfx;
  16. using namespace mozilla::layers;
  17. namespace mozilla {
  18. namespace dom {
  19. ImageBitmapRenderingContext::ImageBitmapRenderingContext()
  20. : mWidth(0)
  21. , mHeight(0)
  22. {
  23. }
  24. ImageBitmapRenderingContext::~ImageBitmapRenderingContext()
  25. {
  26. RemovePostRefreshObserver();
  27. }
  28. JSObject*
  29. ImageBitmapRenderingContext::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  30. {
  31. return ImageBitmapRenderingContextBinding::Wrap(aCx, this, aGivenProto);
  32. }
  33. already_AddRefed<layers::Image>
  34. ImageBitmapRenderingContext::ClipToIntrinsicSize()
  35. {
  36. if (!mImage) {
  37. return nullptr;
  38. }
  39. // If image is larger than canvas intrinsic size, clip it to the intrinsic size.
  40. RefPtr<gfx::SourceSurface> surface;
  41. RefPtr<layers::Image> result;
  42. if (mWidth < mImage->GetSize().width ||
  43. mHeight < mImage->GetSize().height) {
  44. surface = MatchWithIntrinsicSize();
  45. } else {
  46. surface = mImage->GetAsSourceSurface();
  47. }
  48. result = new layers::SourceSurfaceImage(gfx::IntSize(mWidth, mHeight), surface);
  49. return result.forget();
  50. }
  51. void
  52. ImageBitmapRenderingContext::TransferImageBitmap(ImageBitmap& aImageBitmap)
  53. {
  54. TransferFromImageBitmap(aImageBitmap);
  55. }
  56. void
  57. ImageBitmapRenderingContext::TransferFromImageBitmap(ImageBitmap& aImageBitmap)
  58. {
  59. Reset();
  60. mImage = aImageBitmap.TransferAsImage();
  61. if (!mImage) {
  62. return;
  63. }
  64. // Check if ImageBitmap is tainted, and if so flag the canvas tainted too.
  65. if (aImageBitmap.IsWriteOnly() && mCanvasElement) {
  66. mCanvasElement->SetWriteOnly();
  67. }
  68. Redraw(gfxRect(0, 0, mWidth, mHeight));
  69. }
  70. int32_t
  71. ImageBitmapRenderingContext::GetWidth() const
  72. {
  73. return mWidth;
  74. }
  75. int32_t
  76. ImageBitmapRenderingContext::GetHeight() const
  77. {
  78. return mHeight;
  79. }
  80. NS_IMETHODIMP
  81. ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight)
  82. {
  83. mWidth = aWidth;
  84. mHeight = aHeight;
  85. return NS_OK;
  86. }
  87. NS_IMETHODIMP
  88. ImageBitmapRenderingContext::InitializeWithDrawTarget(nsIDocShell* aDocShell,
  89. NotNull<gfx::DrawTarget*> aTarget)
  90. {
  91. return NS_ERROR_NOT_IMPLEMENTED;
  92. }
  93. already_AddRefed<DataSourceSurface>
  94. ImageBitmapRenderingContext::MatchWithIntrinsicSize()
  95. {
  96. RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
  97. RefPtr<DataSourceSurface> temp =
  98. Factory::CreateDataSourceSurface(IntSize(mWidth, mHeight), surface->GetFormat());
  99. if (!temp) {
  100. return nullptr;
  101. }
  102. DataSourceSurface::ScopedMap map(temp, DataSourceSurface::READ_WRITE);
  103. if (!map.IsMapped()) {
  104. return nullptr;
  105. }
  106. RefPtr<DrawTarget> dt =
  107. Factory::CreateDrawTargetForData(BackendType::CAIRO,
  108. map.GetData(),
  109. temp->GetSize(),
  110. map.GetStride(),
  111. temp->GetFormat());
  112. if (!dt || !dt->IsValid()) {
  113. gfxWarning() << "ImageBitmapRenderingContext::MatchWithIntrinsicSize failed";
  114. return nullptr;
  115. }
  116. dt->ClearRect(Rect(0, 0, mWidth, mHeight));
  117. dt->CopySurface(surface,
  118. IntRect(0, 0, surface->GetSize().width,
  119. surface->GetSize().height),
  120. IntPoint(0, 0));
  121. return temp.forget();
  122. }
  123. mozilla::UniquePtr<uint8_t[]>
  124. ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat)
  125. {
  126. *aFormat = 0;
  127. if (!mImage) {
  128. return nullptr;
  129. }
  130. RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
  131. RefPtr<DataSourceSurface> data = surface->GetDataSurface();
  132. if (!data) {
  133. return nullptr;
  134. }
  135. if (data->GetSize() != IntSize(mWidth, mHeight)) {
  136. data = MatchWithIntrinsicSize();
  137. }
  138. *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
  139. return SurfaceToPackedBGRA(data);
  140. }
  141. NS_IMETHODIMP
  142. ImageBitmapRenderingContext::GetInputStream(const char* aMimeType,
  143. const char16_t* aEncoderOptions,
  144. nsIInputStream** aStream)
  145. {
  146. nsCString enccid("@mozilla.org/image/encoder;2?type=");
  147. enccid += aMimeType;
  148. nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
  149. if (!encoder) {
  150. return NS_ERROR_FAILURE;
  151. }
  152. int32_t format = 0;
  153. UniquePtr<uint8_t[]> imageBuffer = GetImageBuffer(&format);
  154. if (!imageBuffer) {
  155. return NS_ERROR_FAILURE;
  156. }
  157. return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(), format,
  158. encoder, aEncoderOptions, aStream);
  159. }
  160. already_AddRefed<mozilla::gfx::SourceSurface>
  161. ImageBitmapRenderingContext::GetSurfaceSnapshot(bool* aPremultAlpha)
  162. {
  163. if (!mImage) {
  164. return nullptr;
  165. }
  166. if (aPremultAlpha) {
  167. *aPremultAlpha = true;
  168. }
  169. RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
  170. if (surface->GetSize() != IntSize(mWidth, mHeight)) {
  171. return MatchWithIntrinsicSize();
  172. }
  173. return surface.forget();
  174. }
  175. NS_IMETHODIMP
  176. ImageBitmapRenderingContext::SetIsOpaque(bool aIsOpaque)
  177. {
  178. return NS_OK;
  179. }
  180. bool
  181. ImageBitmapRenderingContext::GetIsOpaque()
  182. {
  183. return false;
  184. }
  185. NS_IMETHODIMP
  186. ImageBitmapRenderingContext::Reset()
  187. {
  188. if (mCanvasElement) {
  189. mCanvasElement->InvalidateCanvas();
  190. }
  191. mImage = nullptr;
  192. return NS_OK;
  193. }
  194. already_AddRefed<Layer>
  195. ImageBitmapRenderingContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
  196. Layer* aOldLayer,
  197. LayerManager* aManager,
  198. bool aMirror /* = false */)
  199. {
  200. if (aMirror) {
  201. // Not supported for ImageBitmapRenderingContext
  202. return nullptr;
  203. }
  204. if (!mImage) {
  205. // No DidTransactionCallback will be received, so mark the context clean
  206. // now so future invalidations will be dispatched.
  207. MarkContextClean();
  208. return nullptr;
  209. }
  210. RefPtr<ImageLayer> imageLayer;
  211. if (aOldLayer) {
  212. imageLayer = static_cast<ImageLayer*>(aOldLayer);
  213. } else {
  214. imageLayer = aManager->CreateImageLayer();
  215. }
  216. RefPtr<ImageContainer> imageContainer = imageLayer->GetContainer();
  217. if (!imageContainer) {
  218. imageContainer = aManager->CreateImageContainer();
  219. imageLayer->SetContainer(imageContainer);
  220. }
  221. AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
  222. RefPtr<layers::Image> image = ClipToIntrinsicSize();
  223. imageList.AppendElement(ImageContainer::NonOwningImage(image));
  224. imageContainer->SetCurrentImages(imageList);
  225. return imageLayer.forget();
  226. }
  227. void
  228. ImageBitmapRenderingContext::MarkContextClean()
  229. {
  230. }
  231. NS_IMETHODIMP
  232. ImageBitmapRenderingContext::Redraw(const gfxRect& aDirty)
  233. {
  234. if (!mCanvasElement) {
  235. return NS_OK;
  236. }
  237. mozilla::gfx::Rect rect = ToRect(aDirty);
  238. mCanvasElement->InvalidateCanvasContent(&rect);
  239. return NS_OK;
  240. }
  241. NS_IMETHODIMP
  242. ImageBitmapRenderingContext::SetIsIPC(bool aIsIPC)
  243. {
  244. return NS_OK;
  245. }
  246. void
  247. ImageBitmapRenderingContext::DidRefresh()
  248. {
  249. }
  250. void
  251. ImageBitmapRenderingContext::MarkContextCleanForFrameCapture()
  252. {
  253. }
  254. bool
  255. ImageBitmapRenderingContext::IsContextCleanForFrameCapture()
  256. {
  257. return true;
  258. }
  259. NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext)
  260. NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext)
  261. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmapRenderingContext,
  262. mCanvasElement,
  263. mOffscreenCanvas)
  264. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext)
  265. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  266. NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
  267. NS_INTERFACE_MAP_ENTRY(nsISupports)
  268. NS_INTERFACE_MAP_END
  269. }
  270. }