Blame dom/base/ImageTracker.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
/* table of images used in a document, for batch locking/unlocking and
Packit f0b94e
 * animating */
Packit f0b94e
Packit f0b94e
#include "ImageTracker.h"
Packit f0b94e
Packit f0b94e
#include "imgIRequest.h"
Packit f0b94e
#include "mozilla/Preferences.h"
Packit f0b94e
#include "nsXULAppAPI.h"
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
namespace dom {
Packit f0b94e
Packit f0b94e
ImageTracker::ImageTracker() : mLocking(false), mAnimating(true) {}
Packit f0b94e
Packit f0b94e
ImageTracker::~ImageTracker() { SetLockingState(false); }
Packit f0b94e
Packit f0b94e
nsresult ImageTracker::Add(imgIRequest* aImage) {
Packit f0b94e
  MOZ_ASSERT(aImage);
Packit f0b94e
Packit f0b94e
  nsresult rv = NS_OK;
Packit f0b94e
  auto entry = mImages.LookupForAdd(aImage);
Packit f0b94e
  if (entry) {
Packit f0b94e
    // The image is already in the hashtable.  Increment its count.
Packit f0b94e
    uint32_t oldCount = entry.Data();
Packit f0b94e
    MOZ_ASSERT(oldCount > 0, "Entry in the image tracker with count 0!");
Packit f0b94e
    entry.Data() = oldCount + 1;
Packit f0b94e
  } else {
Packit f0b94e
    // A new entry was inserted - set the count to 1.
Packit f0b94e
    entry.OrInsert([]() { return 1; });
Packit f0b94e
Packit f0b94e
    // If we're locking images, lock this image too.
Packit f0b94e
    if (mLocking) {
Packit f0b94e
      rv = aImage->LockImage();
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // If we're animating images, request that this image be animated too.
Packit f0b94e
    if (mAnimating) {
Packit f0b94e
      nsresult rv2 = aImage->IncrementAnimationConsumers();
Packit f0b94e
      rv = NS_SUCCEEDED(rv) ? rv2 : rv;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return rv;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult ImageTracker::Remove(imgIRequest* aImage, uint32_t aFlags) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aImage);
Packit f0b94e
Packit f0b94e
  // Get the old count. It should exist and be > 0.
Packit f0b94e
  if (auto entry = mImages.Lookup(aImage)) {
Packit f0b94e
    MOZ_ASSERT(entry.Data() > 0, "Entry in the image tracker with count 0!");
Packit f0b94e
    // If the count becomes zero, remove it from the tracker.
Packit f0b94e
    if (--entry.Data() == 0) {
Packit f0b94e
      entry.Remove();
Packit f0b94e
    } else {
Packit f0b94e
      return NS_OK;
Packit f0b94e
    }
Packit f0b94e
  } else {
Packit f0b94e
    MOZ_ASSERT_UNREACHABLE("Removing image that wasn't in the tracker!");
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsresult rv = NS_OK;
Packit f0b94e
Packit f0b94e
  // Now that we're no longer tracking this image, unlock it if we'd
Packit f0b94e
  // previously locked it.
Packit f0b94e
  if (mLocking) {
Packit f0b94e
    rv = aImage->UnlockImage();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If we're animating images, remove our request to animate this one.
Packit f0b94e
  if (mAnimating) {
Packit f0b94e
    nsresult rv2 = aImage->DecrementAnimationConsumers();
Packit f0b94e
    rv = NS_SUCCEEDED(rv) ? rv2 : rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aFlags & REQUEST_DISCARD) {
Packit f0b94e
    // Request that the image be discarded if nobody else holds a lock on it.
Packit f0b94e
    // Do this even if !mLocking, because even if we didn't just unlock
Packit f0b94e
    // this image, it might still be a candidate for discarding.
Packit f0b94e
    aImage->RequestDiscard();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return rv;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult ImageTracker::SetLockingState(bool aLocked) {
Packit f0b94e
  if (XRE_IsContentProcess() &&
Packit f0b94e
      !Preferences::GetBool("image.mem.allow_locking_in_content_processes",
Packit f0b94e
                            true)) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // If there's no change, there's nothing to do.
Packit f0b94e
  if (mLocking == aLocked) return NS_OK;
Packit f0b94e
Packit f0b94e
  // Otherwise, iterate over our images and perform the appropriate action.
Packit f0b94e
  for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    imgIRequest* image = iter.Key();
Packit f0b94e
    if (aLocked) {
Packit f0b94e
      image->LockImage();
Packit f0b94e
    } else {
Packit f0b94e
      image->UnlockImage();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Update state.
Packit f0b94e
  mLocking = aLocked;
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ImageTracker::SetAnimatingState(bool aAnimating) {
Packit f0b94e
  // If there's no change, there's nothing to do.
Packit f0b94e
  if (mAnimating == aAnimating) return;
Packit f0b94e
Packit f0b94e
  // Otherwise, iterate over our images and perform the appropriate action.
Packit f0b94e
  for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    imgIRequest* image = iter.Key();
Packit f0b94e
    if (aAnimating) {
Packit f0b94e
      image->IncrementAnimationConsumers();
Packit f0b94e
    } else {
Packit f0b94e
      image->DecrementAnimationConsumers();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Update state.
Packit f0b94e
  mAnimating = aAnimating;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void ImageTracker::RequestDiscardAll() {
Packit f0b94e
  for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
    iter.Key()->RequestDiscard();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace dom
Packit f0b94e
}  // namespace mozilla