mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			236 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
 | 
						|
// reserved. Use of this source code is governed by a BSD-style license that
 | 
						|
// can be found in the LICENSE file.
 | 
						|
 | 
						|
#include "libcef/common/value_base.h"
 | 
						|
 | 
						|
CefValueController::CefValueController()
 | 
						|
    : owner_value_(NULL), owner_object_(NULL) {}
 | 
						|
 | 
						|
CefValueController::~CefValueController() {
 | 
						|
  // Everything should already have been removed.
 | 
						|
  DCHECK(!owner_value_ && !owner_object_);
 | 
						|
  DCHECK(reference_map_.empty());
 | 
						|
  DCHECK(dependency_map_.empty());
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::SetOwner(void* value, Object* object) {
 | 
						|
  DCHECK(value && object);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  // Owner should only be set once.
 | 
						|
  DCHECK(!owner_value_ && !owner_object_);
 | 
						|
 | 
						|
  owner_value_ = value;
 | 
						|
  owner_object_ = object;
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::AddReference(void* value, Object* object) {
 | 
						|
  DCHECK(value && object);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  // Controller should currently have an owner.
 | 
						|
  DCHECK(owner_value_);
 | 
						|
 | 
						|
  // Values should only be added once.
 | 
						|
  DCHECK(reference_map_.find(value) == reference_map_.end());
 | 
						|
  DCHECK(value != owner_value_);
 | 
						|
 | 
						|
  reference_map_.insert(std::make_pair(value, object));
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::Remove(void* value, bool notify_object) {
 | 
						|
  DCHECK(value);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  // Controller should currently have an owner.
 | 
						|
  DCHECK(owner_value_);
 | 
						|
 | 
						|
  if (value == owner_value_) {
 | 
						|
    // Should never notify when removing the owner object.
 | 
						|
    DCHECK(!notify_object);
 | 
						|
 | 
						|
    owner_value_ = NULL;
 | 
						|
    owner_object_ = NULL;
 | 
						|
 | 
						|
    // Remove all references.
 | 
						|
    if (reference_map_.size() > 0) {
 | 
						|
      ReferenceMap::iterator it = reference_map_.begin();
 | 
						|
      for (; it != reference_map_.end(); ++it)
 | 
						|
        it->second->OnControlRemoved();
 | 
						|
      reference_map_.clear();
 | 
						|
    }
 | 
						|
 | 
						|
    // Remove all dependencies.
 | 
						|
    dependency_map_.clear();
 | 
						|
  } else {
 | 
						|
    ReferenceMap::iterator it = reference_map_.find(value);
 | 
						|
    if (it != reference_map_.end()) {
 | 
						|
      // Remove the reference.
 | 
						|
      if (notify_object)
 | 
						|
        it->second->OnControlRemoved();
 | 
						|
      reference_map_.erase(it);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
CefValueController::Object* CefValueController::Get(void* value) {
 | 
						|
  DCHECK(value);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  if (value == owner_value_) {
 | 
						|
    return owner_object_;
 | 
						|
  } else {
 | 
						|
    ReferenceMap::iterator it = reference_map_.find(value);
 | 
						|
    if (it != reference_map_.end())
 | 
						|
      return it->second;
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::AddDependency(void* parent, void* child) {
 | 
						|
  DCHECK(parent && child && parent != child);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  DependencyMap::iterator it = dependency_map_.find(parent);
 | 
						|
  if (it == dependency_map_.end()) {
 | 
						|
    // New set.
 | 
						|
    DependencySet set;
 | 
						|
    set.insert(child);
 | 
						|
    dependency_map_.insert(std::make_pair(parent, set));
 | 
						|
  } else if (it->second.find(child) == it->second.end()) {
 | 
						|
    // Update existing set.
 | 
						|
    it->second.insert(child);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::RemoveDependencies(void* value) {
 | 
						|
  DCHECK(value);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  if (dependency_map_.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  DependencyMap::iterator it_dependency = dependency_map_.find(value);
 | 
						|
  if (it_dependency == dependency_map_.end())
 | 
						|
    return;
 | 
						|
 | 
						|
  // Start with the set of dependencies for the current value.
 | 
						|
  DependencySet remove_set = it_dependency->second;
 | 
						|
  dependency_map_.erase(it_dependency);
 | 
						|
 | 
						|
  DependencySet::iterator it_value;
 | 
						|
  ReferenceMap::iterator it_reference;
 | 
						|
 | 
						|
  while (remove_set.size() > 0) {
 | 
						|
    it_value = remove_set.begin();
 | 
						|
    value = *it_value;
 | 
						|
    remove_set.erase(it_value);
 | 
						|
 | 
						|
    // Does the current value have dependencies?
 | 
						|
    it_dependency = dependency_map_.find(value);
 | 
						|
    if (it_dependency != dependency_map_.end()) {
 | 
						|
      // Append the dependency set to the remove set.
 | 
						|
      remove_set.insert(it_dependency->second.begin(),
 | 
						|
                        it_dependency->second.end());
 | 
						|
      dependency_map_.erase(it_dependency);
 | 
						|
    }
 | 
						|
 | 
						|
    // Does the current value have a reference?
 | 
						|
    it_reference = reference_map_.find(value);
 | 
						|
    if (it_reference != reference_map_.end()) {
 | 
						|
      // Remove the reference.
 | 
						|
      it_reference->second->OnControlRemoved();
 | 
						|
      reference_map_.erase(it_reference);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::TakeFrom(CefValueController* other) {
 | 
						|
  DCHECK(other);
 | 
						|
 | 
						|
  // Both controllers should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
  DCHECK(other->locked());
 | 
						|
 | 
						|
  if (!other->reference_map_.empty()) {
 | 
						|
    // Transfer references from the other to this.
 | 
						|
    ReferenceMap::iterator it = other->reference_map_.begin();
 | 
						|
    for (; it != other->reference_map_.end(); ++it) {
 | 
						|
      // References should only be added once.
 | 
						|
      DCHECK(reference_map_.find(it->first) == reference_map_.end());
 | 
						|
      reference_map_.insert(std::make_pair(it->first, it->second));
 | 
						|
    }
 | 
						|
    other->reference_map_.empty();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!other->dependency_map_.empty()) {
 | 
						|
    // Transfer dependencies from the other to this.
 | 
						|
    DependencyMap::iterator it_other = other->dependency_map_.begin();
 | 
						|
    for (; it_other != other->dependency_map_.end(); ++it_other) {
 | 
						|
      DependencyMap::iterator it_me = dependency_map_.find(it_other->first);
 | 
						|
      if (it_me == dependency_map_.end()) {
 | 
						|
        // All children are new.
 | 
						|
        dependency_map_.insert(
 | 
						|
            std::make_pair(it_other->first, it_other->second));
 | 
						|
      } else {
 | 
						|
        // Evaluate each child.
 | 
						|
        DependencySet::iterator it_other_set = it_other->second.begin();
 | 
						|
        for (; it_other_set != it_other->second.end(); ++it_other_set) {
 | 
						|
          if (it_me->second.find(*it_other_set) == it_me->second.end())
 | 
						|
            it_me->second.insert(*it_other_set);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CefValueController::Swap(void* old_value, void* new_value) {
 | 
						|
  DCHECK(old_value && new_value && old_value != new_value);
 | 
						|
 | 
						|
  // Controller should already be locked.
 | 
						|
  DCHECK(locked());
 | 
						|
 | 
						|
  if (owner_value_ == old_value)
 | 
						|
    owner_value_ = new_value;
 | 
						|
 | 
						|
  if (!reference_map_.empty()) {
 | 
						|
    ReferenceMap::iterator it = reference_map_.find(old_value);
 | 
						|
    if (it != reference_map_.end()) {
 | 
						|
      // References should only be added once.
 | 
						|
      DCHECK(reference_map_.find(new_value) == reference_map_.end());
 | 
						|
      reference_map_.insert(std::make_pair(new_value, it->second));
 | 
						|
      reference_map_.erase(it);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!dependency_map_.empty()) {
 | 
						|
    DependencyMap::iterator it = dependency_map_.find(old_value);
 | 
						|
    if (it != dependency_map_.end()) {
 | 
						|
      dependency_map_.insert(std::make_pair(new_value, it->second));
 | 
						|
      dependency_map_.erase(it);
 | 
						|
    }
 | 
						|
 | 
						|
    it = dependency_map_.begin();
 | 
						|
    for (; it != dependency_map_.end(); ++it) {
 | 
						|
      DependencySet::iterator dit = it->second.find(old_value);
 | 
						|
      if (dit != it->second.end()) {
 | 
						|
        it->second.insert(new_value);
 | 
						|
        it->second.erase(dit);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |