<commit_before>// Copyright (c) 2006-2008 The Chromium 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 "chrome/common/chrome_plugin_lib.h"

#include "base/command_line.h"
#include "base/hash_tables.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/thread.h"
#if defined(OS_WIN)
#include "base/registry.h"
#endif
#include "base/string_util.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/chrome_paths.h"
#include "webkit/glue/plugins/plugin_list.h"

using base::TimeDelta;

// TODO(port): revisit when plugins happier
#if defined(OS_WIN)
const TCHAR ChromePluginLib::kRegistryChromePlugins[] =
    _T("Software\\Google\\Chrome\\Plugins");
static const TCHAR kRegistryLoadOnStartup[] = _T("LoadOnStartup");
static const TCHAR kRegistryPath[] = _T("Path");
#endif

typedef base::hash_map<FilePath, scoped_refptr<ChromePluginLib> >
    PluginMap;

// A map of all the instantiated plugins.
static PluginMap* g_loaded_libs;

// The thread plugins are loaded and used in, lazily initialized upon
// the first creation call.
static PlatformThreadId g_plugin_thread_id = 0;
static MessageLoop* g_plugin_thread_loop = NULL;

static bool IsSingleProcessMode() {
  // We don't support ChromePlugins in single-process mode.
  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
}

// static
bool ChromePluginLib::IsInitialized() {
  return (g_loaded_libs != NULL);
}

// static
ChromePluginLib* ChromePluginLib::Create(const FilePath& filename,
                                         const CPBrowserFuncs* bfuncs) {
  // Keep a map of loaded plugins to ensure we only load each library once.
  if (!g_loaded_libs) {
    g_loaded_libs = new PluginMap();
    g_plugin_thread_id = PlatformThread::CurrentId();
    g_plugin_thread_loop = MessageLoop::current();
  }
  DCHECK(IsPluginThread());

  PluginMap::const_iterator iter = g_loaded_libs->find(filename);
  if (iter != g_loaded_libs->end())
    return iter->second;

  scoped_refptr<ChromePluginLib> plugin(new ChromePluginLib(filename));
  if (!plugin->CP_Initialize(bfuncs))
    return NULL;

  (*g_loaded_libs)[filename] = plugin;
  return plugin;
}

// static
ChromePluginLib* ChromePluginLib::Find(const FilePath& filename) {
  if (g_loaded_libs) {
    PluginMap::const_iterator iter = g_loaded_libs->find(filename);
    if (iter != g_loaded_libs->end())
      return iter->second;
  }
  return NULL;
}

// static
void ChromePluginLib::Destroy(const FilePath& filename) {
  DCHECK(g_loaded_libs);
  PluginMap::iterator iter = g_loaded_libs->find(filename);
  if (iter != g_loaded_libs->end()) {
    iter->second->Unload();
    g_loaded_libs->erase(iter);
  }
}

// static
bool ChromePluginLib::IsPluginThread() {
  return PlatformThread::CurrentId() == g_plugin_thread_id;
}

// static
MessageLoop* ChromePluginLib::GetPluginThreadLoop() {
  return g_plugin_thread_loop;
}

// static
void ChromePluginLib::RegisterPluginsWithNPAPI() {
  // We don't support ChromePlugins in single-process mode.
  if (IsSingleProcessMode())
    return;

  FilePath path;
  if (!PathService::Get(chrome::FILE_GEARS_PLUGIN, &path))
    return;
  NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
}

static void LogPluginLoadTime(const TimeDelta &time) {
  UMA_HISTOGRAM_TIMES("Gears.LoadTime", time);
}

// static
void ChromePluginLib::LoadChromePlugins(const CPBrowserFuncs* bfuncs) {
  static bool loaded = false;
  if (loaded)
    return;
  loaded = true;

  // We don't support ChromePlugins in single-process mode.
  if (IsSingleProcessMode())
    return;

  FilePath path;
  if (!PathService::Get(chrome::FILE_GEARS_PLUGIN, &path))
    return;

  PerfTimer timer;
  ChromePluginLib::Create(path, bfuncs);
  LogPluginLoadTime(timer.Elapsed());

  // TODO(mpcomplete): disabled loading of plugins from the registry until we
  // phase out registry keys from the gears installer.
#if 0
  for (RegistryKeyIterator iter(HKEY_CURRENT_USER, kRegistryChromePlugins);
       iter.Valid(); ++iter) {
    // Use the registry to gather plugin across the file system.
    std::wstring reg_path = kRegistryChromePlugins;
    reg_path.append(L"\\");
    reg_path.append(iter.Name());
    RegKey key(HKEY_CURRENT_USER, reg_path.c_str());

    DWORD is_persistent;
    if (key.ReadValueDW(kRegistryLoadOnStartup, &is_persistent) &&
        is_persistent) {
      std::wstring path;
      if (key.ReadValue(kRegistryPath, &path)) {
        ChromePluginLib::Create(path, bfuncs);
      }
    }
  }
#endif
}

// static
void ChromePluginLib::UnloadAllPlugins() {
  if (g_loaded_libs) {
    PluginMap::iterator it;
    for (PluginMap::iterator it = g_loaded_libs->begin();
         it != g_loaded_libs->end(); ++it) {
      it->second->Unload();
    }
    delete g_loaded_libs;
    g_loaded_libs = NULL;
  }
}

const CPPluginFuncs& ChromePluginLib::functions() const {
  DCHECK(initialized_);
  DCHECK(IsPluginThread());
  return plugin_funcs_;
}

ChromePluginLib::ChromePluginLib(const FilePath& filename)
    : filename_(filename),
#if defined(OS_WIN)
      module_(0),
#endif
      initialized_(false),
      CP_VersionNegotiate_(NULL),
      CP_Initialize_(NULL) {
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
}

ChromePluginLib::~ChromePluginLib() {
}

bool ChromePluginLib::CP_Initialize(const CPBrowserFuncs* bfuncs) {
  LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() <<
               "): initialized=" << initialized_;
  if (initialized_)
    return true;

  if (!Load())
    return false;

  if (CP_VersionNegotiate_) {
    uint16 selected_version = 0;
    CPError rv = CP_VersionNegotiate_(CP_VERSION, CP_VERSION,
                                      &selected_version);
    if ( (rv != CPERR_SUCCESS) || (selected_version != CP_VERSION))
      return false;
  }

  plugin_funcs_.size = sizeof(plugin_funcs_);
  CPError rv = CP_Initialize_(cpid(), bfuncs, &plugin_funcs_);
  initialized_ = (rv == CPERR_SUCCESS) &&
      (CP_GET_MAJOR_VERSION(plugin_funcs_.version) == CP_MAJOR_VERSION) &&
      (CP_GET_MINOR_VERSION(plugin_funcs_.version) <= CP_MINOR_VERSION);
  LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() <<
               "): initialized=" << initialized_ <<
               "): result=" << rv;

  return initialized_;
}

void ChromePluginLib::CP_Shutdown() {
  DCHECK(initialized_);
  functions().shutdown();
  initialized_ = false;
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
}

int ChromePluginLib::CP_Test(void* param) {
  DCHECK(initialized_);
  if (!CP_Test_)
    return -1;
  return CP_Test_(param);
}

bool ChromePluginLib::Load() {
#if !defined(OS_WIN)
  // Mac and Linux won't implement Gears.
  return false;
#else
  DCHECK(module_ == 0);

  module_ = LoadLibrary(filename_.value().c_str());
  if (module_ == 0)
    return false;

  // required initialization function
  CP_Initialize_ = reinterpret_cast<CP_InitializeFunc>
      (GetProcAddress(module_, "CP_Initialize"));

  if (!CP_Initialize_) {
    FreeLibrary(module_);
    module_ = 0;
    return false;
  }

  // optional version negotiation function
  CP_VersionNegotiate_ = reinterpret_cast<CP_VersionNegotiateFunc>
      (GetProcAddress(module_, "CP_VersionNegotiate"));

  // optional test function
  CP_Test_ = reinterpret_cast<CP_TestFunc>
      (GetProcAddress(module_, "CP_Test"));

  return true;
#endif
}

void ChromePluginLib::Unload() {
  NotificationService::current()->Notify(
      NotificationType::CHROME_PLUGIN_UNLOADED,
      Source<ChromePluginLib>(this),
      NotificationService::NoDetails());

  if (initialized_)
    CP_Shutdown();

#if defined(OS_WIN)
  if (module_) {
    FreeLibrary(module_);
    module_ = 0;
  }
#endif
}
<commit_msg>Register internal plugins.<commit_after>// Copyright (c) 2006-2008 The Chromium 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 "chrome/common/chrome_plugin_lib.h"

#include "base/command_line.h"
#include "base/hash_tables.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/thread.h"
#if defined(OS_WIN)
#include "base/registry.h"
#endif
#include "base/string_util.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/chrome_paths.h"
#include "webkit/glue/plugins/plugin_list.h"

using base::TimeDelta;

// TODO(port): revisit when plugins happier
#if defined(OS_WIN)
const TCHAR ChromePluginLib::kRegistryChromePlugins[] =
    _T("Software\\Google\\Chrome\\Plugins");
static const TCHAR kRegistryLoadOnStartup[] = _T("LoadOnStartup");
static const TCHAR kRegistryPath[] = _T("Path");
#endif

typedef base::hash_map<FilePath, scoped_refptr<ChromePluginLib> >
    PluginMap;

// A map of all the instantiated plugins.
static PluginMap* g_loaded_libs;

// The thread plugins are loaded and used in, lazily initialized upon
// the first creation call.
static PlatformThreadId g_plugin_thread_id = 0;
static MessageLoop* g_plugin_thread_loop = NULL;

static bool IsSingleProcessMode() {
  // We don't support ChromePlugins in single-process mode.
  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
}

// static
bool ChromePluginLib::IsInitialized() {
  return (g_loaded_libs != NULL);
}

// static
ChromePluginLib* ChromePluginLib::Create(const FilePath& filename,
                                         const CPBrowserFuncs* bfuncs) {
  // Keep a map of loaded plugins to ensure we only load each library once.
  if (!g_loaded_libs) {
    g_loaded_libs = new PluginMap();
    g_plugin_thread_id = PlatformThread::CurrentId();
    g_plugin_thread_loop = MessageLoop::current();
  }
  DCHECK(IsPluginThread());

  PluginMap::const_iterator iter = g_loaded_libs->find(filename);
  if (iter != g_loaded_libs->end())
    return iter->second;

  scoped_refptr<ChromePluginLib> plugin(new ChromePluginLib(filename));
  if (!plugin->CP_Initialize(bfuncs))
    return NULL;

  (*g_loaded_libs)[filename] = plugin;
  return plugin;
}

// static
ChromePluginLib* ChromePluginLib::Find(const FilePath& filename) {
  if (g_loaded_libs) {
    PluginMap::const_iterator iter = g_loaded_libs->find(filename);
    if (iter != g_loaded_libs->end())
      return iter->second;
  }
  return NULL;
}

// static
void ChromePluginLib::Destroy(const FilePath& filename) {
  DCHECK(g_loaded_libs);
  PluginMap::iterator iter = g_loaded_libs->find(filename);
  if (iter != g_loaded_libs->end()) {
    iter->second->Unload();
    g_loaded_libs->erase(iter);
  }
}

// static
bool ChromePluginLib::IsPluginThread() {
  return PlatformThread::CurrentId() == g_plugin_thread_id;
}

// static
MessageLoop* ChromePluginLib::GetPluginThreadLoop() {
  return g_plugin_thread_loop;
}

// static
void ChromePluginLib::RegisterPluginsWithNPAPI() {
  // We don't support ChromePlugins in single-process mode.
  if (IsSingleProcessMode())
    return;

  FilePath path;
  // Register Gears, if available.
  if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &path))
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);

  // Register the internal Flash, if available.
  if (PathService::Get(chrome::FILE_FLASH_PLUGIN, &path))
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
}

static void LogPluginLoadTime(const TimeDelta &time) {
  UMA_HISTOGRAM_TIMES("Gears.LoadTime", time);
}

// static
void ChromePluginLib::LoadChromePlugins(const CPBrowserFuncs* bfuncs) {
  static bool loaded = false;
  if (loaded)
    return;
  loaded = true;

  // We don't support ChromePlugins in single-process mode.
  if (IsSingleProcessMode())
    return;

  FilePath path;
  if (!PathService::Get(chrome::FILE_GEARS_PLUGIN, &path))
    return;

  PerfTimer timer;
  ChromePluginLib::Create(path, bfuncs);
  LogPluginLoadTime(timer.Elapsed());

  // TODO(mpcomplete): disabled loading of plugins from the registry until we
  // phase out registry keys from the gears installer.
#if 0
  for (RegistryKeyIterator iter(HKEY_CURRENT_USER, kRegistryChromePlugins);
       iter.Valid(); ++iter) {
    // Use the registry to gather plugin across the file system.
    std::wstring reg_path = kRegistryChromePlugins;
    reg_path.append(L"\\");
    reg_path.append(iter.Name());
    RegKey key(HKEY_CURRENT_USER, reg_path.c_str());

    DWORD is_persistent;
    if (key.ReadValueDW(kRegistryLoadOnStartup, &is_persistent) &&
        is_persistent) {
      std::wstring path;
      if (key.ReadValue(kRegistryPath, &path)) {
        ChromePluginLib::Create(path, bfuncs);
      }
    }
  }
#endif
}

// static
void ChromePluginLib::UnloadAllPlugins() {
  if (g_loaded_libs) {
    PluginMap::iterator it;
    for (PluginMap::iterator it = g_loaded_libs->begin();
         it != g_loaded_libs->end(); ++it) {
      it->second->Unload();
    }
    delete g_loaded_libs;
    g_loaded_libs = NULL;
  }
}

const CPPluginFuncs& ChromePluginLib::functions() const {
  DCHECK(initialized_);
  DCHECK(IsPluginThread());
  return plugin_funcs_;
}

ChromePluginLib::ChromePluginLib(const FilePath& filename)
    : filename_(filename),
#if defined(OS_WIN)
      module_(0),
#endif
      initialized_(false),
      CP_VersionNegotiate_(NULL),
      CP_Initialize_(NULL) {
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
}

ChromePluginLib::~ChromePluginLib() {
}

bool ChromePluginLib::CP_Initialize(const CPBrowserFuncs* bfuncs) {
  LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() <<
               "): initialized=" << initialized_;
  if (initialized_)
    return true;

  if (!Load())
    return false;

  if (CP_VersionNegotiate_) {
    uint16 selected_version = 0;
    CPError rv = CP_VersionNegotiate_(CP_VERSION, CP_VERSION,
                                      &selected_version);
    if ( (rv != CPERR_SUCCESS) || (selected_version != CP_VERSION))
      return false;
  }

  plugin_funcs_.size = sizeof(plugin_funcs_);
  CPError rv = CP_Initialize_(cpid(), bfuncs, &plugin_funcs_);
  initialized_ = (rv == CPERR_SUCCESS) &&
      (CP_GET_MAJOR_VERSION(plugin_funcs_.version) == CP_MAJOR_VERSION) &&
      (CP_GET_MINOR_VERSION(plugin_funcs_.version) <= CP_MINOR_VERSION);
  LOG(INFO) << "ChromePluginLib::CP_Initialize(" << filename_.value() <<
               "): initialized=" << initialized_ <<
               "): result=" << rv;

  return initialized_;
}

void ChromePluginLib::CP_Shutdown() {
  DCHECK(initialized_);
  functions().shutdown();
  initialized_ = false;
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
}

int ChromePluginLib::CP_Test(void* param) {
  DCHECK(initialized_);
  if (!CP_Test_)
    return -1;
  return CP_Test_(param);
}

bool ChromePluginLib::Load() {
#if !defined(OS_WIN)
  // Mac and Linux won't implement Gears.
  return false;
#else
  DCHECK(module_ == 0);

  module_ = LoadLibrary(filename_.value().c_str());
  if (module_ == 0)
    return false;

  // required initialization function
  CP_Initialize_ = reinterpret_cast<CP_InitializeFunc>
      (GetProcAddress(module_, "CP_Initialize"));

  if (!CP_Initialize_) {
    FreeLibrary(module_);
    module_ = 0;
    return false;
  }

  // optional version negotiation function
  CP_VersionNegotiate_ = reinterpret_cast<CP_VersionNegotiateFunc>
      (GetProcAddress(module_, "CP_VersionNegotiate"));

  // optional test function
  CP_Test_ = reinterpret_cast<CP_TestFunc>
      (GetProcAddress(module_, "CP_Test"));

  return true;
#endif
}

void ChromePluginLib::Unload() {
  NotificationService::current()->Notify(
      NotificationType::CHROME_PLUGIN_UNLOADED,
      Source<ChromePluginLib>(this),
      NotificationService::NoDetails());

  if (initialized_)
    CP_Shutdown();

#if defined(OS_WIN)
  if (module_) {
    FreeLibrary(module_);
    module_ = 0;
  }
#endif
}
<|endoftext|>


<commit_before><commit_msg>fix win build<commit_after><|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "TagQuery.h"

#include "QueryRegistry.h"

#include "ModelBase/src/nodes/composite/CompositeNode.h"
#include "ModelBase/src/model/TreeManager.h"

#include "../nodes/TagExtension.h"

namespace InformationScripting {

const QStringList TagQuery::NAME_ARGUMENT_NAMES{"n", "name"};
const QStringList TagQuery::ADD_ARGUMENT_NAMES{"a", "add"};
const QStringList TagQuery::REMOVE_ARGUMENT_NAMES{"r", "remove"};
const QStringList TagQuery::PERSISTENT_ARGUMENT_NAMES{"p", "persistent"};

QList<TupleSet> TagQuery::execute(QList<TupleSet> input)
{
	return exec_(this, input);
}

void TagQuery::registerDefaultQueries()
{
	QueryRegistry::instance().registerQueryConstructor("tags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::tags, target, args);
	});
	// Alias to "tags -a"
	QueryRegistry::instance().registerQueryConstructor("addTags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::addTags, target, args);
	});
	// Alias to "tags -r"
	QueryRegistry::instance().registerQueryConstructor("removeTags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::removeTags, target, args);
	});
}

TagQuery::TagQuery(ExecuteFunction<TagQuery> exec, Model::Node* target, QStringList args)
	: ScopedArgumentQuery{target, {
			{NAME_ARGUMENT_NAMES, "Tag name, or regex to find tag", NAME_ARGUMENT_NAMES[1]},
			QCommandLineOption{ADD_ARGUMENT_NAMES},
			QCommandLineOption{REMOVE_ARGUMENT_NAMES},
			{PERSISTENT_ARGUMENT_NAMES, "Wether the change is persistent, default = yes", PERSISTENT_ARGUMENT_NAMES[1], "yes"}
}, QStringList("TagQuery") + args}, exec_{exec}
{
	persistent_ = argument(PERSISTENT_ARGUMENT_NAMES[1]) == "yes";
}

QList<TupleSet> TagQuery::tags(QList<TupleSet> input)
{
	bool addSet = isArgumentSet(ADD_ARGUMENT_NAMES[0]);
	bool removeSet = isArgumentSet(REMOVE_ARGUMENT_NAMES[0]);
	Q_ASSERT(!(addSet && removeSet)); // TODO should be user warning
	if (addSet)
		return addTags(input);
	else if (removeSet)
		return removeTags(input);
	else
		return queryTags(input);
}

QList<TupleSet> TagQuery::queryTags(QList<TupleSet> input)
{
	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning
	QList<TupleSet> result = input;

	// Querying tags non persistent would just return the tag tuples in the input.
	if (!persistent_) return input;

	if (scope() == Scope::Local || scope() == Scope::Global)
	{
		auto targetNode = scope() == Scope::Local ? target() : nullptr;
		if (result.empty()) result << TupleSet();
		insertFoundTags(result[0], matcherFor(tagText), targetNode);
	}
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);

		auto matcher = matcherFor(tagText);
		auto astTuples = result[0].tuples("ast");
		for (auto tuple : astTuples)
			insertFoundTags(result[0], matcher, tuple["ast"]);
	}
	return result;
}

QList<TupleSet> TagQuery::addTags(QList<TupleSet> input)
{
	QList<TupleSet> result = input;
	QList<Model::Node*> addTagsTo;

	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning

	if (scope() == Scope::Local)
	{
		if (result.empty()) result << TupleSet();
		addTagsTo << target();
	}
	else if (scope() == Scope::Global)
	{
		// That doesn't make sense, to which nodes should we add the tags?
		// TODO: warn user
	}
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);
		for (const auto& tuple : result[0].tuples("ast"))
			addTagsTo << static_cast<Model::Node*>(tuple["ast"]);
	}

	if (persistent_)
	{
		auto treeManager = target()->manager();
		treeManager->beginModification(target(), "addTags");
		for (auto node : addTagsTo)
		{
			if (auto astNode = DCast<Model::CompositeNode>(node))
			{
				auto tagExtension = astNode->extension<TagExtension>();
				treeManager->changeModificationTarget(astNode);
				tagExtension->tags()->append(new Model::Text{tagText});
			}
		}
		treeManager->endModification();
	}

	for (auto node : addTagsTo)
		result[0].add({{"tag", tagText}, {"ast", node}});

	return result;
}

QList<TupleSet> TagQuery::removeTags(QList<TupleSet> input)
{
	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning

	QList<TupleSet> result = input;
	auto matcher = matcherFor(tagText);
	QString tagName = "tag";
	TupleSet removedTuples;
	if (scope() == Scope::Local)
		insertFoundTags(removedTuples, matcher, target());
	else if (scope() == Scope::Global)
		insertFoundTags(removedTuples, matcher);
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);
		auto astTuples = result[0].tuples("ast");
		for (auto tuple : astTuples)
			insertFoundTags(removedTuples, matcher, tuple["ast"]);
	}

	if (persistent_)
	{
		auto treeManager = target()->manager();
		treeManager->beginModification(target(), "removeTags");
		for (const auto& tuple : removedTuples.tuples(tagName))
		{
			Model::Node* node = tuple["ast"];
			if (auto astNode = DCast<Model::CompositeNode>(node))
			{
				auto tagExtension = astNode->extension<TagExtension>();
				auto tagsList = tagExtension->tags();
				treeManager->changeModificationTarget(tagsList);
				auto tagsIndex = 0;
				while (tagsIndex < tagsList->size())
				{
					if (matcher.matches(tagsList->at(tagsIndex)->get())) tagsList->remove(tagsIndex);
					else ++tagsIndex;
				}
			}
		}
		treeManager->endModification();
	}

	if (result.size() > 0)
	{
		for (const auto& tuple : removedTuples.take(tagName))
			result[0].remove(tuple);
	}

	return result;
}

void TagQuery::insertFoundTags(TupleSet& tuples, const Model::SymbolMatcher& matcher, Model::Node* from)
{
	Q_ASSERT(persistent_);

	if (!from) from = target()->root();

	QList<Model::Node*> workStack{from};

	while (!workStack.empty())
	{
		auto node = workStack.takeLast();
		if (auto astNode = DCast<Model::CompositeNode>(node))
		{
			auto tagExtension = astNode->extension<TagExtension>();
			for (auto tag : *(tagExtension->tags()))
				if (matcher.matches(tag->get()))
					tuples.add({{"tag", tag->get()}, {"ast", astNode}});
		}
		workStack << node->children();
	}
}

} /* namespace InformationScripting */
<commit_msg>Assert that the TreeManager exists in TagQuery<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "TagQuery.h"

#include "QueryRegistry.h"

#include "ModelBase/src/nodes/composite/CompositeNode.h"
#include "ModelBase/src/model/TreeManager.h"

#include "../nodes/TagExtension.h"

namespace InformationScripting {

const QStringList TagQuery::NAME_ARGUMENT_NAMES{"n", "name"};
const QStringList TagQuery::ADD_ARGUMENT_NAMES{"a", "add"};
const QStringList TagQuery::REMOVE_ARGUMENT_NAMES{"r", "remove"};
const QStringList TagQuery::PERSISTENT_ARGUMENT_NAMES{"p", "persistent"};

QList<TupleSet> TagQuery::execute(QList<TupleSet> input)
{
	return exec_(this, input);
}

void TagQuery::registerDefaultQueries()
{
	QueryRegistry::instance().registerQueryConstructor("tags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::tags, target, args);
	});
	// Alias to "tags -a"
	QueryRegistry::instance().registerQueryConstructor("addTags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::addTags, target, args);
	});
	// Alias to "tags -r"
	QueryRegistry::instance().registerQueryConstructor("removeTags", [](Model::Node* target, QStringList args) {
		return new TagQuery(&TagQuery::removeTags, target, args);
	});
}

TagQuery::TagQuery(ExecuteFunction<TagQuery> exec, Model::Node* target, QStringList args)
	: ScopedArgumentQuery{target, {
			{NAME_ARGUMENT_NAMES, "Tag name, or regex to find tag", NAME_ARGUMENT_NAMES[1]},
			QCommandLineOption{ADD_ARGUMENT_NAMES},
			QCommandLineOption{REMOVE_ARGUMENT_NAMES},
			{PERSISTENT_ARGUMENT_NAMES, "Wether the change is persistent, default = yes", PERSISTENT_ARGUMENT_NAMES[1], "yes"}
}, QStringList("TagQuery") + args}, exec_{exec}
{
	persistent_ = argument(PERSISTENT_ARGUMENT_NAMES[1]) == "yes";
}

QList<TupleSet> TagQuery::tags(QList<TupleSet> input)
{
	bool addSet = isArgumentSet(ADD_ARGUMENT_NAMES[0]);
	bool removeSet = isArgumentSet(REMOVE_ARGUMENT_NAMES[0]);
	Q_ASSERT(!(addSet && removeSet)); // TODO should be user warning
	if (addSet)
		return addTags(input);
	else if (removeSet)
		return removeTags(input);
	else
		return queryTags(input);
}

QList<TupleSet> TagQuery::queryTags(QList<TupleSet> input)
{
	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning
	QList<TupleSet> result = input;

	// Querying tags non persistent would just return the tag tuples in the input.
	if (!persistent_) return input;

	if (scope() == Scope::Local || scope() == Scope::Global)
	{
		auto targetNode = scope() == Scope::Local ? target() : nullptr;
		if (result.empty()) result << TupleSet();
		insertFoundTags(result[0], matcherFor(tagText), targetNode);
	}
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);

		auto matcher = matcherFor(tagText);
		auto astTuples = result[0].tuples("ast");
		for (auto tuple : astTuples)
			insertFoundTags(result[0], matcher, tuple["ast"]);
	}
	return result;
}

QList<TupleSet> TagQuery::addTags(QList<TupleSet> input)
{
	QList<TupleSet> result = input;
	QList<Model::Node*> addTagsTo;

	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning

	if (scope() == Scope::Local)
	{
		if (result.empty()) result << TupleSet();
		addTagsTo << target();
	}
	else if (scope() == Scope::Global)
	{
		// That doesn't make sense, to which nodes should we add the tags?
		// TODO: warn user
	}
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);
		for (const auto& tuple : result[0].tuples("ast"))
			addTagsTo << static_cast<Model::Node*>(tuple["ast"]);
	}

	if (persistent_)
	{
		auto treeManager = target()->manager();
		Q_ASSERT(treeManager);
		treeManager->beginModification(target(), "addTags");
		for (auto node : addTagsTo)
		{
			if (auto astNode = DCast<Model::CompositeNode>(node))
			{
				auto tagExtension = astNode->extension<TagExtension>();
				treeManager->changeModificationTarget(astNode);
				tagExtension->tags()->append(new Model::Text{tagText});
			}
		}
		treeManager->endModification();
	}

	for (auto node : addTagsTo)
		result[0].add({{"tag", tagText}, {"ast", node}});

	return result;
}

QList<TupleSet> TagQuery::removeTags(QList<TupleSet> input)
{
	QString tagText = argument(NAME_ARGUMENT_NAMES[0]);
	Q_ASSERT(tagText.size() > 0); // TODO should be user warning

	QList<TupleSet> result = input;
	auto matcher = matcherFor(tagText);
	QString tagName = "tag";
	TupleSet removedTuples;
	if (scope() == Scope::Local)
		insertFoundTags(removedTuples, matcher, target());
	else if (scope() == Scope::Global)
		insertFoundTags(removedTuples, matcher);
	else if (scope() == Scope::Input)
	{
		Q_ASSERT(input.size() > 0);
		auto astTuples = result[0].tuples("ast");
		for (auto tuple : astTuples)
			insertFoundTags(removedTuples, matcher, tuple["ast"]);
	}

	if (persistent_)
	{
		auto treeManager = target()->manager();
		Q_ASSERT(treeManager);
		treeManager->beginModification(target(), "removeTags");
		for (const auto& tuple : removedTuples.tuples(tagName))
		{
			Model::Node* node = tuple["ast"];
			if (auto astNode = DCast<Model::CompositeNode>(node))
			{
				auto tagExtension = astNode->extension<TagExtension>();
				auto tagsList = tagExtension->tags();
				treeManager->changeModificationTarget(tagsList);
				auto tagsIndex = 0;
				while (tagsIndex < tagsList->size())
				{
					if (matcher.matches(tagsList->at(tagsIndex)->get())) tagsList->remove(tagsIndex);
					else ++tagsIndex;
				}
			}
		}
		treeManager->endModification();
	}

	if (result.size() > 0)
	{
		for (const auto& tuple : removedTuples.take(tagName))
			result[0].remove(tuple);
	}

	return result;
}

void TagQuery::insertFoundTags(TupleSet& tuples, const Model::SymbolMatcher& matcher, Model::Node* from)
{
	Q_ASSERT(persistent_);

	if (!from) from = target()->root();

	QList<Model::Node*> workStack{from};

	while (!workStack.empty())
	{
		auto node = workStack.takeLast();
		if (auto astNode = DCast<Model::CompositeNode>(node))
		{
			auto tagExtension = astNode->extension<TagExtension>();
			for (auto tag : *(tagExtension->tags()))
				if (matcher.matches(tag->get()))
					tuples.add({{"tag", tag->get()}, {"ast", astNode}});
		}
		workStack << node->children();
	}
}

} /* namespace InformationScripting */
<|endoftext|>


<commit_before><commit_msg>Fixed a hang in ChromeFrame while tearing down pending url requests during shutdown. This would occur when we received a redirect notification on an aborted request. We would end up aborting the request twice which would cause the UrlmonUrlRequest object to be destroyed twice by IE, thus resulting in a junk reference in the request map.<commit_after><|endoftext|>


<commit_before>#include "Test.h"
#include "SkBitmap.h"
#include "SkRect.h"

static const char* boolStr(bool value) {
    return value ? "true" : "false";
}

// these are in the same order as the SkBitmap::Config enum
static const char* gConfigName[] = {
    "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8"
};

static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src,
                              const SkBitmap& dst) {
    SkString str;
    str.printf("src %s opaque:%d, dst %s opaque:%d",
               gConfigName[src.config()], src.isOpaque(),
               gConfigName[dst.config()], dst.isOpaque());
    reporter->reportFailed(str);
}

static bool canHaveAlpha(SkBitmap::Config config) {
    return config != SkBitmap::kRGB_565_Config;
}

// copyTo() should preserve isOpaque when it makes sense
static void test_isOpaque(skiatest::Reporter* reporter, const SkBitmap& src,
                          SkBitmap::Config dstConfig) {
    SkBitmap bitmap(src);
    SkBitmap dst;

    // we need the lock so that we get a valid colorTable (when available)
    SkAutoLockPixels alp(bitmap);
    SkColorTable* ctable = bitmap.getColorTable();
    unsigned ctableFlags = ctable ? ctable->getFlags() : 0;

    if (canHaveAlpha(bitmap.config()) && canHaveAlpha(dstConfig)) {
        bitmap.setIsOpaque(false);
        if (ctable) {
            ctable->setFlags(ctableFlags & ~SkColorTable::kColorsAreOpaque_Flag);
        }
        REPORTER_ASSERT(reporter, bitmap.copyTo(&dst, dstConfig));
        REPORTER_ASSERT(reporter, dst.config() == dstConfig);
        if (bitmap.isOpaque() != dst.isOpaque()) {
            report_opaqueness(reporter, bitmap, dst);
        }
    }

    bitmap.setIsOpaque(true);
    if (ctable) {
        ctable->setFlags(ctableFlags | SkColorTable::kColorsAreOpaque_Flag);
    }
    REPORTER_ASSERT(reporter, bitmap.copyTo(&dst, dstConfig));
    REPORTER_ASSERT(reporter, dst.config() == dstConfig);
    if (bitmap.isOpaque() != dst.isOpaque()) {
        report_opaqueness(reporter, bitmap, dst);
    }

    if (ctable) {
        ctable->setFlags(ctableFlags);
    }
}

static void init_src(const SkBitmap& bitmap) {
    SkAutoLockPixels lock(bitmap);
    if (bitmap.getPixels()) {
        memset(bitmap.getPixels(), 4, bitmap.getSize());
    }
}

SkColorTable* init_ctable() {
    static const SkColor colors[] = {
        SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE
    };
    return new SkColorTable(colors, SK_ARRAY_COUNT(colors));
}

struct Pair {
    SkBitmap::Config    fConfig;
    const char*         fValid;
};

static void TestBitmapCopy(skiatest::Reporter* reporter) {
    static const Pair gPairs[] = {
        { SkBitmap::kNo_Config,         "00000000"  },
        { SkBitmap::kA1_Config,         "01000000"  },
        { SkBitmap::kA8_Config,         "00101110"  },
        { SkBitmap::kIndex8_Config,     "00111110"  },
        { SkBitmap::kRGB_565_Config,    "00101110"  },
        { SkBitmap::kARGB_4444_Config,  "00101110"  },
        { SkBitmap::kARGB_8888_Config,  "00101110"  },
// TODO: create valid RLE bitmap to test with
 //       { SkBitmap::kRLE_Index8_Config, "00101111"  }
    };

    const int W = 20;
    const int H = 33;

    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
        for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
            SkBitmap src, dst;
            SkColorTable* ct = NULL;

            src.setConfig(gPairs[i].fConfig, W, H);
            if (SkBitmap::kIndex8_Config == src.config() ||
                    SkBitmap::kRLE_Index8_Config == src.config()) {
                ct = init_ctable();
            }
            src.allocPixels(ct);
            ct->safeRef();

            init_src(src);
            bool success = src.copyTo(&dst, gPairs[j].fConfig);
            bool expected = gPairs[i].fValid[j] != '0';
            if (success != expected) {
                SkString str;
                str.printf("SkBitmap::copyTo from %s to %s. expected %s returned %s",
                           gConfigName[i], gConfigName[j], boolStr(expected),
                           boolStr(success));
                reporter->reportFailed(str);
            }

            bool canSucceed = src.canCopyTo(gPairs[j].fConfig);
            if (success != canSucceed) {
                SkString str;
                str.printf("SkBitmap::copyTo from %s to %s. returned %s canCopyTo %s",
                           gConfigName[i], gConfigName[j], boolStr(success),
                           boolStr(canSucceed));
                reporter->reportFailed(str);
            }

            if (success) {
                REPORTER_ASSERT(reporter, src.width() == dst.width());
                REPORTER_ASSERT(reporter, src.height() == dst.height());
                REPORTER_ASSERT(reporter, dst.config() == gPairs[j].fConfig);
                test_isOpaque(reporter, src, dst.config());
                if (src.config() == dst.config()) {
                    SkAutoLockPixels srcLock(src);
                    SkAutoLockPixels dstLock(dst);
                    REPORTER_ASSERT(reporter, src.readyToDraw());
                    REPORTER_ASSERT(reporter, dst.readyToDraw());
                    const char* srcP = (const char*)src.getAddr(0, 0);
                    const char* dstP = (const char*)dst.getAddr(0, 0);
                    REPORTER_ASSERT(reporter, srcP != dstP);
                    REPORTER_ASSERT(reporter, !memcmp(srcP, dstP,
                                                      src.getSize()));
                }
                // test extractSubset
                {
                    SkBitmap subset;
                    SkIRect r;
                    r.set(1, 1, 2, 2);
                    if (src.extractSubset(&subset, r)) {
                        REPORTER_ASSERT(reporter, subset.width() == 1);
                        REPORTER_ASSERT(reporter, subset.height() == 1);

                        SkBitmap copy;
                        REPORTER_ASSERT(reporter,
                                        subset.copyTo(&copy, subset.config()));
                        REPORTER_ASSERT(reporter, copy.width() == 1);
                        REPORTER_ASSERT(reporter, copy.height() == 1);
                        REPORTER_ASSERT(reporter, copy.rowBytes() <= 4);

                        SkAutoLockPixels alp0(subset);
                        SkAutoLockPixels alp1(copy);
                        // they should both have, or both not-have, a colortable
                        bool hasCT = subset.getColorTable() != NULL;
                        REPORTER_ASSERT(reporter,
                                    (copy.getColorTable() != NULL) == hasCT);
                    }
                }
            } else {
                // dst should be unchanged from its initial state
                REPORTER_ASSERT(reporter, dst.config() == SkBitmap::kNo_Config);
                REPORTER_ASSERT(reporter, dst.width() == 0);
                REPORTER_ASSERT(reporter, dst.height() == 0);
            }
        }
    }
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("BitmapCopy", TestBitmapCopyClass, TestBitmapCopy)
<commit_msg>fix memory leak<commit_after>#include "Test.h"
#include "SkBitmap.h"
#include "SkRect.h"

static const char* boolStr(bool value) {
    return value ? "true" : "false";
}

// these are in the same order as the SkBitmap::Config enum
static const char* gConfigName[] = {
    "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8"
};

static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src,
                              const SkBitmap& dst) {
    SkString str;
    str.printf("src %s opaque:%d, dst %s opaque:%d",
               gConfigName[src.config()], src.isOpaque(),
               gConfigName[dst.config()], dst.isOpaque());
    reporter->reportFailed(str);
}

static bool canHaveAlpha(SkBitmap::Config config) {
    return config != SkBitmap::kRGB_565_Config;
}

// copyTo() should preserve isOpaque when it makes sense
static void test_isOpaque(skiatest::Reporter* reporter, const SkBitmap& src,
                          SkBitmap::Config dstConfig) {
    SkBitmap bitmap(src);
    SkBitmap dst;

    // we need the lock so that we get a valid colorTable (when available)
    SkAutoLockPixels alp(bitmap);
    SkColorTable* ctable = bitmap.getColorTable();
    unsigned ctableFlags = ctable ? ctable->getFlags() : 0;

    if (canHaveAlpha(bitmap.config()) && canHaveAlpha(dstConfig)) {
        bitmap.setIsOpaque(false);
        if (ctable) {
            ctable->setFlags(ctableFlags & ~SkColorTable::kColorsAreOpaque_Flag);
        }
        REPORTER_ASSERT(reporter, bitmap.copyTo(&dst, dstConfig));
        REPORTER_ASSERT(reporter, dst.config() == dstConfig);
        if (bitmap.isOpaque() != dst.isOpaque()) {
            report_opaqueness(reporter, bitmap, dst);
        }
    }

    bitmap.setIsOpaque(true);
    if (ctable) {
        ctable->setFlags(ctableFlags | SkColorTable::kColorsAreOpaque_Flag);
    }
    REPORTER_ASSERT(reporter, bitmap.copyTo(&dst, dstConfig));
    REPORTER_ASSERT(reporter, dst.config() == dstConfig);
    if (bitmap.isOpaque() != dst.isOpaque()) {
        report_opaqueness(reporter, bitmap, dst);
    }

    if (ctable) {
        ctable->setFlags(ctableFlags);
    }
}

static void init_src(const SkBitmap& bitmap) {
    SkAutoLockPixels lock(bitmap);
    if (bitmap.getPixels()) {
        memset(bitmap.getPixels(), 4, bitmap.getSize());
    }
}

SkColorTable* init_ctable() {
    static const SkColor colors[] = {
        SK_ColorBLACK, SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE
    };
    return new SkColorTable(colors, SK_ARRAY_COUNT(colors));
}

struct Pair {
    SkBitmap::Config    fConfig;
    const char*         fValid;
};

static void TestBitmapCopy(skiatest::Reporter* reporter) {
    static const Pair gPairs[] = {
        { SkBitmap::kNo_Config,         "00000000"  },
        { SkBitmap::kA1_Config,         "01000000"  },
        { SkBitmap::kA8_Config,         "00101110"  },
        { SkBitmap::kIndex8_Config,     "00111110"  },
        { SkBitmap::kRGB_565_Config,    "00101110"  },
        { SkBitmap::kARGB_4444_Config,  "00101110"  },
        { SkBitmap::kARGB_8888_Config,  "00101110"  },
// TODO: create valid RLE bitmap to test with
 //       { SkBitmap::kRLE_Index8_Config, "00101111"  }
    };

    const int W = 20;
    const int H = 33;

    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
        for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
            SkBitmap src, dst;
            SkColorTable* ct = NULL;

            src.setConfig(gPairs[i].fConfig, W, H);
            if (SkBitmap::kIndex8_Config == src.config() ||
                    SkBitmap::kRLE_Index8_Config == src.config()) {
                ct = init_ctable();
            }
            src.allocPixels(ct);
            SkSafeUnref(ct);

            init_src(src);
            bool success = src.copyTo(&dst, gPairs[j].fConfig);
            bool expected = gPairs[i].fValid[j] != '0';
            if (success != expected) {
                SkString str;
                str.printf("SkBitmap::copyTo from %s to %s. expected %s returned %s",
                           gConfigName[i], gConfigName[j], boolStr(expected),
                           boolStr(success));
                reporter->reportFailed(str);
            }

            bool canSucceed = src.canCopyTo(gPairs[j].fConfig);
            if (success != canSucceed) {
                SkString str;
                str.printf("SkBitmap::copyTo from %s to %s. returned %s canCopyTo %s",
                           gConfigName[i], gConfigName[j], boolStr(success),
                           boolStr(canSucceed));
                reporter->reportFailed(str);
            }

            if (success) {
                REPORTER_ASSERT(reporter, src.width() == dst.width());
                REPORTER_ASSERT(reporter, src.height() == dst.height());
                REPORTER_ASSERT(reporter, dst.config() == gPairs[j].fConfig);
                test_isOpaque(reporter, src, dst.config());
                if (src.config() == dst.config()) {
                    SkAutoLockPixels srcLock(src);
                    SkAutoLockPixels dstLock(dst);
                    REPORTER_ASSERT(reporter, src.readyToDraw());
                    REPORTER_ASSERT(reporter, dst.readyToDraw());
                    const char* srcP = (const char*)src.getAddr(0, 0);
                    const char* dstP = (const char*)dst.getAddr(0, 0);
                    REPORTER_ASSERT(reporter, srcP != dstP);
                    REPORTER_ASSERT(reporter, !memcmp(srcP, dstP,
                                                      src.getSize()));
                }
                // test extractSubset
                {
                    SkBitmap subset;
                    SkIRect r;
                    r.set(1, 1, 2, 2);
                    if (src.extractSubset(&subset, r)) {
                        REPORTER_ASSERT(reporter, subset.width() == 1);
                        REPORTER_ASSERT(reporter, subset.height() == 1);

                        SkBitmap copy;
                        REPORTER_ASSERT(reporter,
                                        subset.copyTo(&copy, subset.config()));
                        REPORTER_ASSERT(reporter, copy.width() == 1);
                        REPORTER_ASSERT(reporter, copy.height() == 1);
                        REPORTER_ASSERT(reporter, copy.rowBytes() <= 4);

                        SkAutoLockPixels alp0(subset);
                        SkAutoLockPixels alp1(copy);
                        // they should both have, or both not-have, a colortable
                        bool hasCT = subset.getColorTable() != NULL;
                        REPORTER_ASSERT(reporter,
                                    (copy.getColorTable() != NULL) == hasCT);
                    }
                }
            } else {
                // dst should be unchanged from its initial state
                REPORTER_ASSERT(reporter, dst.config() == SkBitmap::kNo_Config);
                REPORTER_ASSERT(reporter, dst.width() == 0);
                REPORTER_ASSERT(reporter, dst.height() == 0);
            }
        }
    }
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("BitmapCopy", TestBitmapCopyClass, TestBitmapCopy)
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS

#include "GrContextFactory.h"
#include "GrInvariantOutput.h"
#include "GrPipeline.h"
#include "GrTest.h"
#include "GrXferProcessor.h"
#include "SkChecksum.h"
#include "SkRandom.h"
#include "Test.h"
#include "effects/GrConfigConversionEffect.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLPathRendering.h"
#include "gl/builders/GrGLProgramBuilder.h"

/*
 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
 * whole thing correctly
 */
static const uint32_t kMaxKeySize = 1024;

class GLBigKeyProcessor : public GrGLFragmentProcessor {
public:
    GLBigKeyProcessor(const GrProcessor&) {}

    virtual void emitCode(GrGLFPBuilder* builder,
                          const GrFragmentProcessor& fp,
                          const char* outputColor,
                          const char* inputColor,
                          const TransformedCoordsArray&,
                          const TextureSamplerArray&) {}

    static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
        for (uint32_t i = 0; i < kMaxKeySize; i++) {
            b->add32(i);
        }
    }

private:
    typedef GrGLFragmentProcessor INHERITED;
};

class BigKeyProcessor : public GrFragmentProcessor {
public:
    static GrFragmentProcessor* Create() {
        GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
        return SkRef(gBigKeyProcessor);
    }

    const char* name() const SK_OVERRIDE { return "Big Ole Key"; }

    virtual void getGLProcessorKey(const GrGLCaps& caps,
                                   GrProcessorKeyBuilder* b) const SK_OVERRIDE {
        GLBigKeyProcessor::GenKey(*this, caps, b);
    }

    GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
        return SkNEW_ARGS(GLBigKeyProcessor, (*this));
    }

private:
    BigKeyProcessor() {
        this->initClassID<BigKeyProcessor>();
    }
    bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
    void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { }

    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;

    typedef GrFragmentProcessor INHERITED;
};

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);

GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
                                                 GrContext*,
                                                 const GrDrawTargetCaps&,
                                                 GrTexture*[]) {
    return BigKeyProcessor::Create();
}

/*
 * Begin test code
 */
static const int kRenderTargetHeight = 1;
static const int kRenderTargetWidth = 1;

static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random) {
    // setup render target
    GrTextureParams params;
    GrSurfaceDesc texDesc;
    texDesc.fWidth = kRenderTargetWidth;
    texDesc.fHeight = kRenderTargetHeight;
    texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    texDesc.fConfig = kRGBA_8888_GrPixelConfig;
    texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
                                                   kBottomLeft_GrSurfaceOrigin;
    GrContentKey key;
    static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain();
    GrContentKey::Builder builder(&key, kDomain, 1);
    builder[0] = texDesc.fOrigin;
    builder.finish();

    GrTexture* texture = context->findAndRefCachedTexture(key);
    if (!texture) {
        texture = context->createTexture(texDesc, true);
        if (texture) {
            SkAssertResult(context->addResourceToCache(key, texture));
        }
    }
    return texture ? texture->asRenderTarget() : NULL;
}

static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,
                           GrPipelineBuilder* pipelineBuilder, SkRandom* random,
                           GrTexture* dummyTextures[]) {
    SkAutoTUnref<const GrXPFactory> xpf(
        GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
    SkASSERT(xpf);
    pipelineBuilder->setXPFactory(xpf.get());
}

static const GrGeometryProcessor* get_random_gp(GrContext* context,
                                                const GrDrawTargetCaps& caps,
                                                SkRandom* random,
                                                GrTexture* dummyTextures[]) {
    return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
                                                                    context,
                                                                    caps,
                                                                    dummyTextures);
}

static void set_random_color_coverage_stages(GrGLGpu* gpu,
                                             GrPipelineBuilder* pipelineBuilder,
                                             int maxStages,
                                             bool usePathRendering,
                                             SkRandom* random,
                                             GrTexture* dummyTextures[]) {
    int numProcs = random->nextULessThan(maxStages + 1);
    int numColorProcs = random->nextULessThan(numProcs + 1);

    int currTextureCoordSet = 0;
    for (int s = 0; s < numProcs;) {
        SkAutoTUnref<const GrFragmentProcessor> fp(
                GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
                                                                         gpu->getContext(),
                                                                         *gpu->caps(),
                                                                         dummyTextures));
        SkASSERT(fp);

        // If adding this effect would exceed the max texture coord set count then generate a
        // new random effect.
        if (usePathRendering && gpu->glPathRendering()->texturingMode() ==
                                GrGLPathRendering::FixedFunction_TexturingMode) {;
            int numTransforms = fp->numTransforms();
            if (currTextureCoordSet + numTransforms >
                gpu->glCaps().maxFixedFunctionTextureCoords()) {
                continue;
            }
            currTextureCoordSet += numTransforms;
        }

        // finally add the stage to the correct pipeline in the drawstate
        if (s < numColorProcs) {
            pipelineBuilder->addColorProcessor(fp);
        } else {
            pipelineBuilder->addCoverageProcessor(fp);
        }
        ++s;
    }
}

static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    int state = 0;
    for (int i = 1; i <= GrPipelineBuilder::kLast_StateBit; i <<= 1) {
        state |= random->nextBool() * i;
    }
    pipelineBuilder->enableState(state);
}

// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
                                 kReplace_StencilOp,
                                 kReplace_StencilOp,
                                 kAlways_StencilFunc,
                                 0xffff,
                                 0xffff,
                                 0xffff);
    GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
                                 kKeep_StencilOp,
                                 kKeep_StencilOp,
                                 kNever_StencilFunc,
                                 0xffff,
                                 0xffff,
                                 0xffff);

    if (random->nextBool()) {
        pipelineBuilder->setStencil(kDoesWriteStencil);
    } else {
        pipelineBuilder->setStencil(kDoesNotWriteStencil);
    }
}

bool GrDrawTarget::programUnitTest(int maxStages) {
    GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

    // dummy scissor state
    GrScissorState scissor;

    // setup clip
    SkRect screen = SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth),
                                   SkIntToScalar(kRenderTargetHeight));

    SkClipStack stack;
    stack.clipDevRect(screen, SkRegion::kReplace_Op, false);

    // wrap the SkClipStack in a GrClipData
    GrClipData clipData;
    clipData.fClipStack.reset(SkRef(&stack));
    this->setClip(&clipData);

    SkRandom random;
    static const int NUM_TESTS = 512;
    for (int t = 0; t < NUM_TESTS;) {
        // setup random render target(can fail)
        SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, &random));
        if (!rt.get()) {
            SkDebugf("Could not allocate render target");
            return false;
        }

        GrPipelineBuilder pipelineBuilder;
        pipelineBuilder.setRenderTarget(rt.get());

        // if path rendering we have to setup a couple of things like the draw type
        bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();

        // twiddle drawstate knobs randomly
        bool hasGeometryProcessor = !usePathRendering;
        SkAutoTUnref<const GrGeometryProcessor> gp;
        SkAutoTUnref<const GrPathProcessor> pathProc;
        if (hasGeometryProcessor) {
            gp.reset(get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures));
        } else {
            pathProc.reset(GrPathProcessor::Create(GrColor_WHITE));
        }
        set_random_color_coverage_stages(gpu,
                                         &pipelineBuilder,
                                         maxStages - hasGeometryProcessor,
                                         usePathRendering,
                                         &random,
                                         dummyTextures);

        // creates a random xfer processor factory on the draw state
        set_random_xpf(fContext, gpu->glCaps(), &pipelineBuilder, &random, dummyTextures);

        set_random_state(&pipelineBuilder, &random);
        set_random_stencil(&pipelineBuilder, &random);

        GrDeviceCoordTexture dstCopy;

        const GrPrimitiveProcessor* primProc;
        if (hasGeometryProcessor) {
            primProc = gp.get();
        } else {
            primProc = pathProc.get();
        }

        const GrProcOptInfo& colorPOI = pipelineBuilder.colorProcInfo(primProc);
        const GrProcOptInfo& coveragePOI = pipelineBuilder.coverageProcInfo(primProc);

        if (!this->setupDstReadIfNecessary(pipelineBuilder, colorPOI, coveragePOI, &dstCopy,
                                           NULL)) {
            SkDebugf("Couldn't setup dst read texture");
            return false;
        }

        // create optimized draw state, setup readDst texture if required, and build a descriptor
        // and program.  ODS creation can fail, so we have to check
        GrPipeline pipeline(pipelineBuilder, colorPOI, coveragePOI,
                            *gpu->caps(), scissor, &dstCopy);
        if (pipeline.mustSkip()) {
            continue;
        }
        GrBatchTracker bt;
        primProc->initBatchTracker(&bt, pipeline.getInitBatchTracker());

        GrProgramDesc desc;
        gpu->buildProgramDesc(&desc, *primProc, pipeline, bt);

        GrGpu::DrawArgs args(primProc, &pipeline, &desc, &bt);
        SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(args, gpu));

        if (NULL == program.get()) {
            SkDebugf("Failed to create program!");
            return false;
        }

        // because occasionally optimized drawstate creation will fail for valid reasons, we only
        // want to increment on success
        ++t;
    }
    return true;
}

DEF_GPUTEST(GLPrograms, reporter, factory) {
    for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
        GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
        if (context) {
            GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());

            /*
             * For the time being, we only support the test with desktop GL or for android on
             * ARM platforms
             * TODO When we run ES 3.00 GLSL in more places, test again
             */
            int maxStages;
            if (kGL_GrGLStandard == gpu->glStandard() ||
                kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
                maxStages = 6;
            } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
                       kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
                maxStages = 1;
            } else {
                return;
            }
#if SK_ANGLE
            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
            if (type == GrContextFactory::kANGLE_GLContextType) {
                maxStages = 3;
            }
#endif
            GrTestTarget target;
            context->getTestTarget(&target);
            REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));
        }
    }
}

#endif
<commit_msg>Decrease number of allowed stages for Angle on GLProgramTest<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS

#include "GrContextFactory.h"
#include "GrInvariantOutput.h"
#include "GrPipeline.h"
#include "GrTest.h"
#include "GrXferProcessor.h"
#include "SkChecksum.h"
#include "SkRandom.h"
#include "Test.h"
#include "effects/GrConfigConversionEffect.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLPathRendering.h"
#include "gl/builders/GrGLProgramBuilder.h"

/*
 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
 * whole thing correctly
 */
static const uint32_t kMaxKeySize = 1024;

class GLBigKeyProcessor : public GrGLFragmentProcessor {
public:
    GLBigKeyProcessor(const GrProcessor&) {}

    virtual void emitCode(GrGLFPBuilder* builder,
                          const GrFragmentProcessor& fp,
                          const char* outputColor,
                          const char* inputColor,
                          const TransformedCoordsArray&,
                          const TextureSamplerArray&) {}

    static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
        for (uint32_t i = 0; i < kMaxKeySize; i++) {
            b->add32(i);
        }
    }

private:
    typedef GrGLFragmentProcessor INHERITED;
};

class BigKeyProcessor : public GrFragmentProcessor {
public:
    static GrFragmentProcessor* Create() {
        GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
        return SkRef(gBigKeyProcessor);
    }

    const char* name() const SK_OVERRIDE { return "Big Ole Key"; }

    virtual void getGLProcessorKey(const GrGLCaps& caps,
                                   GrProcessorKeyBuilder* b) const SK_OVERRIDE {
        GLBigKeyProcessor::GenKey(*this, caps, b);
    }

    GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
        return SkNEW_ARGS(GLBigKeyProcessor, (*this));
    }

private:
    BigKeyProcessor() {
        this->initClassID<BigKeyProcessor>();
    }
    bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
    void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { }

    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;

    typedef GrFragmentProcessor INHERITED;
};

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);

GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
                                                 GrContext*,
                                                 const GrDrawTargetCaps&,
                                                 GrTexture*[]) {
    return BigKeyProcessor::Create();
}

/*
 * Begin test code
 */
static const int kRenderTargetHeight = 1;
static const int kRenderTargetWidth = 1;

static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random) {
    // setup render target
    GrTextureParams params;
    GrSurfaceDesc texDesc;
    texDesc.fWidth = kRenderTargetWidth;
    texDesc.fHeight = kRenderTargetHeight;
    texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    texDesc.fConfig = kRGBA_8888_GrPixelConfig;
    texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
                                                   kBottomLeft_GrSurfaceOrigin;
    GrContentKey key;
    static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain();
    GrContentKey::Builder builder(&key, kDomain, 1);
    builder[0] = texDesc.fOrigin;
    builder.finish();

    GrTexture* texture = context->findAndRefCachedTexture(key);
    if (!texture) {
        texture = context->createTexture(texDesc, true);
        if (texture) {
            SkAssertResult(context->addResourceToCache(key, texture));
        }
    }
    return texture ? texture->asRenderTarget() : NULL;
}

static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,
                           GrPipelineBuilder* pipelineBuilder, SkRandom* random,
                           GrTexture* dummyTextures[]) {
    SkAutoTUnref<const GrXPFactory> xpf(
        GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
    SkASSERT(xpf);
    pipelineBuilder->setXPFactory(xpf.get());
}

static const GrGeometryProcessor* get_random_gp(GrContext* context,
                                                const GrDrawTargetCaps& caps,
                                                SkRandom* random,
                                                GrTexture* dummyTextures[]) {
    return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
                                                                    context,
                                                                    caps,
                                                                    dummyTextures);
}

static void set_random_color_coverage_stages(GrGLGpu* gpu,
                                             GrPipelineBuilder* pipelineBuilder,
                                             int maxStages,
                                             bool usePathRendering,
                                             SkRandom* random,
                                             GrTexture* dummyTextures[]) {
    int numProcs = random->nextULessThan(maxStages + 1);
    int numColorProcs = random->nextULessThan(numProcs + 1);

    int currTextureCoordSet = 0;
    for (int s = 0; s < numProcs;) {
        SkAutoTUnref<const GrFragmentProcessor> fp(
                GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
                                                                         gpu->getContext(),
                                                                         *gpu->caps(),
                                                                         dummyTextures));
        SkASSERT(fp);

        // If adding this effect would exceed the max texture coord set count then generate a
        // new random effect.
        if (usePathRendering && gpu->glPathRendering()->texturingMode() ==
                                GrGLPathRendering::FixedFunction_TexturingMode) {;
            int numTransforms = fp->numTransforms();
            if (currTextureCoordSet + numTransforms >
                gpu->glCaps().maxFixedFunctionTextureCoords()) {
                continue;
            }
            currTextureCoordSet += numTransforms;
        }

        // finally add the stage to the correct pipeline in the drawstate
        if (s < numColorProcs) {
            pipelineBuilder->addColorProcessor(fp);
        } else {
            pipelineBuilder->addCoverageProcessor(fp);
        }
        ++s;
    }
}

static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    int state = 0;
    for (int i = 1; i <= GrPipelineBuilder::kLast_StateBit; i <<= 1) {
        state |= random->nextBool() * i;
    }
    pipelineBuilder->enableState(state);
}

// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
    GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
                                 kReplace_StencilOp,
                                 kReplace_StencilOp,
                                 kAlways_StencilFunc,
                                 0xffff,
                                 0xffff,
                                 0xffff);
    GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
                                 kKeep_StencilOp,
                                 kKeep_StencilOp,
                                 kNever_StencilFunc,
                                 0xffff,
                                 0xffff,
                                 0xffff);

    if (random->nextBool()) {
        pipelineBuilder->setStencil(kDoesWriteStencil);
    } else {
        pipelineBuilder->setStencil(kDoesNotWriteStencil);
    }
}

bool GrDrawTarget::programUnitTest(int maxStages) {
    GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

    // dummy scissor state
    GrScissorState scissor;

    // setup clip
    SkRect screen = SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth),
                                   SkIntToScalar(kRenderTargetHeight));

    SkClipStack stack;
    stack.clipDevRect(screen, SkRegion::kReplace_Op, false);

    // wrap the SkClipStack in a GrClipData
    GrClipData clipData;
    clipData.fClipStack.reset(SkRef(&stack));
    this->setClip(&clipData);

    SkRandom random;
    static const int NUM_TESTS = 512;
    for (int t = 0; t < NUM_TESTS;) {
        // setup random render target(can fail)
        SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, &random));
        if (!rt.get()) {
            SkDebugf("Could not allocate render target");
            return false;
        }

        GrPipelineBuilder pipelineBuilder;
        pipelineBuilder.setRenderTarget(rt.get());

        // if path rendering we have to setup a couple of things like the draw type
        bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();

        // twiddle drawstate knobs randomly
        bool hasGeometryProcessor = !usePathRendering;
        SkAutoTUnref<const GrGeometryProcessor> gp;
        SkAutoTUnref<const GrPathProcessor> pathProc;
        if (hasGeometryProcessor) {
            gp.reset(get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures));
        } else {
            pathProc.reset(GrPathProcessor::Create(GrColor_WHITE));
        }
        set_random_color_coverage_stages(gpu,
                                         &pipelineBuilder,
                                         maxStages - hasGeometryProcessor,
                                         usePathRendering,
                                         &random,
                                         dummyTextures);

        // creates a random xfer processor factory on the draw state
        set_random_xpf(fContext, gpu->glCaps(), &pipelineBuilder, &random, dummyTextures);

        set_random_state(&pipelineBuilder, &random);
        set_random_stencil(&pipelineBuilder, &random);

        GrDeviceCoordTexture dstCopy;

        const GrPrimitiveProcessor* primProc;
        if (hasGeometryProcessor) {
            primProc = gp.get();
        } else {
            primProc = pathProc.get();
        }

        const GrProcOptInfo& colorPOI = pipelineBuilder.colorProcInfo(primProc);
        const GrProcOptInfo& coveragePOI = pipelineBuilder.coverageProcInfo(primProc);

        if (!this->setupDstReadIfNecessary(pipelineBuilder, colorPOI, coveragePOI, &dstCopy,
                                           NULL)) {
            SkDebugf("Couldn't setup dst read texture");
            return false;
        }

        // create optimized draw state, setup readDst texture if required, and build a descriptor
        // and program.  ODS creation can fail, so we have to check
        GrPipeline pipeline(pipelineBuilder, colorPOI, coveragePOI,
                            *gpu->caps(), scissor, &dstCopy);
        if (pipeline.mustSkip()) {
            continue;
        }
        GrBatchTracker bt;
        primProc->initBatchTracker(&bt, pipeline.getInitBatchTracker());

        GrProgramDesc desc;
        gpu->buildProgramDesc(&desc, *primProc, pipeline, bt);

        GrGpu::DrawArgs args(primProc, &pipeline, &desc, &bt);
        SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(args, gpu));

        if (NULL == program.get()) {
            SkDebugf("Failed to create program!");
            return false;
        }

        // because occasionally optimized drawstate creation will fail for valid reasons, we only
        // want to increment on success
        ++t;
    }
    return true;
}

DEF_GPUTEST(GLPrograms, reporter, factory) {
    for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
        GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
        if (context) {
            GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());

            /*
             * For the time being, we only support the test with desktop GL or for android on
             * ARM platforms
             * TODO When we run ES 3.00 GLSL in more places, test again
             */
            int maxStages;
            if (kGL_GrGLStandard == gpu->glStandard() ||
                kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
                maxStages = 6;
            } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
                       kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
                maxStages = 1;
            } else {
                return;
            }
#if SK_ANGLE
            // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
            if (type == GrContextFactory::kANGLE_GLContextType) {
                maxStages = 2;
            }
#endif
            GrTestTarget target;
            context->getTestTarget(&target);
            REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));
        }
    }
}

#endif
<|endoftext|>


<commit_before>/*
 * sodium_utils.cpp
 *
 *  Created on: Mar 30, 2018
 *      Author: Daniel
 */

#include "sodium_utils.hpp"

const std::string& SodiumUtils::SODIUM_PUBLIC_HEADER()
{
	const static std::string value = "SODIUM PUBLIC KEY\n";
	return value;
}

const std::string& SodiumUtils::SODIUM_PRIVATE_HEADER()
{
	const static std::string value = "SODIUM PRIVATE KEY\n";
	return value;
}

bool SodiumUtils::checkSodiumPrivate(const std::string& input)
{
	std::string privateHeader = SODIUM_PRIVATE_HEADER();
	bool hasHeader = (input.length() > 0 && input.substr(0, privateHeader.length()) == privateHeader);
	bool expectedLength = (input.length() == (privateHeader.length() + crypto_box_SECRETKEYBYTES*3));
	return hasHeader && expectedLength;
}

bool SodiumUtils::checkSodiumPublic(const std::string& input)
{
	std::string publicHeader = SODIUM_PUBLIC_HEADER();
	bool hasHeader = (input.length() > 0 && input.substr(0, publicHeader.length()) == publicHeader);
	bool expectedLength = (input.length() == (publicHeader.length() + crypto_box_PUBLICKEYBYTES*3));
	return hasHeader && expectedLength;
}

std::string SodiumUtils::randomString(int length)
{
	if(sodium_init() == -1)
	{
		exit(1); //any signs of sodium failure makes this program useless
	}

	int alphanumLength = 62;
	const std::string alphanum[] =
    {"0","1","2","3","4",
    "5","6","7","8","9",
    "A","B","C","D","E","F",
    "G","H","I","J","K",
    "L","M","N","O","P",
    "Q","R","S","T","U",
    "V","W","X","Y","Z",
    "a","b","c","d","e","f",
    "g","h","i","j","k",
    "l","m","n","o","p",
    "q","r","s","t","u",
    "v","w","x","y","z"
    };

	std::string randomized = "";
	for(int i=0; i<length; i++)
	{
		int index = randombytes_uniform(alphanumLength);
		std::string character = alphanum[index];
		randomized = randomized + character;
	}
	return randomized;
}

void SodiumUtils::sodiumEncrypt(bool asym, const unsigned char* input, int inputLength, const unsigned char* myPrivate, const unsigned char* yourPublic, std::unique_ptr<unsigned char[]>& output, int& outputLength)
{
	//setup nonce (like password salt)
	int nonceLength = 0;
	if(asym)
	{
		nonceLength = crypto_box_NONCEBYTES;
	}
	else
	{
		nonceLength = crypto_secretbox_NONCEBYTES;
	}
	unsigned char nonce[nonceLength] = {};
	randombytes_buf(nonce, nonceLength);

	//setup cipher text
	int cipherTextLength = 0, libsodiumOK = 0;
	unsigned char cipherText[2000] = {}; //guaranteed bigger than MTU of 1500
	if(asym)
	{
		cipherTextLength = crypto_box_MACBYTES + inputLength;
		libsodiumOK = crypto_box_easy(cipherText, input, inputLength, nonce, yourPublic, myPrivate);
	}
	else
	{
		cipherTextLength = crypto_secretbox_MACBYTES + inputLength;
		libsodiumOK = crypto_secretbox_easy(cipherText, input, inputLength, nonce, myPrivate); //myPrivate more like "ourPrivate" for symmetric
	}

	//encryption failed
	if(libsodiumOK != 0)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	unsigned char messageLengthDisassembled[sizeof(uint32_t)] = {};
	disassembleInt(inputLength, messageLengthDisassembled);

	//assemble the output
	const int finalSetupLength = crypto_box_NONCEBYTES+sizeof(uint32_t)+cipherTextLength;
//	unsigned char* finalSetup = new unsigned char[finalSetupLength];
	output = std::make_unique<unsigned char[]>(finalSetupLength);
	memset(output.get(), 0, finalSetupLength);
	memcpy(output.get(), nonce, crypto_box_NONCEBYTES);
	memcpy(output.get()+crypto_box_NONCEBYTES, messageLengthDisassembled, sizeof(uint32_t));
	memcpy(output.get()+crypto_box_NONCEBYTES+sizeof(uint32_t), cipherText, cipherTextLength);

	outputLength = finalSetupLength;
	//output[nonce|message length|encrypted]
}

void SodiumUtils::sodiumDecrypt(bool asym, const unsigned char* input, int inputLength, const unsigned char* myPrivate, const unsigned char* yourPublic, std::unique_ptr<unsigned char[]>& output, int& outputLength)
{
	//input[nonce|message length|encrypted]

	//extracts nonce (sorta like a salt)
	int nonceLength = 0;
	if(asym)
	{
		nonceLength = crypto_box_NONCEBYTES;
	}
	else
	{
		nonceLength = crypto_secretbox_NONCEBYTES;
	}
	if(nonceLength > inputLength)
	{
		//invalid encrypted bytes, doesn't have a nonce
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}
	unsigned char nonce[nonceLength] = {};
	memcpy(nonce, input, nonceLength);

	//get the message length (and figure out the cipher text length)
	if((nonceLength + sizeof(uint32_t)) > inputLength)
	{
		//invalid encrypted bytes, doesn't have a message length
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}
	unsigned char messageLengthDisassembled[sizeof(uint32_t)];
	memcpy(messageLengthDisassembled, input+crypto_box_NONCEBYTES, sizeof(uint32_t));
	const int messageLength = reassembleInt(messageLengthDisassembled);
	const int cipherLength = inputLength - crypto_box_NONCEBYTES - sizeof(uint32_t);

	//check to make sure the message length makes sense
	const bool messageCompressed = messageLength > cipherLength; //this isn't a compression function. not possible
	const bool messageMIA = messageLength < 1;
	if(messageCompressed || messageMIA)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	unsigned char cipherText[cipherLength] = {};
	memcpy(cipherText, input+crypto_box_NONCEBYTES+sizeof(uint32_t), cipherLength);
	//store the message in somewhere it is guaranteed to fit in case messageLength is bogus/malicious
	unsigned char messageStorage[cipherLength] = {};

	int libsodiumOK = 0;
	if(asym)
	{
		libsodiumOK = crypto_box_open_easy(messageStorage, cipherText, cipherLength, nonce, yourPublic, myPrivate);
	}
	else
	{
		libsodiumOK = crypto_secretbox_open_easy(messageStorage, cipherText, cipherLength, nonce, myPrivate);
	}

	if(libsodiumOK != 0)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	//now that the message has been successfully decrypted, take in on blind faith messageLength makes was ok
	//	up to the next function to make sure the decryption contents aren't truncated by a malicious messageLength
	output = std::make_unique<unsigned char[]>(messageLength);
//	unsigned char* message = new unsigned char[messageLength];
	memcpy(output.get(), messageStorage, messageLength);
//	output = std::unique_ptr<unsigned char>(message);
	outputLength = messageLength;
}

void SodiumUtils::disassembleInt(int input, unsigned char* output)
{
	input = htonl(input);
	memcpy(output, &input, sizeof(uint32_t));
}

int SodiumUtils::reassembleInt(unsigned char* input)
{
	int result = 0;
	memcpy(&result, input, sizeof(uint32_t));
	return ntohl(result);
}
<commit_msg>Remove commented out code<commit_after>/*
 * sodium_utils.cpp
 *
 *  Created on: Mar 30, 2018
 *      Author: Daniel
 */

#include "sodium_utils.hpp"

const std::string& SodiumUtils::SODIUM_PUBLIC_HEADER()
{
	const static std::string value = "SODIUM PUBLIC KEY\n";
	return value;
}

const std::string& SodiumUtils::SODIUM_PRIVATE_HEADER()
{
	const static std::string value = "SODIUM PRIVATE KEY\n";
	return value;
}

bool SodiumUtils::checkSodiumPrivate(const std::string& input)
{
	std::string privateHeader = SODIUM_PRIVATE_HEADER();
	bool hasHeader = (input.length() > 0 && input.substr(0, privateHeader.length()) == privateHeader);
	bool expectedLength = (input.length() == (privateHeader.length() + crypto_box_SECRETKEYBYTES*3));
	return hasHeader && expectedLength;
}

bool SodiumUtils::checkSodiumPublic(const std::string& input)
{
	std::string publicHeader = SODIUM_PUBLIC_HEADER();
	bool hasHeader = (input.length() > 0 && input.substr(0, publicHeader.length()) == publicHeader);
	bool expectedLength = (input.length() == (publicHeader.length() + crypto_box_PUBLICKEYBYTES*3));
	return hasHeader && expectedLength;
}

std::string SodiumUtils::randomString(int length)
{
	if(sodium_init() == -1)
	{
		exit(1); //any signs of sodium failure makes this program useless
	}

	int alphanumLength = 62;
	const std::string alphanum[] =
    {"0","1","2","3","4",
    "5","6","7","8","9",
    "A","B","C","D","E","F",
    "G","H","I","J","K",
    "L","M","N","O","P",
    "Q","R","S","T","U",
    "V","W","X","Y","Z",
    "a","b","c","d","e","f",
    "g","h","i","j","k",
    "l","m","n","o","p",
    "q","r","s","t","u",
    "v","w","x","y","z"
    };

	std::string randomized = "";
	for(int i=0; i<length; i++)
	{
		int index = randombytes_uniform(alphanumLength);
		std::string character = alphanum[index];
		randomized = randomized + character;
	}
	return randomized;
}

void SodiumUtils::sodiumEncrypt(bool asym, const unsigned char* input, int inputLength, const unsigned char* myPrivate, const unsigned char* yourPublic, std::unique_ptr<unsigned char[]>& output, int& outputLength)
{
	//setup nonce (like password salt)
	int nonceLength = 0;
	if(asym)
	{
		nonceLength = crypto_box_NONCEBYTES;
	}
	else
	{
		nonceLength = crypto_secretbox_NONCEBYTES;
	}
	unsigned char nonce[nonceLength] = {};
	randombytes_buf(nonce, nonceLength);

	//setup cipher text
	int cipherTextLength = 0, libsodiumOK = 0;
	unsigned char cipherText[2000] = {}; //guaranteed bigger than MTU of 1500
	if(asym)
	{
		cipherTextLength = crypto_box_MACBYTES + inputLength;
		libsodiumOK = crypto_box_easy(cipherText, input, inputLength, nonce, yourPublic, myPrivate);
	}
	else
	{
		cipherTextLength = crypto_secretbox_MACBYTES + inputLength;
		libsodiumOK = crypto_secretbox_easy(cipherText, input, inputLength, nonce, myPrivate); //myPrivate more like "ourPrivate" for symmetric
	}

	//encryption failed
	if(libsodiumOK != 0)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	unsigned char messageLengthDisassembled[sizeof(uint32_t)] = {};
	disassembleInt(inputLength, messageLengthDisassembled);

	//assemble the output
	const int finalSetupLength = crypto_box_NONCEBYTES+sizeof(uint32_t)+cipherTextLength;
	output = std::make_unique<unsigned char[]>(finalSetupLength);
	memset(output.get(), 0, finalSetupLength);
	memcpy(output.get(), nonce, crypto_box_NONCEBYTES);
	memcpy(output.get()+crypto_box_NONCEBYTES, messageLengthDisassembled, sizeof(uint32_t));
	memcpy(output.get()+crypto_box_NONCEBYTES+sizeof(uint32_t), cipherText, cipherTextLength);

	outputLength = finalSetupLength;
	//output[nonce|message length|encrypted]
}

void SodiumUtils::sodiumDecrypt(bool asym, const unsigned char* input, int inputLength, const unsigned char* myPrivate, const unsigned char* yourPublic, std::unique_ptr<unsigned char[]>& output, int& outputLength)
{
	//input[nonce|message length|encrypted]

	//extracts nonce (sorta like a salt)
	int nonceLength = 0;
	if(asym)
	{
		nonceLength = crypto_box_NONCEBYTES;
	}
	else
	{
		nonceLength = crypto_secretbox_NONCEBYTES;
	}
	if(nonceLength > inputLength)
	{
		//invalid encrypted bytes, doesn't have a nonce
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}
	unsigned char nonce[nonceLength] = {};
	memcpy(nonce, input, nonceLength);

	//get the message length (and figure out the cipher text length)
	if((nonceLength + sizeof(uint32_t)) > inputLength)
	{
		//invalid encrypted bytes, doesn't have a message length
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}
	unsigned char messageLengthDisassembled[sizeof(uint32_t)];
	memcpy(messageLengthDisassembled, input+crypto_box_NONCEBYTES, sizeof(uint32_t));
	const int messageLength = reassembleInt(messageLengthDisassembled);
	const int cipherLength = inputLength - crypto_box_NONCEBYTES - sizeof(uint32_t);

	//check to make sure the message length makes sense
	const bool messageCompressed = messageLength > cipherLength; //this isn't a compression function. not possible
	const bool messageMIA = messageLength < 1;
	if(messageCompressed || messageMIA)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	unsigned char cipherText[cipherLength] = {};
	memcpy(cipherText, input+crypto_box_NONCEBYTES+sizeof(uint32_t), cipherLength);
	//store the message in somewhere it is guaranteed to fit in case messageLength is bogus/malicious
	unsigned char messageStorage[cipherLength] = {};

	int libsodiumOK = 0;
	if(asym)
	{
		libsodiumOK = crypto_box_open_easy(messageStorage, cipherText, cipherLength, nonce, yourPublic, myPrivate);
	}
	else
	{
		libsodiumOK = crypto_secretbox_open_easy(messageStorage, cipherText, cipherLength, nonce, myPrivate);
	}

	if(libsodiumOK != 0)
	{
		output = std::unique_ptr<unsigned char[]>(); //pointer to nothing
		outputLength = 0;
		return;
	}

	//now that the message has been successfully decrypted, take in on blind faith messageLength makes was ok
	//	up to the next function to make sure the decryption contents aren't truncated by a malicious messageLength
	output = std::make_unique<unsigned char[]>(messageLength);
	memcpy(output.get(), messageStorage, messageLength);
	outputLength = messageLength;
}

void SodiumUtils::disassembleInt(int input, unsigned char* output)
{
	input = htonl(input);
	memcpy(output, &input, sizeof(uint32_t));
}

int SodiumUtils::reassembleInt(unsigned char* input)
{
	int result = 0;
	memcpy(&result, input, sizeof(uint32_t));
	return ntohl(result);
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "DWindow.h"
#include "DDebugManager.h"
#include "DWindowManager.h"

DWindowManager::DWindowManager()
	: CurrentWindow(nullptr)
{
}

DWindowManager::~DWindowManager()
{
	delete DF;
}

DWindow* DWindowManager::NewWindow(int Width, int Height, std::string Title)
{
	DWindow *Window = new DWindow(AllocWindowObject(Width, Height, Title));
	Window->DF->Engine = this->DF->Engine;
	Window->DF->WindowManager = this->DF->WindowManager;
	Window->DF->DebugManager = this->DF->DebugManager;
	Window->DF->Window = Window;

	this->Windows.push_back(Window);
	return Window;
}

GLFWwindow* DWindowManager::AllocWindowObject(int Width, int Height, std::string Title)
{
	GLFWwindow* Window = glfwCreateWindow(Width, Height, Title.c_str(), nullptr, nullptr);
	if (Window == nullptr){
		glfwTerminate();
		this->DF->DebugManager->Error(this, "Window Create Failed");
		return nullptr;
	}
	glfwSetInputMode(Window, GLFW_STICKY_KEYS, GL_TRUE);
	return Window;
}

void DWindowManager::DestroyWindow(DWindow* Window)
{
	this->Windows.erase(std::find(Windows.begin(), Windows.end(), Window));
}

void DWindowManager::DestroyWindowObject(GLFWwindow* Window)
{
	glfwDestroyWindow(Window);
}

void DWindowManager::Initialize()
{
	glfwWindowHint(GLFW_SAMPLES, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_VISIBLE, 0);
	glfwWindowHint(GLFW_RESIZABLE, 0);
}

void DWindowManager::MakeCurrent(DWindow* Window)
{
	glfwMakeContextCurrent(Window->GetWindow());
	CurrentWindow = Window;
}

void DWindowManager::Loop()
{
	PreLoop();
	Update();
	PostLoop();
}

void DWindowManager::PreLoop()
{
	for (auto &Window : Windows)
	{
		this->MakeCurrent(Window);
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	}
}

void DWindowManager::PostLoop()
{
	glfwTerminate();
}

void DWindowManager::Update()
{
	std::vector<GLFWwindow*> ShouldClose;

	do{
		for (auto &Window : Windows)
		{
			this->MakeCurrent(Window);

			glfwSwapBuffers(CurrentWindow->GetWindow());
			glfwPollEvents();
			if (glfwWindowShouldClose(CurrentWindow->GetWindow()))
			{
				ShouldClose.push_back(CurrentWindow->GetWindow());
			}
		}
		while (!ShouldClose.empty())
		{
			DestroyWindowObject(ShouldClose.back());
			ShouldClose.pop_back();
		}
	} while (this->HasWindowAvailable());

}

bool DWindowManager::HasWindowAvailable()
{
	return !Windows.empty();
}

<commit_msg>Fix Bug Closing A Window causes Runtime Error<commit_after>#include "stdafx.h"
#include "DWindow.h"
#include "DDebugManager.h"
#include "DWindowManager.h"

DWindowManager::DWindowManager()
	: CurrentWindow(nullptr)
{
}

DWindowManager::~DWindowManager()
{
	delete DF;
}

DWindow* DWindowManager::NewWindow(int Width, int Height, std::string Title)
{
	DWindow *Window = new DWindow(AllocWindowObject(Width, Height, Title));
	Window->DF->Engine = this->DF->Engine;
	Window->DF->WindowManager = this->DF->WindowManager;
	Window->DF->DebugManager = this->DF->DebugManager;
	Window->DF->Window = Window;

	this->Windows.push_back(Window);
	return Window;
}

GLFWwindow* DWindowManager::AllocWindowObject(int Width, int Height, std::string Title)
{
	GLFWwindow* Window = glfwCreateWindow(Width, Height, Title.c_str(), nullptr, nullptr);
	if (Window == nullptr){
		glfwTerminate();
		this->DF->DebugManager->Error(this, "Window Create Failed");
		return nullptr;
	}
	glfwSetInputMode(Window, GLFW_STICKY_KEYS, GL_TRUE);
	return Window;
}

void DWindowManager::DestroyWindow(DWindow* Window)
{
	this->Windows.erase(std::find(Windows.begin(), Windows.end(), Window));
	DestroyWindowObject(Window->GetWindow());
}

void DWindowManager::DestroyWindowObject(GLFWwindow* Window)
{
	glfwDestroyWindow(Window);
}

void DWindowManager::Initialize()
{
	glfwWindowHint(GLFW_SAMPLES, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//glfwWindowHint(GLFW_VISIBLE, 0);
	glfwWindowHint(GLFW_RESIZABLE, 0);
}

void DWindowManager::MakeCurrent(DWindow* Window)
{
	glfwMakeContextCurrent(Window->GetWindow());
	CurrentWindow = Window;
}

void DWindowManager::Loop()
{
	PreLoop();
	Update();
	PostLoop();
}

void DWindowManager::PreLoop()
{
	for (auto &Window : Windows)
	{
		this->MakeCurrent(Window);
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	}
}

void DWindowManager::PostLoop()
{
	glfwTerminate();
}

void DWindowManager::Update()
{
	std::vector<DWindow*> ShouldClose;

	do{
		for (auto &Window : Windows)
		{
			this->MakeCurrent(Window);

			glfwSwapBuffers(CurrentWindow->GetWindow());
			glfwPollEvents();
			if (glfwWindowShouldClose(CurrentWindow->GetWindow()))
			{
				ShouldClose.push_back(CurrentWindow);
			}
		}
		while (!ShouldClose.empty())
		{
			DestroyWindow(ShouldClose.back());
			ShouldClose.pop_back();
		}
	} while (this->HasWindowAvailable());

}

bool DWindowManager::HasWindowAvailable()
{
	return !Windows.empty();
}

<|endoftext|>


<commit_before><commit_msg>tdf#91426 - fix DX canvas - missed by VclPtr / Clang plugin.<commit_after><|endoftext|>