author Andrew Osmond <>
Tue, 24 Apr 2018 13:51:35 -0400
changeset 415325 1173dccd114e1c86047a6f01e341cf1c4ea8fe9c
parent 287075 58475d84315a54c9bda2dd19f9f0b9d1b4cb9ac2
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1444537 - Part 3. Fix how redecode errors could cause animated image state inconsistencies. r=tnikkel We can discard frames from an animated image if the memory footprint exceeds the threshold. This will cause us to redecode frames on demand instead. However decoders can fail to produce the same results on subsequent runs due to differences in memory pressure, etc. If this happens our state can get inconsistent. In particular, if we keep failing on the first frame, we end up in an infinite loop on the decoder thread. Since we don't have the owning image to signal, as we had to release our reference to it after the first pass, we can do little but stop decoding. From the user's perspective, the animation will come to a stop.

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at */

 * Provides DebugOnly, a type for variables used only in debug builds (i.e. by
 * assertions).

#ifndef mozilla_DebugOnly_h
#define mozilla_DebugOnly_h

#include "mozilla/Attributes.h"

namespace mozilla {

 * DebugOnly contains a value of type T, but only in debug builds.  In release
 * builds, it does not contain a value.  This helper is intended to be used with
 * MOZ_ASSERT()-style macros, allowing one to write:
 *   DebugOnly<bool> check = func();
 *   MOZ_ASSERT(check);
 * more concisely than declaring |check| conditional on #ifdef DEBUG.
 * DebugOnly instances can only be coerced to T in debug builds.  In release
 * builds they don't have a value, so type coercion is not well defined.
 * NOTE: DebugOnly instances still take up one byte of space, plus padding, even
 * in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info).
 * For this reason the class is MOZ_STACK_CLASS to prevent consumers using
 * DebugOnly for struct/class members and unwittingly inflating the size of
 * their objects in release builds.
template<typename T>
class MOZ_STACK_CLASS DebugOnly
#ifdef DEBUG
  T value;

  DebugOnly() { }
  MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) { }
  DebugOnly(const DebugOnly& aOther) : value(aOther.value) { }
  DebugOnly& operator=(const T& aRhs) {
    value = aRhs;
    return *this;

  void operator++(int) { value++; }
  void operator--(int) { value--; }

  // Do not define operator+=(), etc. here.  These will coerce via the
  // implicit cast and built-in operators.  Defining explicit methods here
  // will create ambiguity the compiler can't deal with.

  T* operator&() { return &value; }

  operator T&() { return value; }
  operator const T&() const { return value; }

  T& operator->() { return value; }
  const T& operator->() const { return value; }

  DebugOnly() { }
  MOZ_IMPLICIT DebugOnly(const T&) { }
  DebugOnly(const DebugOnly&) { }
  DebugOnly& operator=(const T&) { return *this; }
  void operator++(int) { }
  void operator--(int) { }
  DebugOnly& operator+=(const T&) { return *this; }
  DebugOnly& operator-=(const T&) { return *this; }
  DebugOnly& operator&=(const T&) { return *this; }
  DebugOnly& operator|=(const T&) { return *this; }
  DebugOnly& operator^=(const T&) { return *this; }

   * DebugOnly must always have a destructor or else it will
   * generate "unused variable" warnings, exactly what it's intended
   * to avoid!
  ~DebugOnly() {}

} // namespace mozilla

#endif /* mozilla_DebugOnly_h */