tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ImageData.cpp (5560B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 et tw=78: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/ImageData.h"
      8 
      9 #include "ErrorList.h"
     10 #include "js/StructuredClone.h"
     11 #include "js/Value.h"
     12 #include "jsapi.h"
     13 #include "jsfriendapi.h"
     14 #include "mozilla/CheckedInt.h"
     15 #include "mozilla/ErrorResult.h"
     16 #include "mozilla/HoldDropJSObjects.h"
     17 #include "mozilla/RefPtr.h"
     18 #include "mozilla/dom/BindingDeclarations.h"
     19 #include "mozilla/dom/ImageDataBinding.h"
     20 #include "nsCycleCollectionNoteChild.h"
     21 
     22 namespace mozilla::dom {
     23 
     24 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageData)
     25 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(ImageData, DropData())
     26 
     27 NS_IMPL_CYCLE_COLLECTION_CLASS(ImageData)
     28 
     29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageData)
     30  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     31  NS_INTERFACE_MAP_ENTRY(nsISupports)
     32 NS_INTERFACE_MAP_END
     33 
     34 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ImageData)
     35  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)
     36  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     37 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     38 
     39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ImageData)
     40  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
     41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     42 
     43 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ImageData)
     44  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     45  tmp->DropData();
     46  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
     47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     48 
     49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(ImageData)
     50  if (tmp->HasKnownLiveWrapper()) {
     51    tmp->mData.exposeToActiveJS();
     52    return true;
     53  }
     54 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
     55 
     56 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(ImageData)
     57  return tmp->HasKnownLiveWrapper() && tmp->HasNothingToTrace(tmp);
     58 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
     59 
     60 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(ImageData)
     61  return tmp->HasKnownLiveWrapper();
     62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
     63 
     64 // static
     65 already_AddRefed<ImageData> ImageData::Constructor(const GlobalObject& aGlobal,
     66                                                   const uint32_t aWidth,
     67                                                   const uint32_t aHeight,
     68                                                   ErrorResult& aRv) {
     69  if (aWidth == 0 || aHeight == 0) {
     70    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     71    return nullptr;
     72  }
     73 
     74  // Restrict the typed array length to INT32_MAX because that's all we support.
     75  CheckedInt<uint32_t> length = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
     76  if (!length.isValid() || length.value() > INT32_MAX) {
     77    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     78    return nullptr;
     79  }
     80  js::AssertSameCompartment(aGlobal.Context(), aGlobal.Get());
     81  JS::Rooted<JSObject*> data(
     82      aGlobal.Context(),
     83      Uint8ClampedArray::Create(aGlobal.Context(), length.value(), aRv));
     84  if (aRv.Failed()) {
     85    return nullptr;
     86  }
     87  RefPtr<ImageData> imageData =
     88      new ImageData(aGlobal.GetAsSupports(), aWidth, aHeight, data);
     89  return imageData.forget();
     90 }
     91 
     92 // static
     93 already_AddRefed<ImageData> ImageData::Constructor(
     94    const GlobalObject& aGlobal, const Uint8ClampedArray& aData,
     95    const uint32_t aWidth, const Optional<uint32_t>& aHeight,
     96    ErrorResult& aRv) {
     97  Maybe<uint32_t> maybeLength = aData.ProcessData(
     98      [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&& nogc) {
     99        return Some(aData.Length());
    100      });
    101  uint32_t length = maybeLength.valueOr(0);
    102  if (length == 0 || length % 4) {
    103    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    104    return nullptr;
    105  }
    106  length /= 4;
    107  if (aWidth == 0) {
    108    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    109    return nullptr;
    110  }
    111  uint32_t height = length / aWidth;
    112  if (length != aWidth * height ||
    113      (aHeight.WasPassed() && aHeight.Value() != height)) {
    114    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
    115    return nullptr;
    116  }
    117 
    118  JS::Rooted<JSObject*> dataObj(aGlobal.Context(), aData.Obj());
    119  RefPtr<ImageData> imageData =
    120      new ImageData(aGlobal.GetAsSupports(), aWidth, height, dataObj);
    121  return imageData.forget();
    122 }
    123 
    124 void ImageData::HoldData() { mozilla::HoldJSObjects(this); }
    125 
    126 void ImageData::DropData() {
    127  if (mData) {
    128    mData = nullptr;
    129    mozilla::DropJSObjects(this);
    130  }
    131 }
    132 
    133 JSObject* ImageData::WrapObject(JSContext* aCx,
    134                                JS::Handle<JSObject*> aGivenProto) {
    135  return ImageData_Binding::Wrap(aCx, this, aGivenProto);
    136 }
    137 
    138 // static
    139 already_AddRefed<ImageData> ImageData::ReadStructuredClone(
    140    JSContext* aCx, nsIGlobalObject* aGlobal,
    141    JSStructuredCloneReader* aReader) {
    142  // Read the information out of the stream.
    143  uint32_t width, height;
    144  JS::Rooted<JS::Value> dataArray(aCx);
    145  if (!JS_ReadUint32Pair(aReader, &width, &height) ||
    146      !JS_ReadTypedArray(aReader, &dataArray)) {
    147    return nullptr;
    148  }
    149  MOZ_ASSERT(dataArray.isObject());
    150 
    151  JS::Rooted<JSObject*> arrayObj(aCx, &dataArray.toObject());
    152  RefPtr<ImageData> imageData = new ImageData(aGlobal, width, height, arrayObj);
    153  return imageData.forget();
    154 }
    155 
    156 bool ImageData::WriteStructuredClone(JSContext* aCx,
    157                                     JSStructuredCloneWriter* aWriter) const {
    158  JS::Rooted<JS::Value> arrayValue(aCx, JS::ObjectValue(*GetDataObject()));
    159  if (!JS_WrapValue(aCx, &arrayValue)) {
    160    return false;
    161  }
    162 
    163  return JS_WriteUint32Pair(aWriter, Width(), Height()) &&
    164         JS_WriteTypedArray(aWriter, arrayValue);
    165 }
    166 
    167 }  // namespace mozilla::dom