/* static */ uint32_t
ImageCacheKey::ComputeHash(ImageURL* aURI,
                           const Maybe<uint64_t>& aBlobSerial,
                           const PrincipalOriginAttributes& aAttrs,
                           void* aControlledDocument)
{
  // Since we frequently call Hash() several times in a row on the same
  // ImageCacheKey, as an optimization we compute our hash once and store it.

  nsPrintfCString ptr("%p", aControlledDocument);
  nsAutoCString suffix;
  aAttrs.CreateSuffix(suffix);

  if (aBlobSerial) {
    // For blob URIs, we hash the serial number of the underlying blob, so that
    // different blob URIs which point to the same blob share a cache entry. We
    // also include the ref portion of the URI to support media fragments which
    // requires us to create different Image objects even if the source data is
    // the same.
    nsAutoCString ref;
    aURI->GetRef(ref);
    return HashGeneric(*aBlobSerial, HashString(ref + suffix + ptr));
  }

  // For non-blob URIs, we hash the URI spec.
  nsAutoCString spec;
  aURI->GetSpec(spec);
  return HashString(spec + suffix + ptr);
}
static bool
WriteSuffixAndSpec(JSStructuredCloneWriter* aWriter,
                   const PrincipalOriginAttributes& aAttrs,
                   const nsCString& aSpec)
{
  nsAutoCString suffix;
  aAttrs.CreateSuffix(suffix);

  return JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
         JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
         JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length());
}