<commit_before>#include "filename/filename-parser.h"
#include <QChar>
#include <QList>
#include <QStack>
#include "filename/ast/filename-node-condition.h"
#include "filename/ast/filename-node-condition-ignore.h"
#include "filename/ast/filename-node-condition-invert.h"
#include "filename/ast/filename-node-condition-javascript.h"
#include "filename/ast/filename-node-condition-op.h"
#include "filename/ast/filename-node-condition-tag.h"
#include "filename/ast/filename-node-condition-token.h"
#include "filename/ast/filename-node-conditional.h"
#include "filename/ast/filename-node-javascript.h"
#include "filename/ast/filename-node-root.h"
#include "filename/ast/filename-node-text.h"
#include "filename/ast/filename-node-variable.h"

#define ESCAPE_CHARACTER '^'

FilenameParser::FilenameParser(QString str)
	: m_str(std::move(str)), m_index(0)
{}

const QString &FilenameParser::error() const
{
	return m_error;
}

FilenameNodeRoot *FilenameParser::parseRoot()
{
	try {
		return parseRootNode();
	} catch (const std::runtime_error &e) {
		m_error = e.what();
		return nullptr;
	}
}

FilenameNodeCondition *FilenameParser::parseCondition()
{
	try {
		return parseConditionNode();
	} catch (const std::runtime_error &e) {
		m_error = e.what();
		return nullptr;
	}
}

QChar FilenameParser::peek()
{
	return m_str[m_index];
}

bool FilenameParser::finished()
{
	return m_index >= m_str.count();
}

void FilenameParser::skipSpaces()
{
	while (peek().isSpace()) {
		m_index++;
	}
}

int FilenameParser::indexOf(const QList<QChar> &chars, int max)
{
	bool escapeNext = false;

	int limit = max < 0 ? m_str.count() : qMin(max, m_str.count());
	for (int index = m_index; index < limit; ++index) {
		QChar c = m_str[index];

		// Don't return on escaped characters
		bool isEscape = c == ESCAPE_CHARACTER || ((c == '<' || c == '>') && index < m_str.length() - 1 && c == m_str[index + 1]);
		if (isEscape && !escapeNext) {
			escapeNext = true;
		} else if (chars.contains(c) && !escapeNext) {
			return index;
		}

		// Clear escape character if unused
		if (!isEscape && escapeNext) {
			escapeNext = false;
		}
	}

	return -1;
}

QString FilenameParser::readUntil(const QList<QChar> &chars, bool allowEnd)
{
	QString ret;
	bool escapeNext = false;

	while (!finished()) {
		QChar c = m_str[m_index];

		// Don't return on escaped characters
		bool isEscape = c == ESCAPE_CHARACTER || ((c == '<' || c == '>') && m_index < m_str.length() - 1 && c == m_str[m_index + 1]);
		if (isEscape && !escapeNext) {
			escapeNext = true;
		} else {
			if (chars.contains(c) && !escapeNext) {
				return ret;
			}
			ret.append(c);
		}

		// Clear escape character if unused
		if (!isEscape && escapeNext) {
			escapeNext = false;
		}

		m_index++;
	}

	if (!allowEnd) {
		throw std::runtime_error("Unexpected EOF");
	}

	return ret;
}

FilenameNodeRoot *FilenameParser::parseRootNode()
{
	QList<FilenameNode*> exprs;

	while (!finished()) {
		exprs.append(parseExpr());
	}

	return new FilenameNodeRoot(exprs);
}

FilenameNode *FilenameParser::parseExpr(const QList<QChar> &addChars)
{
	if (m_str.mid(m_index, 11) == "javascript:") {
		return parseJavaScript();
	}

	QList<QChar> until = QList<QChar>{ '<', '%' } + addChars;
	QString txt = readUntil(until, true);
	if (txt.isEmpty()) {
		QChar p = peek();

		if (p == '<' && (m_index >= m_str.length() - 1 || m_str[m_index + 1] != '<')) {
			return parseConditional();
		}
		if (p == '%') {
			return parseVariable();
		}
	}

	return new FilenameNodeText(txt);
}

FilenameNodeJavaScript *FilenameParser::parseJavaScript()
{
	m_index += 11; // javascript:

	int start = m_index;
	m_index = m_str.length();

	return new FilenameNodeJavaScript(m_str.mid(start));
}

FilenameNodeVariable *FilenameParser::parseVariable()
{
	m_index++; // %

	QString name = readUntil({ ':', '%' });

	QMap<QString, QString> opts;
	while (peek() != '%') {
		m_index++; // : or ,

		QString opt = readUntil({ '=', ',', '%' });

		QString val;
		if (peek() == '=') {
			m_index++; // =
			val = readUntil({ ',', '%' });
		}

		opts.insert(opt, val);
	}

	m_index++; // %

	return new FilenameNodeVariable(name, opts);
}

FilenameNodeConditional *FilenameParser::parseConditional()
{
	m_index++; // <

	FilenameNodeCondition *condition = nullptr;
	FilenameNode *ifTrue = nullptr;
	FilenameNode *ifFalse = nullptr;

	// Legacy conditionals
	int endIndex = indexOf({ '>' });
	int sepIndex = indexOf({ '?' }, endIndex);
	if (sepIndex < 0) {
		QList<FilenameNode*> exprs;
		QList<FilenameNodeCondition*> conds;

		while (peek() != '>') {
			QList<QChar> stop { '>', '-', '!', '"', '%' };
			if (!stop.contains(peek())) {
				exprs.append(parseExpr(stop));
			}

			if (peek() != '>') {
				auto cond = parseSingleCondition(true);
				conds.append(cond);
				exprs.append(cond);
			}
		}

		if (conds.isEmpty()) {
			throw std::runtime_error("No condition found in conditional");
		}

		condition = conds.takeFirst();
		while (!conds.isEmpty()) {
			condition = new FilenameNodeConditionOp(FilenameNodeConditionOp::And, condition, conds.takeFirst());
		}

		ifTrue = exprs.count() == 1
			? exprs.first()
			: new FilenameNodeRoot(exprs);
	} else {
		condition = parseConditionNode();
		if (peek() != '?') {
			delete condition;
			throw std::runtime_error("Expected '?' after condition");
		}
		m_index++; // ?

		ifTrue = parseExpr({ ':', '>' });
		if (peek() == ':') {
			m_index++; // :
			ifFalse = parseExpr({ '>' });
		}

		if (peek() != '>') {
			delete condition;
			delete ifTrue;
			delete ifFalse;
			throw std::runtime_error("Expected '>' at the end of contional");
		}
	}

	m_index++; // >

	return new FilenameNodeConditional(condition, ifTrue, ifFalse);
}

FilenameNodeCondition *FilenameParser::parseConditionNode()
{
	if (m_str.mid(m_index, 11) == "javascript:") {
		return parseConditionJavaScript();
	}

	skipSpaces();

	FilenameNodeCondition *lhs;

	// Parenthesis
	QChar p = peek();
	if (p == '(') {
		m_index++; // (

		lhs = parseConditionNode();
		if (peek() != ')') {
			delete lhs;
			throw std::runtime_error("Expected ')' after condition in parenthesis");
		}

		m_index++; // )
	} else {
		lhs = parseSingleCondition();
	}

	QStack<QChar> opsStack;
	QStack<FilenameNodeCondition*> termStack;

	while (!finished()) {
		skipSpaces();

		QChar p = peek();
		QChar c = p == '"' || p == '%' ? '&' : p;
		if (c != '&' && c != '|') {
			break;
		}

		termStack.push(lhs);

		int prec = (c == '&' ? 2 : 1);

		while (!opsStack.isEmpty()) {
			QChar stackC = opsStack.top();
			int stackPrec = (stackC == '&' ? 2 : 1);

			if (prec > stackPrec) {
				break;
			}

			FilenameNodeCondition *operand2 = termStack.pop();
			FilenameNodeCondition *operand1 = termStack.pop();

			QChar opC = opsStack.pop();
			auto op = opC == '&' ? FilenameNodeConditionOp::And : FilenameNodeConditionOp::Or;
			auto expr = new FilenameNodeConditionOp(op, operand1, operand2);
			termStack.push(expr);
		}

		opsStack.push(c);

		if (p == c) {
			m_index++;
			skipSpaces();
		}

		termStack.push(parseSingleCondition());
	}

	while (!opsStack.isEmpty()) {
		FilenameNodeCondition *operand2 = termStack.pop();
		FilenameNodeCondition *operand1 = termStack.pop();

		QChar opC = opsStack.pop();
		auto op = opC == '&' ? FilenameNodeConditionOp::And : FilenameNodeConditionOp::Or;
		auto expr = new FilenameNodeConditionOp(op, operand1, operand2);
		termStack.push(expr);
	}

	auto term = lhs;

	if (!termStack.isEmpty()) {
		term = termStack.pop();
	}

	skipSpaces();

	return term;
}

FilenameNodeCondition *FilenameParser::parseSingleCondition(bool legacy)
{
	QChar c = peek();

	if (legacy && c == '-') {
		return parseConditionIgnore();
	}
	if (c == '!' || c == '-') {
		return parseConditionInvert();
	}
	if (c == '%') {
		return parseConditionToken();
	}
	if (c == '"') {
		return parseConditionTag();
	}

	if (!legacy) {
		return parseConditionTag(false);
	}

	throw std::runtime_error("Expected '!', '%' or '\"' for condition");
}

FilenameNodeConditionIgnore *FilenameParser::parseConditionIgnore()
{
	m_index++; // -

	auto cond = parseSingleCondition();

	return new FilenameNodeConditionIgnore(cond);
}

FilenameNodeConditionInvert *FilenameParser::parseConditionInvert()
{
	m_index++; // ! or -

	auto cond = parseSingleCondition();

	return new FilenameNodeConditionInvert(cond);
}

FilenameNodeConditionJavaScript *FilenameParser::parseConditionJavaScript()
{
	m_index += 11; // javascript:

	int start = m_index;
	m_index = m_str.length();

	return new FilenameNodeConditionJavaScript(m_str.mid(start));
}

FilenameNodeConditionTag *FilenameParser::parseConditionTag(bool quotes)
{
	if (quotes) {
		m_index++; // "
	}

	QString tag = quotes
		? readUntil({ '"' })
		: readUntil({ ' ', '&', '|', '?' }, true);

	if (quotes) {
		m_index++; // "
	}

	return new FilenameNodeConditionTag(Tag(tag));
}

FilenameNodeConditionToken *FilenameParser::parseConditionToken()
{
	m_index++; // %

	QString token = readUntil({ '%' });

	m_index++; // %

	return new FilenameNodeConditionToken(token);
}
<commit_msg>Stay in legacy mode when parsing conditional ignores<commit_after>#include "filename/filename-parser.h"
#include <QChar>
#include <QList>
#include <QStack>
#include "filename/ast/filename-node-condition.h"
#include "filename/ast/filename-node-condition-ignore.h"
#include "filename/ast/filename-node-condition-invert.h"
#include "filename/ast/filename-node-condition-javascript.h"
#include "filename/ast/filename-node-condition-op.h"
#include "filename/ast/filename-node-condition-tag.h"
#include "filename/ast/filename-node-condition-token.h"
#include "filename/ast/filename-node-conditional.h"
#include "filename/ast/filename-node-javascript.h"
#include "filename/ast/filename-node-root.h"
#include "filename/ast/filename-node-text.h"
#include "filename/ast/filename-node-variable.h"

#define ESCAPE_CHARACTER '^'

FilenameParser::FilenameParser(QString str)
	: m_str(std::move(str)), m_index(0)
{}

const QString &FilenameParser::error() const
{
	return m_error;
}

FilenameNodeRoot *FilenameParser::parseRoot()
{
	try {
		return parseRootNode();
	} catch (const std::runtime_error &e) {
		m_error = e.what();
		return nullptr;
	}
}

FilenameNodeCondition *FilenameParser::parseCondition()
{
	try {
		return parseConditionNode();
	} catch (const std::runtime_error &e) {
		m_error = e.what();
		return nullptr;
	}
}

QChar FilenameParser::peek()
{
	return m_str[m_index];
}

bool FilenameParser::finished()
{
	return m_index >= m_str.count();
}

void FilenameParser::skipSpaces()
{
	while (peek().isSpace()) {
		m_index++;
	}
}

int FilenameParser::indexOf(const QList<QChar> &chars, int max)
{
	bool escapeNext = false;

	int limit = max < 0 ? m_str.count() : qMin(max, m_str.count());
	for (int index = m_index; index < limit; ++index) {
		QChar c = m_str[index];

		// Don't return on escaped characters
		bool isEscape = c == ESCAPE_CHARACTER || ((c == '<' || c == '>') && index < m_str.length() - 1 && c == m_str[index + 1]);
		if (isEscape && !escapeNext) {
			escapeNext = true;
		} else if (chars.contains(c) && !escapeNext) {
			return index;
		}

		// Clear escape character if unused
		if (!isEscape && escapeNext) {
			escapeNext = false;
		}
	}

	return -1;
}

QString FilenameParser::readUntil(const QList<QChar> &chars, bool allowEnd)
{
	QString ret;
	bool escapeNext = false;

	while (!finished()) {
		QChar c = m_str[m_index];

		// Don't return on escaped characters
		bool isEscape = c == ESCAPE_CHARACTER || ((c == '<' || c == '>') && m_index < m_str.length() - 1 && c == m_str[m_index + 1]);
		if (isEscape && !escapeNext) {
			escapeNext = true;
		} else {
			if (chars.contains(c) && !escapeNext) {
				return ret;
			}
			ret.append(c);
		}

		// Clear escape character if unused
		if (!isEscape && escapeNext) {
			escapeNext = false;
		}

		m_index++;
	}

	if (!allowEnd) {
		throw std::runtime_error("Unexpected EOF");
	}

	return ret;
}

FilenameNodeRoot *FilenameParser::parseRootNode()
{
	QList<FilenameNode*> exprs;

	while (!finished()) {
		exprs.append(parseExpr());
	}

	return new FilenameNodeRoot(exprs);
}

FilenameNode *FilenameParser::parseExpr(const QList<QChar> &addChars)
{
	if (m_str.mid(m_index, 11) == "javascript:") {
		return parseJavaScript();
	}

	QList<QChar> until = QList<QChar>{ '<', '%' } + addChars;
	QString txt = readUntil(until, true);
	if (txt.isEmpty()) {
		QChar p = peek();

		if (p == '<' && (m_index >= m_str.length() - 1 || m_str[m_index + 1] != '<')) {
			return parseConditional();
		}
		if (p == '%') {
			return parseVariable();
		}
	}

	return new FilenameNodeText(txt);
}

FilenameNodeJavaScript *FilenameParser::parseJavaScript()
{
	m_index += 11; // javascript:

	int start = m_index;
	m_index = m_str.length();

	return new FilenameNodeJavaScript(m_str.mid(start));
}

FilenameNodeVariable *FilenameParser::parseVariable()
{
	m_index++; // %

	QString name = readUntil({ ':', '%' });

	QMap<QString, QString> opts;
	while (peek() != '%') {
		m_index++; // : or ,

		QString opt = readUntil({ '=', ',', '%' });

		QString val;
		if (peek() == '=') {
			m_index++; // =
			val = readUntil({ ',', '%' });
		}

		opts.insert(opt, val);
	}

	m_index++; // %

	return new FilenameNodeVariable(name, opts);
}

FilenameNodeConditional *FilenameParser::parseConditional()
{
	m_index++; // <

	FilenameNodeCondition *condition = nullptr;
	FilenameNode *ifTrue = nullptr;
	FilenameNode *ifFalse = nullptr;

	// Legacy conditionals
	int endIndex = indexOf({ '>' });
	int sepIndex = indexOf({ '?' }, endIndex);
	if (sepIndex < 0) {
		QList<FilenameNode*> exprs;
		QList<FilenameNodeCondition*> conds;

		while (peek() != '>') {
			QList<QChar> stop { '>', '-', '!', '"', '%' };
			if (!stop.contains(peek())) {
				exprs.append(parseExpr(stop));
			}

			if (peek() != '>') {
				auto cond = parseSingleCondition(true);
				conds.append(cond);
				exprs.append(cond);
			}
		}

		if (conds.isEmpty()) {
			throw std::runtime_error("No condition found in conditional");
		}

		condition = conds.takeFirst();
		while (!conds.isEmpty()) {
			condition = new FilenameNodeConditionOp(FilenameNodeConditionOp::And, condition, conds.takeFirst());
		}

		ifTrue = exprs.count() == 1
			? exprs.first()
			: new FilenameNodeRoot(exprs);
	} else {
		condition = parseConditionNode();
		if (peek() != '?') {
			delete condition;
			throw std::runtime_error("Expected '?' after condition");
		}
		m_index++; // ?

		ifTrue = parseExpr({ ':', '>' });
		if (peek() == ':') {
			m_index++; // :
			ifFalse = parseExpr({ '>' });
		}

		if (peek() != '>') {
			delete condition;
			delete ifTrue;
			delete ifFalse;
			throw std::runtime_error("Expected '>' at the end of contional");
		}
	}

	m_index++; // >

	return new FilenameNodeConditional(condition, ifTrue, ifFalse);
}

FilenameNodeCondition *FilenameParser::parseConditionNode()
{
	if (m_str.mid(m_index, 11) == "javascript:") {
		return parseConditionJavaScript();
	}

	skipSpaces();

	FilenameNodeCondition *lhs;

	// Parenthesis
	QChar p = peek();
	if (p == '(') {
		m_index++; // (

		lhs = parseConditionNode();
		if (peek() != ')') {
			delete lhs;
			throw std::runtime_error("Expected ')' after condition in parenthesis");
		}

		m_index++; // )
	} else {
		lhs = parseSingleCondition();
	}

	QStack<QChar> opsStack;
	QStack<FilenameNodeCondition*> termStack;

	while (!finished()) {
		skipSpaces();

		QChar p = peek();
		QChar c = p == '"' || p == '%' ? '&' : p;
		if (c != '&' && c != '|') {
			break;
		}

		termStack.push(lhs);

		int prec = (c == '&' ? 2 : 1);

		while (!opsStack.isEmpty()) {
			QChar stackC = opsStack.top();
			int stackPrec = (stackC == '&' ? 2 : 1);

			if (prec > stackPrec) {
				break;
			}

			FilenameNodeCondition *operand2 = termStack.pop();
			FilenameNodeCondition *operand1 = termStack.pop();

			QChar opC = opsStack.pop();
			auto op = opC == '&' ? FilenameNodeConditionOp::And : FilenameNodeConditionOp::Or;
			auto expr = new FilenameNodeConditionOp(op, operand1, operand2);
			termStack.push(expr);
		}

		opsStack.push(c);

		if (p == c) {
			m_index++;
			skipSpaces();
		}

		termStack.push(parseSingleCondition());
	}

	while (!opsStack.isEmpty()) {
		FilenameNodeCondition *operand2 = termStack.pop();
		FilenameNodeCondition *operand1 = termStack.pop();

		QChar opC = opsStack.pop();
		auto op = opC == '&' ? FilenameNodeConditionOp::And : FilenameNodeConditionOp::Or;
		auto expr = new FilenameNodeConditionOp(op, operand1, operand2);
		termStack.push(expr);
	}

	auto term = lhs;

	if (!termStack.isEmpty()) {
		term = termStack.pop();
	}

	skipSpaces();

	return term;
}

FilenameNodeCondition *FilenameParser::parseSingleCondition(bool legacy)
{
	QChar c = peek();

	if (legacy && c == '-') {
		return parseConditionIgnore();
	}
	if (c == '!' || c == '-') {
		return parseConditionInvert();
	}
	if (c == '%') {
		return parseConditionToken();
	}
	if (c == '"') {
		return parseConditionTag();
	}

	if (!legacy) {
		return parseConditionTag(false);
	}

	throw std::runtime_error("Expected '!', '%' or '\"' for condition");
}

FilenameNodeConditionIgnore *FilenameParser::parseConditionIgnore()
{
	m_index++; // -

	auto cond = parseSingleCondition(true);

	return new FilenameNodeConditionIgnore(cond);
}

FilenameNodeConditionInvert *FilenameParser::parseConditionInvert()
{
	m_index++; // ! or -

	auto cond = parseSingleCondition();

	return new FilenameNodeConditionInvert(cond);
}

FilenameNodeConditionJavaScript *FilenameParser::parseConditionJavaScript()
{
	m_index += 11; // javascript:

	int start = m_index;
	m_index = m_str.length();

	return new FilenameNodeConditionJavaScript(m_str.mid(start));
}

FilenameNodeConditionTag *FilenameParser::parseConditionTag(bool quotes)
{
	if (quotes) {
		m_index++; // "
	}

	QString tag = quotes
		? readUntil({ '"' })
		: readUntil({ ' ', '&', '|', '?' }, true);

	if (quotes) {
		m_index++; // "
	}

	return new FilenameNodeConditionTag(Tag(tag));
}

FilenameNodeConditionToken *FilenameParser::parseConditionToken()
{
	m_index++; // %

	QString token = readUntil({ '%' });

	m_index++; // %

	return new FilenameNodeConditionToken(token);
}
<|endoftext|>


<commit_before><commit_msg>This should hopefully fix the problem with disappearing dimap folders (backport revision 1.313)<commit_after><|endoftext|>


<commit_before>/*******************************************************************************
*
* MIT License
*
* Copyright (c) 2017 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef GUARD_MIOPEN_DB_HPP_
#define GUARD_MIOPEN_DB_HPP_

#include <string>
#include <ios>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/optional.hpp>

#include <miopen/db_record.hpp>
#include <miopen/lock_file.hpp>

namespace miopen {
/// No instance of this class should be used from several threads at the same time.
class Db
{
    public:
    inline Db(const std::string& filename_)
        : filename(filename_), lock_file(LockFileDispatcher::Get((filename_ + ".lock").c_str()))
    {
    }

    /// Searches db for provided key and returns found record or none if key not found in database
    inline boost::optional<DbRecord> FindRecord(const std::string& key)
    {
        shared_lock lock(lock_file);
        return FindRecordUnsafe(key, nullptr);
    }

    template <class T>
    inline boost::optional<DbRecord> FindRecord(const T& problem_config)
    {
        shared_lock lock(lock_file);
        return FindRecordUnsafe(problem_config);
    }

    /// Stores provided record in database. If record with same key is already in database it is
    /// replaced by provided record.
    ///
    /// Returns true if store was successful, false otherwise.
    inline bool StoreRecord(const DbRecord& record)
    {
        exclusive_lock lock(lock_file);
        return StoreRecordUnsafe(record);
    }

    /// Stores provided record in database. If record with same key is already in database it is
    /// updated with values from provided record. Provided records data is also updated via
    /// DbRecord::Merge().
    ///
    /// Returns true if update was successful, false otherwise.
    inline bool UpdateRecord(DbRecord& record)
    {
        exclusive_lock lock(lock_file);
        return UpdateRecordUnsafe(record);
    }

    /// Removes record with provided key from db
    ///
    /// Returns true if remove was successful, false otherwise.
    inline bool RemoveRecord(const std::string& key)
    {
        exclusive_lock lock(lock_file);
        return RemoveRecordUnsafe(key);
    }

    template <class T>
    inline bool RemoveRecord(const T& problem_config)
    {
        auto key = DbRecord::Serialize(problem_config);
        return RemoveRecord(key);
    }

    /// Updates record under key PROBLEM_CONFIG with data ID:VALUES in database.
    /// Both T and V classes should have "void Serialize(std::ostream&) const" member function
    /// available.
    ///
    /// Returns updated record or none if update was unsuccessful.
    template <class T, class V>
    inline boost::optional<DbRecord>
    Update(const T& problem_config, const std::string& id, const V& values)
    {
        DbRecord record(problem_config);
        record.SetValues(id, values);
        bool ok = UpdateRecord(record);
        if(ok)
            return record;
        else
            return boost::none;
    }

    /// Searches for record with key PROBLEM_CONFIG and gets VALUES under the ID from it.
    /// Class T should have "void Serialize(std::ostream&) const" member function available.
    /// Class V shall have "bool Deserialize(const std::string& str)" member function available.
    ///
    /// Returns false if there is none PROBLEM_CONFIG=ID:VALUES in the database
    /// or in case of any error, e.g. if VALUES cannot be deserialized due to incorrect format.
    template <class T, class V>
    inline bool Load(const T& problem_config, const std::string& id, V& values)
    {
        auto record = FindRecord(problem_config);

        if(!record)
            return false;
        return record->GetValues(id, values);
    }

    /// Removes ID with associated VALUES from record with key PROBLEM_CONFIG from db.
    /// If payload of a record becomes empty after that, also removes the entire record
    ///
    /// Returns true if remove was successful. Returns false if this PROBLEM_CONFIG or ID was not
    /// found.
    template <class T>
    inline bool Remove(const T& problem_config, const std::string& id)
    {
        exclusive_lock lock(lock_file);
        auto record = FindRecordUnsafe(problem_config);
        if(!record)
            return false;
        bool erased = record->EraseValues(id);
        if(!erased)
            return false;
        return StoreRecordUnsafe(*record);
    }

    private:
    struct RecordPositions
    {
        std::streamoff begin = -1;
        std::streamoff end   = -1;
    };

    using exclusive_lock = boost::interprocess::scoped_lock<LockFile>;
    using shared_lock    = boost::interprocess::sharable_lock<LockFile>;

    std::string filename;
    LockFile lock_file;

    boost::optional<DbRecord> FindRecordUnsafe(const std::string& key, RecordPositions* pos);
    bool FlushUnsafe(const DbRecord& record, const RecordPositions* pos);
    bool StoreRecordUnsafe(const DbRecord& record);
    bool UpdateRecordUnsafe(DbRecord& record);
    bool RemoveRecordUnsafe(const std::string& key);

    template <class T>
    inline boost::optional<DbRecord> FindRecordUnsafe(const T& problem_config)
    {
        std::string key = DbRecord::Serialize(problem_config);
        return FindRecordUnsafe(key, nullptr);
    }
};

class MultiFileDb
{
public:
    MultiFileDb(const std::string& installed_path, const std::string& user_path)
        : _installed(installed_path)
        , _user(user_path)
    {}

    boost::optional<DbRecord> FindRecord(const std::string& key)
    {
        auto users = _user.FindRecord(key);

        if (users)
            return users;

        return _installed.FindRecord(key);
    }

    template <class T>
    boost::optional<DbRecord> FindRecord(const T& problem_config)
    {
        auto users = _user.FindRecord(problem_config);

        if (users)
            return users;

        return _installed.FindRecord(problem_config);
    }

    bool StoreRecord(const DbRecord& record) { return _user.StoreRecord(record); }

    bool UpdateRecord(DbRecord& record) { return _user.UpdateRecord(record); }

    bool RemoveRecord(const std::string& key) { return _user.RemoveRecord(key); }

    template <class T>
    bool RemoveRecord(const T& problem_config) { return _user.RemoveRecord(problem_config); }

    template <class T, class V>
    boost::optional<DbRecord>
        Update(const T& problem_config, const std::string& id, const V& values) { return _user.Update(problem_config, id, values); }

    template <class T, class V>
    bool Load(const T& problem_config, const std::string& id, V& values)
    {
        if (_user.Load(problem_config, id, values))
            return true;

        return _installed.Load(problem_config, id, values);
    }

    template <class T>
    bool Remove(const T& problem_config, const std::string& id) { return _user.Remove(problem_config, id); }

private:
    Db _installed, _user;
};
} // namespace miopen

#endif // GUARD_MIOPEN_DB_HPP_
<commit_msg>Fixed minor bug.<commit_after>/*******************************************************************************
*
* MIT License
*
* Copyright (c) 2017 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef GUARD_MIOPEN_DB_HPP_
#define GUARD_MIOPEN_DB_HPP_

#include <string>
#include <ios>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/optional.hpp>

#include <miopen/db_record.hpp>
#include <miopen/lock_file.hpp>

namespace miopen {
/// No instance of this class should be used from several threads at the same time.
class Db
{
    public:
    inline Db(const std::string& filename_)
        : filename(filename_), lock_file(LockFileDispatcher::Get((filename_ + ".lock").c_str()))
    {
    }

    /// Searches db for provided key and returns found record or none if key not found in database
    inline boost::optional<DbRecord> FindRecord(const std::string& key)
    {
        shared_lock lock(lock_file);
        return FindRecordUnsafe(key, nullptr);
    }

    template <class T>
    inline boost::optional<DbRecord> FindRecord(const T& problem_config)
    {
        shared_lock lock(lock_file);
        return FindRecordUnsafe(problem_config);
    }

    /// Stores provided record in database. If record with same key is already in database it is
    /// replaced by provided record.
    ///
    /// Returns true if store was successful, false otherwise.
    inline bool StoreRecord(const DbRecord& record)
    {
        exclusive_lock lock(lock_file);
        return StoreRecordUnsafe(record);
    }

    /// Stores provided record in database. If record with same key is already in database it is
    /// updated with values from provided record. Provided records data is also updated via
    /// DbRecord::Merge().
    ///
    /// Returns true if update was successful, false otherwise.
    inline bool UpdateRecord(DbRecord& record)
    {
        exclusive_lock lock(lock_file);
        return UpdateRecordUnsafe(record);
    }

    /// Removes record with provided key from db
    ///
    /// Returns true if remove was successful, false otherwise.
    inline bool RemoveRecord(const std::string& key)
    {
        exclusive_lock lock(lock_file);
        return RemoveRecordUnsafe(key);
    }

    template <class T>
    inline bool RemoveRecord(const T& problem_config)
    {
        auto key = DbRecord::Serialize(problem_config);
        return RemoveRecord(key);
    }

    /// Updates record under key PROBLEM_CONFIG with data ID:VALUES in database.
    /// Both T and V classes should have "void Serialize(std::ostream&) const" member function
    /// available.
    ///
    /// Returns updated record or none if update was unsuccessful.
    template <class T, class V>
    inline boost::optional<DbRecord>
    Update(const T& problem_config, const std::string& id, const V& values)
    {
        DbRecord record(problem_config);
        record.SetValues(id, values);
        bool ok = UpdateRecord(record);
        if(ok)
            return record;
        else
            return boost::none;
    }

    /// Searches for record with key PROBLEM_CONFIG and gets VALUES under the ID from it.
    /// Class T should have "void Serialize(std::ostream&) const" member function available.
    /// Class V shall have "bool Deserialize(const std::string& str)" member function available.
    ///
    /// Returns false if there is none PROBLEM_CONFIG=ID:VALUES in the database
    /// or in case of any error, e.g. if VALUES cannot be deserialized due to incorrect format.
    template <class T, class V>
    inline bool Load(const T& problem_config, const std::string& id, V& values)
    {
        auto record = FindRecord(problem_config);

        if(!record)
            return false;
        return record->GetValues(id, values);
    }

    /// Removes ID with associated VALUES from record with key PROBLEM_CONFIG from db.
    /// If payload of a record becomes empty after that, also removes the entire record
    ///
    /// Returns true if remove was successful. Returns false if this PROBLEM_CONFIG or ID was not
    /// found.
    template <class T>
    inline bool Remove(const T& problem_config, const std::string& id)
    {
        exclusive_lock lock(lock_file);
        auto record = FindRecordUnsafe(problem_config);
        if(!record)
            return false;
        bool erased = record->EraseValues(id);
        if(!erased)
            return false;
        return StoreRecordUnsafe(*record);
    }

    private:
    struct RecordPositions
    {
        std::streamoff begin = -1;
        std::streamoff end   = -1;
    };

    using exclusive_lock = boost::interprocess::scoped_lock<LockFile>;
    using shared_lock    = boost::interprocess::sharable_lock<LockFile>;

    std::string filename;
    LockFile lock_file;

    boost::optional<DbRecord> FindRecordUnsafe(const std::string& key, RecordPositions* pos);
    bool FlushUnsafe(const DbRecord& record, const RecordPositions* pos);
    bool StoreRecordUnsafe(const DbRecord& record);
    bool UpdateRecordUnsafe(DbRecord& record);
    bool RemoveRecordUnsafe(const std::string& key);

    template <class T>
    inline boost::optional<DbRecord> FindRecordUnsafe(const T& problem_config)
    {
        std::string key = DbRecord::Serialize(problem_config);
        return FindRecordUnsafe(key, nullptr);
    }
};

class MultiFileDb
{
public:
    MultiFileDb(const std::string& installed_path, const std::string& user_path)
        : _installed(installed_path)
        , _user(user_path)
    {}

    boost::optional<DbRecord> FindRecord(const std::string& key)
    {
        auto users = _user.FindRecord(key);
        auto installed = _installed.FindRecord(key);

        if (users && installed)
        {
            users->Merge(installed);
            return users;
        }

        if (users)
            return users;

        return installed;
    }

    template <class T>
    boost::optional<DbRecord> FindRecord(const T& problem_config)
    {
        auto users = _user.FindRecord(problem_config);
        auto installed = _installed.FindRecord(problem_config);

        if (users && installed)
        {
            users->Merge(installed);
            return users;
        }

        if (users)
            return users;

        return installed;
    }

    bool StoreRecord(const DbRecord& record) { return _user.StoreRecord(record); }

    bool UpdateRecord(DbRecord& record) { return _user.UpdateRecord(record); }

    bool RemoveRecord(const std::string& key) { return _user.RemoveRecord(key); }

    template <class T>
    bool RemoveRecord(const T& problem_config) { return _user.RemoveRecord(problem_config); }

    template <class T, class V>
    boost::optional<DbRecord>
        Update(const T& problem_config, const std::string& id, const V& values) { return _user.Update(problem_config, id, values); }

    template <class T, class V>
    bool Load(const T& problem_config, const std::string& id, V& values)
    {
        if (_user.Load(problem_config, id, values))
            return true;

        return _installed.Load(problem_config, id, values);
    }

    template <class T>
    bool Remove(const T& problem_config, const std::string& id) { return _user.Remove(problem_config, id); }

private:
    Db _installed, _user;
};
} // namespace miopen

#endif // GUARD_MIOPEN_DB_HPP_
<|endoftext|>


<commit_before>
#include "ImwPlatformWindow.h"

#include "ImwWindowManager.h"

namespace ImWindow
{
//SFF_BEGIN
	ImwPlatformWindow::ImwPlatformWindow(EPlatformWindowType eType, bool bCreateContext)
	{
		m_eType = eType;
		m_pContainer = new ImwContainer(this);
		m_pContext = NULL;
		m_pPreviousContext = NULL;
		m_bNeedRender = false;
		m_bShowContent = true;

		if ( bCreateContext )
		{
			ImGuiContext* pGlobalContext = ImGui::GetCurrentContext();
			IM_ASSERT(pGlobalContext != NULL);

			m_pContext = ImGui::CreateContext( pGlobalContext->IO.MemAllocFn, pGlobalContext->IO.MemFreeFn );

			ImGuiIO& oGlobalIO = pGlobalContext->IO;
			ImGuiIO& oNewIO = m_pContext->IO;

			memcpy(&(oNewIO.KeyMap), &(oGlobalIO.KeyMap ), sizeof( pGlobalContext->IO.KeyMap ));
			oNewIO.RenderDrawListsFn = NULL;
			oNewIO.GetClipboardTextFn = oGlobalIO.GetClipboardTextFn;
			oNewIO.SetClipboardTextFn = oGlobalIO.SetClipboardTextFn;
			oNewIO.ImeSetInputScreenPosFn = oGlobalIO.ImeSetInputScreenPosFn;
			oNewIO.IniFilename = NULL;
		}
	}

	ImwPlatformWindow::~ImwPlatformWindow()
	{
		ImwSafeDelete(m_pContainer);

		if (m_pContext != NULL)
		{
			m_pContext->IO.Fonts = NULL;
			SetContext(false);
			ImGui::Shutdown();
			RestoreContext(false);
			ImGui::DestroyContext(m_pContext);
			m_pContext = NULL;
		}
	}

	bool ImwPlatformWindow::Init(ImwPlatformWindow* /*pParent*/)
	{
		return true;
	}

	EPlatformWindowType ImwPlatformWindow::GetType() const
	{
		return m_eType;
	}

	bool ImwPlatformWindow::IsMainWindow() const
	{
		return m_eType == E_PLATFORM_WINDOW_TYPE_MAIN;
	}

	const ImVec2 c_oVec2_0 = ImVec2(0,0);
	ImVec2 ImwPlatformWindow::GetPosition() const
	{
		return c_oVec2_0;
	}

	ImVec2 ImwPlatformWindow::GetSize() const
	{
		return ImGui::GetIO().DisplaySize;
	}

	ImVec2 ImwPlatformWindow::GetNormalPosition() const
	{
		return GetPosition();
	}

	ImVec2 ImwPlatformWindow::GetNormalSize() const
	{
		return GetSize();
	}

	bool ImwPlatformWindow::IsWindowMaximized() const
	{
		return false;
	}

	bool ImwPlatformWindow::IsWindowMinimized() const
	{
		return false;
	}

	void ImwPlatformWindow::Show(bool /*bShow*/)
	{
	}

	void ImwPlatformWindow::SetSize(int /*iWidth*/, int /*iHeight*/)
	{
	}

	void ImwPlatformWindow::SetPosition(int /*iX*/, int /*iY*/)
	{
	}

	void ImwPlatformWindow::SetWindowMaximized(bool /*bMaximized*/)
	{
	}

	void  ImwPlatformWindow::SetWindowMinimized()
	{
	}

	void ImwPlatformWindow::SetTitle(const char* /*pTtile*/)
	{
	}

	bool ImwPlatformWindow::IsShowContent() const
	{
		return m_bShowContent;
	}

	void ImwPlatformWindow::SetShowContent(bool bShow)
	{
		m_bShowContent = bShow;
	}

	void ImwPlatformWindow::PreUpdate()
	{
	}

	void ImwPlatformWindow::PreRender()
	{
	}

	void ImwPlatformWindow::OnOverlay()
	{
	}

	void ImwPlatformWindow::RenderDrawLists(ImDrawData* /*pDrawData */)
	{
	}

	void ImwPlatformWindow::Render()
	{
		if( m_bNeedRender )
		{
			m_bNeedRender = false;
			SetContext(false);
			ImGui::GetIO().DisplaySize = GetSize();
			PreRender();
			ImGui::Render();
			RenderDrawLists(ImGui::GetDrawData());
			RestoreContext(false);
		}
	}

	void ImwPlatformWindow::PaintContainer()
	{
		m_pContainer->Paint();
	}

	void ImwPlatformWindow::OnClose()
	{
		ImwWindowManager::GetInstance()->OnClosePlatformWindow(this);
	}

	void ImwPlatformWindow::OnDropFiles(int iCount, char** pFiles, const ImVec2& oPos)
	{
		ImwWindow* pWindow = GetWindowAtPos(oPos);
		IM_ASSERT(pWindow != NULL);
		if (pWindow != NULL)
		{
			pWindow->OnDropFiles(iCount, pFiles, oPos);
		}
	}

	bool ImwPlatformWindow::Save(JsonValue& oJson)
	{
		ImVec2 oSize = GetNormalSize();
		ImVec2 oPos = GetNormalPosition();

		oJson["Width"] = (long)oSize.x;
		oJson["Height"] = (long)oSize.y;
		oJson["Left"] = (long)oPos.x;
		oJson["Top"] = (long)oPos.y;
		oJson["Mode"] = (long)(IsWindowMaximized() ? 1 : (IsWindowMinimized() ? -1 : 0));

		return m_pContainer->Save(oJson["Container"]);
	}

	bool ImwPlatformWindow::Load(const JsonValue& oJson, bool bJustCheck)
	{
		if (!oJson["Width"].IsNumeric() || !oJson["Height"].IsNumeric() || !oJson["Left"].IsNumeric() || !oJson["Top"].IsNumeric() || (!oJson["Mode"].IsNumeric() && !oJson["Maximized"].IsBoolean()))
			return false;

		if (!bJustCheck)
		{
			SetSize((long)oJson["Width"], (long)oJson["Height"]);
			SetPosition((long)oJson["Left"], (long)oJson["Top"]);

			if (oJson["Mode"].IsNumeric())
			{
				long iMode = (long)oJson["Mode"];
				if (iMode < 0)
				{
					SetWindowMinimized();
				}
				else
				{
					SetWindowMaximized(iMode > 0);
				}
			}
			else if (oJson["Maximized"].IsBoolean())
			{
				SetWindowMaximized(oJson["Maximized"]);
			}
		}

		return m_pContainer->Load(oJson["Container"], bJustCheck);
	}

	static bool s_bContextPushed = false;

	bool ImwPlatformWindow::IsContextSet()
	{
		return s_bContextPushed;
	}

	bool ImwPlatformWindow::HasContext() const
	{
		return m_pContext != NULL;
	}

	ImGuiContext* ImwPlatformWindow::GetContext()
	{
		return m_pContext;
	}

	void ImwPlatformWindow::SetContext(bool bCopyStyle)
	{
		IM_ASSERT(s_bContextPushed == false);
		s_bContextPushed = true;
		if (m_pContext != NULL)
		{
			IM_ASSERT( m_pPreviousContext == NULL );
			m_pPreviousContext = ImGui::GetCurrentContext();
			ImGui::SetCurrentContext(m_pContext);
			if (bCopyStyle)
			{
				//Copy style from Global context
				memcpy(&(m_pContext->Style), &(m_pPreviousContext->Style), sizeof(ImGuiStyle));
			}
		}
	}

	void ImwPlatformWindow::RestoreContext(bool bCopyStyle)
	{
		IM_ASSERT(s_bContextPushed == true);
		s_bContextPushed = false;
		if (m_pContext != NULL)
		{
			IM_ASSERT(m_pPreviousContext != NULL);
			if (bCopyStyle)
			{
				//Copy style to Global context
				memcpy(&(m_pPreviousContext->Style), &(m_pContext->Style), sizeof(ImGuiStyle));
			}
			ImGui::SetCurrentContext(m_pPreviousContext);
			m_pPreviousContext = NULL;
		}
	}

	void ImwPlatformWindow::OnLoseFocus()
	{
		if (NULL != m_pContext)
		{
			m_pContext->SetNextWindowPosCond = m_pContext->SetNextWindowSizeCond = m_pContext->SetNextWindowContentSizeCond = m_pContext->SetNextWindowCollapsedCond = m_pContext->SetNextWindowFocus = 0;
			m_pContext->ActiveId = 0;

			for (int i = 0; i < 512; ++i)
				m_pContext->IO.KeysDown[i] = false;

			for (int i = 0; i < 5; ++i)
				m_pContext->IO.MouseDown[i] = false;

			m_pContext->IO.KeyAlt = false;
			m_pContext->IO.KeyCtrl = false;
			m_pContext->IO.KeyShift = false;
		}
	}

	void ImwPlatformWindow::Dock(ImwWindow* pWindow)
	{
		m_pContainer->Dock(pWindow);
	}

	bool ImwPlatformWindow::UnDock(ImwWindow* pWindow)
	{
		return m_pContainer->UnDock(pWindow);
	}

	ImwContainer* ImwPlatformWindow::GetContainer()
	{
		return m_pContainer;
	}

	ImwWindow* ImwPlatformWindow::GetWindowAtPos(const ImVec2& oPos) const
	{
		return m_pContainer->GetWindowAtPos(oPos);
	}

	const ImwContainer* ImwPlatformWindow::HasWindow(ImwWindow* pWindow)
	{
		return m_pContainer->HasWindow(pWindow);
	}

	bool ImwPlatformWindow::FocusWindow(ImwWindow* pWindow)
	{
		return m_pContainer->FocusWindow(pWindow);
	}

	void ImwPlatformWindow::RefreshTitle()
	{
		const ImwChar* pMainTitle = ImwWindowManager::GetInstance()->GetMainTitle();

		ImwWindow* pActiveWindow = m_pContainer->GetActiveWindow();
		const ImwChar* pActiveWindowTitle = NULL;

		if (pActiveWindow != NULL)
		{
			pActiveWindowTitle = pActiveWindow->GetTitle();
		}

		const size_t c_iMaxTitleLen = 512;
		ImwChar pTitle[c_iMaxTitleLen + 1];
		size_t iCurrentIndex = 0;

		if (pMainTitle != NULL)
		{
			size_t iLen = strlen(pMainTitle);
			if (iLen > (c_iMaxTitleLen - iCurrentIndex))
				iLen = c_iMaxTitleLen - iCurrentIndex;
			if (iLen > 0)
			{
				memcpy(pTitle + iCurrentIndex, pMainTitle, iLen);
				iCurrentIndex += iLen;
			}
		}

		if (pActiveWindowTitle != NULL)
		{
			if (iCurrentIndex != 0)
			{
				const char* const c_pSeparator = " - ";
				size_t iLen = strlen(c_pSeparator);
				if (iLen > (c_iMaxTitleLen - iCurrentIndex))
					iLen = c_iMaxTitleLen - iCurrentIndex;
				if (iLen > 0)
				{
					memcpy(pTitle + iCurrentIndex, c_pSeparator, iLen);
					iCurrentIndex += iLen;
				}
			}

			size_t iLen = strlen(pActiveWindowTitle);
			if (iLen > (c_iMaxTitleLen - iCurrentIndex))
				iLen = c_iMaxTitleLen - iCurrentIndex;
			if (iLen > 0)
			{
				memcpy(pTitle + iCurrentIndex, pActiveWindowTitle, iLen);
				iCurrentIndex += iLen;
			}
		}

		pTitle[iCurrentIndex] = 0;
		SetTitle(pTitle);
	}
//SFF_END
}<commit_msg>GetContext() will always return something<commit_after>
#include "ImwPlatformWindow.h"

#include "ImwWindowManager.h"

namespace ImWindow
{
//SFF_BEGIN
	ImwPlatformWindow::ImwPlatformWindow(EPlatformWindowType eType, bool bCreateContext)
	{
		m_eType = eType;
		m_pContainer = new ImwContainer(this);
		m_pContext = NULL;
		m_pPreviousContext = NULL;
		m_bNeedRender = false;
		m_bShowContent = true;

		if ( bCreateContext )
		{
			ImGuiContext* pGlobalContext = ImGui::GetCurrentContext();
			IM_ASSERT(pGlobalContext != NULL);

			m_pContext = ImGui::CreateContext( pGlobalContext->IO.MemAllocFn, pGlobalContext->IO.MemFreeFn );

			ImGuiIO& oGlobalIO = pGlobalContext->IO;
			ImGuiIO& oNewIO = m_pContext->IO;

			memcpy(&(oNewIO.KeyMap), &(oGlobalIO.KeyMap ), sizeof( pGlobalContext->IO.KeyMap ));
			oNewIO.RenderDrawListsFn = NULL;
			oNewIO.GetClipboardTextFn = oGlobalIO.GetClipboardTextFn;
			oNewIO.SetClipboardTextFn = oGlobalIO.SetClipboardTextFn;
			oNewIO.ImeSetInputScreenPosFn = oGlobalIO.ImeSetInputScreenPosFn;
			oNewIO.IniFilename = NULL;
		}
	}

	ImwPlatformWindow::~ImwPlatformWindow()
	{
		ImwSafeDelete(m_pContainer);

		if (m_pContext != NULL)
		{
			m_pContext->IO.Fonts = NULL;
			SetContext(false);
			ImGui::Shutdown();
			RestoreContext(false);
			ImGui::DestroyContext(m_pContext);
			m_pContext = NULL;
		}
	}

	bool ImwPlatformWindow::Init(ImwPlatformWindow* /*pParent*/)
	{
		return true;
	}

	EPlatformWindowType ImwPlatformWindow::GetType() const
	{
		return m_eType;
	}

	bool ImwPlatformWindow::IsMainWindow() const
	{
		return m_eType == E_PLATFORM_WINDOW_TYPE_MAIN;
	}

	const ImVec2 c_oVec2_0 = ImVec2(0,0);
	ImVec2 ImwPlatformWindow::GetPosition() const
	{
		return c_oVec2_0;
	}

	ImVec2 ImwPlatformWindow::GetSize() const
	{
		return ImGui::GetIO().DisplaySize;
	}

	ImVec2 ImwPlatformWindow::GetNormalPosition() const
	{
		return GetPosition();
	}

	ImVec2 ImwPlatformWindow::GetNormalSize() const
	{
		return GetSize();
	}

	bool ImwPlatformWindow::IsWindowMaximized() const
	{
		return false;
	}

	bool ImwPlatformWindow::IsWindowMinimized() const
	{
		return false;
	}

	void ImwPlatformWindow::Show(bool /*bShow*/)
	{
	}

	void ImwPlatformWindow::SetSize(int /*iWidth*/, int /*iHeight*/)
	{
	}

	void ImwPlatformWindow::SetPosition(int /*iX*/, int /*iY*/)
	{
	}

	void ImwPlatformWindow::SetWindowMaximized(bool /*bMaximized*/)
	{
	}

	void  ImwPlatformWindow::SetWindowMinimized()
	{
	}

	void ImwPlatformWindow::SetTitle(const char* /*pTtile*/)
	{
	}

	bool ImwPlatformWindow::IsShowContent() const
	{
		return m_bShowContent;
	}

	void ImwPlatformWindow::SetShowContent(bool bShow)
	{
		m_bShowContent = bShow;
	}

	void ImwPlatformWindow::PreUpdate()
	{
	}

	void ImwPlatformWindow::PreRender()
	{
	}

	void ImwPlatformWindow::OnOverlay()
	{
	}

	void ImwPlatformWindow::RenderDrawLists(ImDrawData* /*pDrawData */)
	{
	}

	void ImwPlatformWindow::Render()
	{
		if( m_bNeedRender )
		{
			m_bNeedRender = false;
			SetContext(false);
			ImGui::GetIO().DisplaySize = GetSize();
			PreRender();
			ImGui::Render();
			RenderDrawLists(ImGui::GetDrawData());
			RestoreContext(false);
		}
	}

	void ImwPlatformWindow::PaintContainer()
	{
		m_pContainer->Paint();
	}

	void ImwPlatformWindow::OnClose()
	{
		ImwWindowManager::GetInstance()->OnClosePlatformWindow(this);
	}

	void ImwPlatformWindow::OnDropFiles(int iCount, char** pFiles, const ImVec2& oPos)
	{
		ImwWindow* pWindow = GetWindowAtPos(oPos);
		IM_ASSERT(pWindow != NULL);
		if (pWindow != NULL)
		{
			pWindow->OnDropFiles(iCount, pFiles, oPos);
		}
	}

	bool ImwPlatformWindow::Save(JsonValue& oJson)
	{
		ImVec2 oSize = GetNormalSize();
		ImVec2 oPos = GetNormalPosition();

		oJson["Width"] = (long)oSize.x;
		oJson["Height"] = (long)oSize.y;
		oJson["Left"] = (long)oPos.x;
		oJson["Top"] = (long)oPos.y;
		oJson["Mode"] = (long)(IsWindowMaximized() ? 1 : (IsWindowMinimized() ? -1 : 0));

		return m_pContainer->Save(oJson["Container"]);
	}

	bool ImwPlatformWindow::Load(const JsonValue& oJson, bool bJustCheck)
	{
		if (!oJson["Width"].IsNumeric() || !oJson["Height"].IsNumeric() || !oJson["Left"].IsNumeric() || !oJson["Top"].IsNumeric() || (!oJson["Mode"].IsNumeric() && !oJson["Maximized"].IsBoolean()))
			return false;

		if (!bJustCheck)
		{
			SetSize((long)oJson["Width"], (long)oJson["Height"]);
			SetPosition((long)oJson["Left"], (long)oJson["Top"]);

			if (oJson["Mode"].IsNumeric())
			{
				long iMode = (long)oJson["Mode"];
				if (iMode < 0)
				{
					SetWindowMinimized();
				}
				else
				{
					SetWindowMaximized(iMode > 0);
				}
			}
			else if (oJson["Maximized"].IsBoolean())
			{
				SetWindowMaximized(oJson["Maximized"]);
			}
		}

		return m_pContainer->Load(oJson["Container"], bJustCheck);
	}

	static bool s_bContextPushed = false;

	bool ImwPlatformWindow::IsContextSet()
	{
		return s_bContextPushed;
	}

	bool ImwPlatformWindow::HasContext() const
	{
		return m_pContext != NULL;
	}

	ImGuiContext* ImwPlatformWindow::GetContext()
	{
		if (m_pContext != NULL)
			return m_pContext;
		return ImGui::GetCurrentContext();
	}

	void ImwPlatformWindow::SetContext(bool bCopyStyle)
	{
		IM_ASSERT(s_bContextPushed == false);
		s_bContextPushed = true;
		if (m_pContext != NULL)
		{
			IM_ASSERT( m_pPreviousContext == NULL );
			m_pPreviousContext = ImGui::GetCurrentContext();
			ImGui::SetCurrentContext(m_pContext);
			if (bCopyStyle)
			{
				//Copy style from Global context
				memcpy(&(m_pContext->Style), &(m_pPreviousContext->Style), sizeof(ImGuiStyle));
			}
		}
	}

	void ImwPlatformWindow::RestoreContext(bool bCopyStyle)
	{
		IM_ASSERT(s_bContextPushed == true);
		s_bContextPushed = false;
		if (m_pContext != NULL)
		{
			IM_ASSERT(m_pPreviousContext != NULL);
			if (bCopyStyle)
			{
				//Copy style to Global context
				memcpy(&(m_pPreviousContext->Style), &(m_pContext->Style), sizeof(ImGuiStyle));
			}
			ImGui::SetCurrentContext(m_pPreviousContext);
			m_pPreviousContext = NULL;
		}
	}

	void ImwPlatformWindow::OnLoseFocus()
	{
		if (NULL != m_pContext)
		{
			m_pContext->SetNextWindowPosCond = m_pContext->SetNextWindowSizeCond = m_pContext->SetNextWindowContentSizeCond = m_pContext->SetNextWindowCollapsedCond = m_pContext->SetNextWindowFocus = 0;
			m_pContext->ActiveId = 0;

			for (int i = 0; i < 512; ++i)
				m_pContext->IO.KeysDown[i] = false;

			for (int i = 0; i < 5; ++i)
				m_pContext->IO.MouseDown[i] = false;

			m_pContext->IO.KeyAlt = false;
			m_pContext->IO.KeyCtrl = false;
			m_pContext->IO.KeyShift = false;
		}
	}

	void ImwPlatformWindow::Dock(ImwWindow* pWindow)
	{
		m_pContainer->Dock(pWindow);
	}

	bool ImwPlatformWindow::UnDock(ImwWindow* pWindow)
	{
		return m_pContainer->UnDock(pWindow);
	}

	ImwContainer* ImwPlatformWindow::GetContainer()
	{
		return m_pContainer;
	}

	ImwWindow* ImwPlatformWindow::GetWindowAtPos(const ImVec2& oPos) const
	{
		return m_pContainer->GetWindowAtPos(oPos);
	}

	const ImwContainer* ImwPlatformWindow::HasWindow(ImwWindow* pWindow)
	{
		return m_pContainer->HasWindow(pWindow);
	}

	bool ImwPlatformWindow::FocusWindow(ImwWindow* pWindow)
	{
		return m_pContainer->FocusWindow(pWindow);
	}

	void ImwPlatformWindow::RefreshTitle()
	{
		const ImwChar* pMainTitle = ImwWindowManager::GetInstance()->GetMainTitle();

		ImwWindow* pActiveWindow = m_pContainer->GetActiveWindow();
		const ImwChar* pActiveWindowTitle = NULL;

		if (pActiveWindow != NULL)
		{
			pActiveWindowTitle = pActiveWindow->GetTitle();
		}

		const size_t c_iMaxTitleLen = 512;
		ImwChar pTitle[c_iMaxTitleLen + 1];
		size_t iCurrentIndex = 0;

		if (pMainTitle != NULL)
		{
			size_t iLen = strlen(pMainTitle);
			if (iLen > (c_iMaxTitleLen - iCurrentIndex))
				iLen = c_iMaxTitleLen - iCurrentIndex;
			if (iLen > 0)
			{
				memcpy(pTitle + iCurrentIndex, pMainTitle, iLen);
				iCurrentIndex += iLen;
			}
		}

		if (pActiveWindowTitle != NULL)
		{
			if (iCurrentIndex != 0)
			{
				const char* const c_pSeparator = " - ";
				size_t iLen = strlen(c_pSeparator);
				if (iLen > (c_iMaxTitleLen - iCurrentIndex))
					iLen = c_iMaxTitleLen - iCurrentIndex;
				if (iLen > 0)
				{
					memcpy(pTitle + iCurrentIndex, c_pSeparator, iLen);
					iCurrentIndex += iLen;
				}
			}

			size_t iLen = strlen(pActiveWindowTitle);
			if (iLen > (c_iMaxTitleLen - iCurrentIndex))
				iLen = c_iMaxTitleLen - iCurrentIndex;
			if (iLen > 0)
			{
				memcpy(pTitle + iCurrentIndex, pActiveWindowTitle, iLen);
				iCurrentIndex += iLen;
			}
		}

		pTitle[iCurrentIndex] = 0;
		SetTitle(pTitle);
	}
//SFF_END
}<|endoftext|>


<commit_before>// Difference from running average.

#include <vector>
#include <sstream>
#include <boost/date_time.hpp>
#include <boost/filesystem.hpp>
#include <opencv2/opencv.hpp>
#include "RateTicker.hpp"
#include "Config.hpp"
#include "util.hpp"

int main(int argc, char** argv)
{
    // Parse command-line arguments.
    int DEVICE, WIDTH, HEIGHT, DURATION;
    std::istringstream(std::string(argv[1])) >> DEVICE;
    std::istringstream(std::string(argv[2])) >> WIDTH;
    std::istringstream(std::string(argv[3])) >> HEIGHT;
    std::istringstream(std::string(argv[4])) >> DURATION;

    // Create the OpenCV video capture object.
    cv::VideoCapture cap(DEVICE);
    cap.set(3, WIDTH);
    cap.set(4, HEIGHT);

    // Create the output window.
    const char* title = "detect 1";
    cv::namedWindow(title, CV_WINDOW_NORMAL);

    // Initialize the classifiers and their respective colors.
    Config config ("conf/classifiers.conf");
    std::vector< cv::CascadeClassifier* > classifiers;
    std::vector< cv::Scalar > colors;
    for(auto fname : config.keys())
    {
        boost::filesystem::path file(fname + ".xml");
        for(auto dname : { "/usr/share/OpenCV/haarcascades",
                    "/usr/share/OpenCV/lbpcascades" }
            )
        {
            boost::filesystem::path dir(dname);
            boost::filesystem::path full = dir / file;
            auto cfer = new cv::CascadeClassifier(full.string());
            if( cfer->empty() ) continue;
            classifiers.push_back(cfer);
            int rr, gg, bb;
            std::stringstream(config[fname]) >> rr >> gg >> bb;
            colors.push_back(cv::Scalar(rr, gg, bb));
        }
    }

    // Keep track of previous iteration's timestamp.
    boost::posix_time::ptime tstamp_prev;

    // Monitor framerates for the given seconds past.
    std::vector<float> periods = { 1, 5, 10 };
    RateTicker framerate (periods);

    // Run the loop for designated amount of time.
    auto now = boost::posix_time::microsec_clock::universal_time();
    auto dur = boost::posix_time::seconds(DURATION);
    auto end = now + dur;
    while (end > boost::posix_time::microsec_clock::universal_time())
    {
        // Take a snapshot.
        cv::Mat frame;
        cap >> frame;

        // Collect a list of positive detection rectangles.
        struct RectColor{
            cv::Rect rect;
            cv::Scalar color;
        };
        std::vector<RectColor> results;
        for(auto ii=0; ii!= classifiers.size(); ++ii){
            std::vector<cv::Rect> rects;
            classifiers[ii]->detectMultiScale(
                frame,
                rects,
                1.3,  // scale factor.
                3,    // min neighbors.
                0,    // flags.
                {frame.size().width/20, frame.size().height/20},  // min size.
                {frame.size().width/2, frame.size().height/2}     // max size.
                );
            for(auto jj=rects.begin(); jj!= rects.end(); ++jj){
                results.push_back({ *jj, colors[ii] });
            }
        }

        // Draw the rectangles.
        for(auto ii=results.begin(); ii!=results.end(); ++ii){
            auto rect = ii->rect;
            auto color = ii->color;
            cv::rectangle(
                frame,
                cv::Point(rect.x, rect.y),
                cv::Point(rect.x + rect.width, rect.y + rect.height),
                color,
                2  // thickness.
                );
        }

        // Display the snapshot.
        cv::imshow(title, frame);
        cv::waitKey(1);
    }
}
<commit_msg>Add framerate display.<commit_after>// Difference from running average.

#include <vector>
#include <sstream>
#include <boost/date_time.hpp>
#include <boost/filesystem.hpp>
#include <opencv2/opencv.hpp>
#include "RateTicker.hpp"
#include "Config.hpp"
#include "util.hpp"

int main(int argc, char** argv)
{
    // Parse command-line arguments.
    int DEVICE, WIDTH, HEIGHT, DURATION;
    std::istringstream(std::string(argv[1])) >> DEVICE;
    std::istringstream(std::string(argv[2])) >> WIDTH;
    std::istringstream(std::string(argv[3])) >> HEIGHT;
    std::istringstream(std::string(argv[4])) >> DURATION;

    // Create the OpenCV video capture object.
    cv::VideoCapture cap(DEVICE);
    cap.set(3, WIDTH);
    cap.set(4, HEIGHT);

    // Create the output window.
    const char* title = "detect 1";
    cv::namedWindow(title, CV_WINDOW_NORMAL);

    // Initialize the classifiers and their respective colors.
    Config config ("conf/classifiers.conf");
    std::vector< cv::CascadeClassifier* > classifiers;
    std::vector< cv::Scalar > colors;
    for(auto fname : config.keys())
    {
        boost::filesystem::path file(fname + ".xml");
        for(auto dname : { "/usr/share/OpenCV/haarcascades",
                    "/usr/share/OpenCV/lbpcascades" }
            )
        {
            boost::filesystem::path dir(dname);
            boost::filesystem::path full = dir / file;
            auto cfer = new cv::CascadeClassifier(full.string());
            if( cfer->empty() ) continue;
            classifiers.push_back(cfer);
            int rr, gg, bb;
            std::stringstream(config[fname]) >> rr >> gg >> bb;
            colors.push_back(cv::Scalar(rr, gg, bb));
        }
    }

    // Monitor framerates for the given seconds past.
    RateTicker framerate ({ 1, 5, 10 });

    // Run the loop for designated amount of time.
    auto now = boost::posix_time::microsec_clock::universal_time();
    auto dur = boost::posix_time::seconds(DURATION);
    auto end = now + dur;
    while (end > boost::posix_time::microsec_clock::universal_time())
    {
        // Take a snapshot.
        cv::Mat frame;
        cap >> frame;

        // Collect a list of positive detection rectangles.
        struct RectColor{
            cv::Rect rect;
            cv::Scalar color;
        };
        std::vector<RectColor> results;
        for(auto ii=0; ii!= classifiers.size(); ++ii){
            std::vector<cv::Rect> rects;
            classifiers[ii]->detectMultiScale(
                frame,
                rects,
                1.3,  // scale factor.
                3,    // min neighbors.
                0,    // flags.
                {frame.size().width/20, frame.size().height/20},  // min size.
                {frame.size().width/2, frame.size().height/2}     // max size.
                );
            for(auto jj=rects.begin(); jj!= rects.end(); ++jj){
                results.push_back({ *jj, colors[ii] });
            }
        }

        // Draw the rectangles.
        for(auto ii=results.begin(); ii!=results.end(); ++ii){
            auto rect = ii->rect;
            auto color = ii->color;
            cv::rectangle(
                frame,
                cv::Point(rect.x, rect.y),
                cv::Point(rect.x + rect.width, rect.y + rect.height),
                color,
                2  // thickness.
                );
        }

        // Write the display framerate on top of the image.
        auto fps = framerate.tick();
        std::ostringstream line;
        line << std::fixed << std::setprecision(2);
        line << fps[0] << ", " << fps[1] << ", " << fps[2];
        std::list<std::string> lines;
        lines.push_back(line.str());
        sherlock::writeOSD(frame, lines, 0.04);

        // Display the snapshot.
        cv::imshow(title, frame);
        cv::waitKey(1);
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"

namespace {

typedef InProcessBrowserTest PrintPreviewTabControllerBrowserTest;

// Test to verify that when a preview tab navigates, we can create a new print
// preview tab for both initiator tab and new preview tab contents.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       NavigateFromPrintPreviewTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  GURL url(chrome::kAboutBlankURL);
  ui_test_utils::NavigateToURL(browser(), url);
  EXPECT_EQ(url, preview_tab->tab_contents()->GetURL());

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New preview tab is created.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_NE(new_preview_tab, preview_tab);

  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Newest preview tab is created and the previously created preview tab is not
  // merely activated.
  EXPECT_EQ(4, browser()->tab_count());
  EXPECT_NE(newest_preview_tab, new_preview_tab);
}

// Test to verify that when a initiator tab navigates, we can create a new
// preview tab for the new tab contents. But we cannot create a preview tab for
// the old preview tab.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       NavigateFromInitiatorTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  // Activate initiator tab.
  browser()->ActivateTabAt(0, true);
  GURL url(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), url);

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New preview tab is created.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_NE(new_preview_tab, preview_tab);

  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Make sure preview tab is not created for |preview_tab|.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_EQ(newest_preview_tab, preview_tab);
}

// Test to verify that even after reloading initiator tab and preview tab,
// their association exists.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       ReloadInitiatorTabAndPreviewTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  // Activate initiator tab and reload.
  browser()->ActivateTabAt(0, true);
  browser()->Reload(CURRENT_TAB);

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // Old preview tab is activated.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_EQ(new_preview_tab, preview_tab);

  // Reload preview tab.
  browser()->Reload(CURRENT_TAB);
  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Make sure new preview tab is not created for |preview_tab|.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_EQ(newest_preview_tab, preview_tab);
}

// Test that print preview tabs are placed correctly.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       OpenPreviewTabInCorrectPosition) {
  const int kTabCount = 4;
  // Create kTabCount - 1 tabs since we start with 1 tab already.
  for (int i = 0; i < kTabCount - 1; ++i) {
    browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
    p.disposition = NEW_FOREGROUND_TAB;
    browser::Navigate(&p);
  }
  EXPECT_EQ(kTabCount, browser()->tab_count());

  // Create a print preview tab.
  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  const int kInitiatorTabIndex = 1;
  TabContentsWrapper* initiator_tab =
      browser()->GetTabContentsWrapperAt(kInitiatorTabIndex);
  ASSERT_TRUE(initiator_tab);
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);
  EXPECT_TRUE(preview_tab);

  // Check the preview tab's location.
  EXPECT_EQ(preview_tab,
            browser()->GetTabContentsWrapperAt(kInitiatorTabIndex + 1));
  EXPECT_EQ(preview_tab, browser()->GetSelectedTabContentsWrapper());
}

// Test that print preview tabs created by pop-up windows are placed correctly.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       OpenPreviewTabFromPopupInCorrectPosition) {
  const int kTabCount = 4;
  // Create kTabCount - 1 tabs since we start with 1 tab already.
  for (int i = 0; i < kTabCount - 1; ++i) {
    browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
    p.disposition = NEW_FOREGROUND_TAB;
    browser::Navigate(&p);
  }
  EXPECT_EQ(kTabCount, browser()->tab_count());

  // Create a popup
  browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
  p.disposition = NEW_POPUP;
  ui_test_utils::NavigateToURL(&p);

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
  // Navigate() should have opened a new tab on CrOS.
  EXPECT_EQ(browser(), p.browser);
  EXPECT_EQ(Browser::TYPE_TABBED, p.browser->type());
#else
  // Navigate() should have opened a new popup window.
  EXPECT_NE(browser(), p.browser);
  EXPECT_EQ(Browser::TYPE_POPUP, p.browser->type());
#endif
  ASSERT_TRUE(p.target_contents);

  // Create a print preview tab.
  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(p.target_contents);
  EXPECT_TRUE(preview_tab);

  int tab_position = kTabCount;
#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
  // Increment position since CrOS opened a new tab instead of a popup.
  tab_position++;
#endif

  // Check the preview tab's location.
  EXPECT_EQ(preview_tab, browser()->GetTabContentsWrapperAt(tab_position));
  EXPECT_EQ(preview_tab, browser()->GetSelectedTabContentsWrapper());
}

}  // namespace
<commit_msg>Fix OpenPreviewTabFromPopupInCorrectPosition test on Linux Views.<commit_after>// Copyright (c) 2011 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/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"

namespace {

typedef InProcessBrowserTest PrintPreviewTabControllerBrowserTest;

// Test to verify that when a preview tab navigates, we can create a new print
// preview tab for both initiator tab and new preview tab contents.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       NavigateFromPrintPreviewTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  GURL url(chrome::kAboutBlankURL);
  ui_test_utils::NavigateToURL(browser(), url);
  EXPECT_EQ(url, preview_tab->tab_contents()->GetURL());

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New preview tab is created.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_NE(new_preview_tab, preview_tab);

  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Newest preview tab is created and the previously created preview tab is not
  // merely activated.
  EXPECT_EQ(4, browser()->tab_count());
  EXPECT_NE(newest_preview_tab, new_preview_tab);
}

// Test to verify that when a initiator tab navigates, we can create a new
// preview tab for the new tab contents. But we cannot create a preview tab for
// the old preview tab.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       NavigateFromInitiatorTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  // Activate initiator tab.
  browser()->ActivateTabAt(0, true);
  GURL url(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), url);

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New preview tab is created.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_NE(new_preview_tab, preview_tab);

  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Make sure preview tab is not created for |preview_tab|.
  EXPECT_EQ(3, browser()->tab_count());
  EXPECT_EQ(newest_preview_tab, preview_tab);
}

// Test to verify that even after reloading initiator tab and preview tab,
// their association exists.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       ReloadInitiatorTabAndPreviewTab) {
  ASSERT_TRUE(browser());
  BrowserList::SetLastActive(browser());
  ASSERT_TRUE(BrowserList::GetLastActive());

  // Lets start with one window with one tab.
  EXPECT_EQ(1u, BrowserList::size());
  EXPECT_EQ(1, browser()->tab_count());

  // Create a reference to initiator tab contents.
  TabContentsWrapper* initiator_tab =
      browser()->GetSelectedTabContentsWrapper();
  ASSERT_TRUE(initiator_tab);

  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  // Get the preview tab for initiator tab.
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // New print preview tab is created. Current focus is on preview tab.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_NE(initiator_tab, preview_tab);

  // Activate initiator tab and reload.
  browser()->ActivateTabAt(0, true);
  browser()->Reload(CURRENT_TAB);

  // Get the print preview tab for initiator tab.
  TabContentsWrapper* new_preview_tab =
     tab_controller->GetOrCreatePreviewTab(initiator_tab);

  // Old preview tab is activated.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_EQ(new_preview_tab, preview_tab);

  // Reload preview tab.
  browser()->Reload(CURRENT_TAB);
  // Get the print preview tab for old preview tab.
  TabContentsWrapper* newest_preview_tab =
  tab_controller->GetOrCreatePreviewTab(preview_tab);

  // Make sure new preview tab is not created for |preview_tab|.
  EXPECT_EQ(2, browser()->tab_count());
  EXPECT_EQ(newest_preview_tab, preview_tab);
}

// Test that print preview tabs are placed correctly.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       OpenPreviewTabInCorrectPosition) {
  const int kTabCount = 4;
  // Create kTabCount - 1 tabs since we start with 1 tab already.
  for (int i = 0; i < kTabCount - 1; ++i) {
    browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
    p.disposition = NEW_FOREGROUND_TAB;
    browser::Navigate(&p);
  }
  EXPECT_EQ(kTabCount, browser()->tab_count());

  // Create a print preview tab.
  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  const int kInitiatorTabIndex = 1;
  TabContentsWrapper* initiator_tab =
      browser()->GetTabContentsWrapperAt(kInitiatorTabIndex);
  ASSERT_TRUE(initiator_tab);
  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(initiator_tab);
  EXPECT_TRUE(preview_tab);

  // Check the preview tab's location.
  EXPECT_EQ(preview_tab,
            browser()->GetTabContentsWrapperAt(kInitiatorTabIndex + 1));
  EXPECT_EQ(preview_tab, browser()->GetSelectedTabContentsWrapper());
}

// Test that print preview tabs created by pop-up windows are placed correctly.
IN_PROC_BROWSER_TEST_F(PrintPreviewTabControllerBrowserTest,
                       OpenPreviewTabFromPopupInCorrectPosition) {
  const int kTabCount = 4;
  // Create kTabCount - 1 tabs since we start with 1 tab already.
  for (int i = 0; i < kTabCount - 1; ++i) {
    browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
    p.disposition = NEW_FOREGROUND_TAB;
    browser::Navigate(&p);
  }
  EXPECT_EQ(kTabCount, browser()->tab_count());

  // Create a popup
  browser::NavigateParams p(browser(), GURL(), PageTransition::LINK);
  p.disposition = NEW_POPUP;
  ui_test_utils::NavigateToURL(&p);

#if defined(OS_CHROMEOS)
  // Navigate() should have opened a new tab on CrOS.
  EXPECT_EQ(browser(), p.browser);
  EXPECT_EQ(Browser::TYPE_TABBED, p.browser->type());
#else
  // Navigate() should have opened a new popup window.
  EXPECT_NE(browser(), p.browser);
  EXPECT_EQ(Browser::TYPE_POPUP, p.browser->type());
#endif
  ASSERT_TRUE(p.target_contents);

  // Create a print preview tab.
  scoped_refptr<printing::PrintPreviewTabController>
     tab_controller(new printing::PrintPreviewTabController());
  ASSERT_TRUE(tab_controller);

  TabContentsWrapper* preview_tab =
    tab_controller->GetOrCreatePreviewTab(p.target_contents);
  EXPECT_TRUE(preview_tab);

  int tab_position = kTabCount;
#if defined(OS_CHROMEOS)
  // Increment position since CrOS opened a new tab instead of a popup.
  tab_position++;
#endif

  // Check the preview tab's location.
  EXPECT_EQ(preview_tab, browser()->GetTabContentsWrapperAt(tab_position));
  EXPECT_EQ(preview_tab, browser()->GetSelectedTabContentsWrapper());
}

}  // namespace
<|endoftext|>


<commit_before>#include "df_font.h"

#include "df_bitmap.h"
#include "df_common.h"

#if _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include "df_bmp.h"
#endif

#include <limits.h>
#include <memory.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

// ****************************************************************************
// Glyph
// ****************************************************************************

typedef struct
{
    unsigned startX;
    unsigned startY;
    unsigned runLen;
} EncodedRun;

class Glyph
{
public:
    unsigned m_width;
    int m_numRuns;
    EncodedRun *m_pixelRuns;

    Glyph(int w)
    {
        m_width = w;
    }
};

// ****************************************************************************
// Global variables
// ****************************************************************************

DfFont *g_defaultFont = NULL;

static int GetPixel(char *tmpBitmap, int bmpWidth, int x, int y)
{
    return tmpBitmap[y * bmpWidth + x];
}

struct MemBuf
{
    unsigned char *data;
    int len;
    int currentPos;
    int currentByte;
    int hiNibbleNext;

    MemBuf(unsigned *_data, int _len)
    {
        data = (unsigned char *)_data;
        len = _len;
        currentPos = 0;
        currentByte = 0;
        hiNibbleNext = 0;
    }

    int ReadByte()
    {
        if (currentPos >= len) return 0;
        currentByte = data[currentPos];
        currentPos++;
        return currentByte;
    }

    int ReadNibble()
    {
        if (hiNibbleNext) {
            hiNibbleNext = 0;
            return currentByte >> 4;
        }

        ReadByte();
        hiNibbleNext = 1;
        return currentByte & 0xf;
    }
};

// ****************************************************************************
// Public Functions
// ****************************************************************************

DfFont *LoadFontFromMemory(void *_buf, int bufLen)
{
    MemBuf buf((unsigned int *)_buf, bufLen);
    DfFont *tr = new DfFont;
    memset(tr, 0, sizeof(DfFont));

    tr->maxCharWidth = buf.ReadByte();
    tr->charHeight = buf.ReadByte();
    tr->fixedWidth = !buf.ReadByte();

    char glyphWidths[224];
    if (!tr->fixedWidth)
    {
        for (int i = 0; i < 224; i++) glyphWidths[i] = buf.ReadByte();
    }
    else
    {
        for (int i = 0; i < 224; i++) glyphWidths[i] = tr->maxCharWidth;
    }

    // Decode the RLE data into a bitmap with one char per pixel.
    int bmpWidth = tr->maxCharWidth * 16;
    int bmpHeight = tr->charHeight * 14;
    char *tmpBitmap = new char [bmpWidth * bmpHeight];
    {
        int runVal = 1;
        int tmpBitmapOffset = 0;
        while (buf.currentPos < buf.len)
        {
            int runLeft = buf.ReadNibble();

            if (runLeft == 0) // 0 is the escape token.
            {
                runLeft = buf.ReadNibble();
                runLeft += buf.ReadNibble() << 4;
            }

            runVal = 1 - runVal;
            DebugAssert((tmpBitmapOffset + runLeft) < bmpWidth * bmpHeight);
            memset(tmpBitmap + tmpBitmapOffset, runVal, runLeft);
            tmpBitmapOffset += runLeft;
        }

        int pixelsLeft = bmpWidth * bmpHeight - tmpBitmapOffset;
        DebugAssert(pixelsLeft >= 0);
        memset(tmpBitmap + tmpBitmapOffset, 0, pixelsLeft);
    }

    // Undo "up" prediction
    for (int y = 1; y < bmpHeight; y++)
    {
        for (int x = 0; x < bmpWidth; x++)
        {
            char up = tmpBitmap[(y - 1) * bmpWidth + x];
            tmpBitmap[y * bmpWidth + x] ^= up;
        }
    }

    // Allocate enough EncodedRuns to store the worst case for a glyph of this size.
    // Worst case is if the whole glyph is encoded as runs of one pixel. There has
    // to be a gap of one pixel between each run, so there can only be half as many
    // runs as there are pixels.
    unsigned tempRunsSize = tr->charHeight * (tr->maxCharWidth / 2 + 1);
    EncodedRun *tempRuns = new EncodedRun [tempRunsSize];

    // Run-length encode each ASCII character
    for (int i = 32; i < 256; i++)
    {
        // Read back the bitmap and construct a run-length encoding
        memset(tempRuns, 0, tempRunsSize);
        EncodedRun *run = tempRuns;
        for (int y = 0; y < tr->charHeight; y++)
        {
            int x = 0;
            int bmpY = (i - 32) / 16 * tr->charHeight + y;
            while (x < tr->maxCharWidth)
            {
                // Skip blank pixels
                int bmpX = i % 16 * tr->maxCharWidth + x;
                while (GetPixel(tmpBitmap, bmpWidth, bmpX, bmpY) == 0)
                {
                    x++;
                    if (x >= tr->maxCharWidth)
                        break;
                    bmpX++;
                }

                // Have we got to the end of the line?
                if (x >= tr->maxCharWidth)
                    continue;

                run->startX = x;
                run->startY = y;
                run->runLen = 0;

                // Count non-blank pixels
                while (GetPixel(tmpBitmap, bmpWidth, bmpX, bmpY) != 0)
                {
                    x++;
                    run->runLen++;
                    if (x >= tr->maxCharWidth)
                        break;
                    bmpX++;
                }

                run++;
            }
        }

        // Create the glyph to store the encoded runs we've made
        Glyph *glyph = new Glyph(glyphWidths[i - 32]);
        tr->glyphs[i] = glyph;

        // Copy the runs into the glyph
        glyph->m_numRuns = run - tempRuns;
        glyph->m_pixelRuns = new EncodedRun [glyph->m_numRuns];
        memcpy(glyph->m_pixelRuns, tempRuns, glyph->m_numRuns * sizeof(EncodedRun));
    }

    delete [] tempRuns;
    delete [] tmpBitmap;

    return tr;
}

DfFont *LoadFontFromFile(char const *filename, int pixHeight)
{
    FILE *f = fopen(filename, "rb");
    if (!f) return NULL;

    char buf[5];
    fread(buf, 1, 5, f);
    if (memcmp(buf, "dfbf\0", 5) != 0) return NULL;

    unsigned char numFonts = 0;
    fread(&numFonts, 1, 1, f);

    unsigned int fileOffsets[257];
    fread(fileOffsets, 4, numFonts, f);
    fseek(f, 0, SEEK_END);
    fileOffsets[numFonts] = ftell(f);

    for (unsigned i = 0; i < numFonts; i++) {
        fseek(f, fileOffsets[i], SEEK_SET);
        int maxWidth = fgetc(f);
        int thisPixHeight = fgetc(f);
        if (thisPixHeight == pixHeight) {
            fseek(f, fileOffsets[i], SEEK_SET);
            int fontBinSize = fileOffsets[i + 1] - fileOffsets[i];
            char *fontBuf = new char[fontBinSize];
            fread(fontBuf, 1, fontBinSize, f);
            DfFont *fnt = LoadFontFromMemory((unsigned int *)fontBuf, fontBinSize);
            delete[] fontBuf;
            return fnt;
        }
    }

    return NULL;
}

static int DrawTextSimpleClipped(DfFont *tr, DfColour col, DfBitmap *bmp, int _x, int y, char const *text, int maxChars)
{
    int x = _x;
    DfColour *startRow = bmp->pixels + y * bmp->width;
    int width = bmp->width;

    if (y + tr->charHeight < bmp->clipTop || y > bmp->clipBottom)
        return 0;

    for (int j = 0; text[j] && j < maxChars; j++)
    {
        if (x > bmp->clipRight)
            break;

        unsigned char c = text[j];
        Glyph *glyph = tr->glyphs[c];

        EncodedRun *rleBuf = glyph->m_pixelRuns;
        for (int i = 0; i < glyph->m_numRuns; i++)
        {
            int y3 = y + rleBuf->startY;
            if (y3 >= bmp->clipTop && y3 < bmp->clipBottom)
            {
                DfColour *thisRow = startRow + rleBuf->startY * width;
                for (unsigned i = 0; i < rleBuf->runLen; i++)
                {
                    int x3 = x + rleBuf->startX + i;
                    if (x3 >= bmp->clipLeft && x3 < bmp->clipRight)
                        thisRow[x3] = col;
                }
            }
            rleBuf++;
        }

        x += glyph->m_width;
    }

    return x - _x;
}

int DrawTextSimpleLen(DfFont *tr, DfColour col, DfBitmap *bmp, int _x, int y, char const *text, int maxChars)
{
    int x = _x;
    int width = bmp->width;

    if (x < bmp->clipLeft || y < bmp->clipTop || (y + tr->charHeight) > bmp->clipBottom)
        return DrawTextSimpleClipped(tr, col, bmp, _x, y, text, maxChars);

    DfColour *startRow = bmp->pixels + y * bmp->width;
    for (int j = 0; text[j] && j < maxChars; j++)
    {
        unsigned char c = text[j];
        if (x + (int)tr->glyphs[c]->m_width > bmp->clipRight)
            break;

        // Copy the glyph onto the stack for better cache performance. This increased the
        // performance from 13.8 to 14.4 million chars per second. Madness.
        Glyph glyph = *tr->glyphs[c];
        EncodedRun *rleBuf = glyph.m_pixelRuns;
        for (int i = 0; i < glyph.m_numRuns; i++)
        {
            DfColour *startPixel = startRow + rleBuf->startY * width + rleBuf->startX + x;
            for (unsigned i = 0; i < rleBuf->runLen; i++)
                startPixel[i] = col;
            rleBuf++;
        }

        x += glyph.m_width;
    }

    return x - _x;
}

int DrawTextSimple(DfFont *f, DfColour col, DfBitmap *bmp, int x, int y, char const *text)
{
    return DrawTextSimpleLen(f, col, bmp, x, y, text, 9999);
}

int DrawTextLeft(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);
    return DrawTextSimple(tr, c, bmp, x, y, buf);
}

int DrawTextRight(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);

    int width = GetTextWidth(tr, buf);
    return DrawTextSimple(tr, c, bmp, x - width, y, buf);
}

int DrawTextCentre(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);

    int width = GetTextWidth(tr, buf);
    return DrawTextSimple(tr, c, bmp, x - width/2, y, buf);
}

int GetTextWidth(DfFont *tr, char const *text, int len)
{
    len = IntMin((int)strlen(text), len);
    if (tr->fixedWidth)
    {
        return len * tr->maxCharWidth;
    }
    else
    {
        int width = 0;
        for (int i = 0; i < len; i++)
            width += tr->glyphs[text[i] & 0xff]->m_width;

        return width;
    }
}
<commit_msg>Fix a warning from GCC.<commit_after>#include "df_font.h"

#include "df_bitmap.h"
#include "df_common.h"

#if _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include "df_bmp.h"
#endif

#include <limits.h>
#include <memory.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

// ****************************************************************************
// Glyph
// ****************************************************************************

typedef struct
{
    unsigned startX;
    unsigned startY;
    unsigned runLen;
} EncodedRun;

class Glyph
{
public:
    unsigned m_width;
    int m_numRuns;
    EncodedRun *m_pixelRuns;

    Glyph(int w)
    {
        m_width = w;
    }
};

// ****************************************************************************
// Global variables
// ****************************************************************************

DfFont *g_defaultFont = NULL;

static int GetPixel(char *tmpBitmap, int bmpWidth, int x, int y)
{
    return tmpBitmap[y * bmpWidth + x];
}

struct MemBuf
{
    unsigned char *data;
    int len;
    int currentPos;
    int currentByte;
    int hiNibbleNext;

    MemBuf(unsigned *_data, int _len)
    {
        data = (unsigned char *)_data;
        len = _len;
        currentPos = 0;
        currentByte = 0;
        hiNibbleNext = 0;
    }

    int ReadByte()
    {
        if (currentPos >= len) return 0;
        currentByte = data[currentPos];
        currentPos++;
        return currentByte;
    }

    int ReadNibble()
    {
        if (hiNibbleNext) {
            hiNibbleNext = 0;
            return currentByte >> 4;
        }

        ReadByte();
        hiNibbleNext = 1;
        return currentByte & 0xf;
    }
};

// ****************************************************************************
// Public Functions
// ****************************************************************************

DfFont *LoadFontFromMemory(void *_buf, int bufLen)
{
    MemBuf buf((unsigned int *)_buf, bufLen);
    DfFont *tr = new DfFont;
    memset(tr, 0, sizeof(DfFont));

    tr->maxCharWidth = buf.ReadByte();
    tr->charHeight = buf.ReadByte();
    tr->fixedWidth = !buf.ReadByte();

    char glyphWidths[224];
    if (!tr->fixedWidth)
    {
        for (int i = 0; i < 224; i++) glyphWidths[i] = buf.ReadByte();
    }
    else
    {
        for (int i = 0; i < 224; i++) glyphWidths[i] = tr->maxCharWidth;
    }

    // Decode the RLE data into a bitmap with one char per pixel.
    int bmpWidth = tr->maxCharWidth * 16;
    int bmpHeight = tr->charHeight * 14;
    char *tmpBitmap = new char [bmpWidth * bmpHeight];
    {
        int runVal = 1;
        int tmpBitmapOffset = 0;
        while (buf.currentPos < buf.len)
        {
            int runLeft = buf.ReadNibble();

            if (runLeft == 0) // 0 is the escape token.
            {
                runLeft = buf.ReadNibble();
                runLeft += buf.ReadNibble() << 4;
            }

            runVal = 1 - runVal;
            DebugAssert((tmpBitmapOffset + runLeft) < bmpWidth * bmpHeight);
            memset(tmpBitmap + tmpBitmapOffset, runVal, runLeft);
            tmpBitmapOffset += runLeft;
        }

        int pixelsLeft = bmpWidth * bmpHeight - tmpBitmapOffset;
        DebugAssert(pixelsLeft >= 0);
        memset(tmpBitmap + tmpBitmapOffset, 0, pixelsLeft);
    }

    // Undo "up" prediction
    for (int y = 1; y < bmpHeight; y++)
    {
        for (int x = 0; x < bmpWidth; x++)
        {
            char up = tmpBitmap[(y - 1) * bmpWidth + x];
            tmpBitmap[y * bmpWidth + x] ^= up;
        }
    }

    // Allocate enough EncodedRuns to store the worst case for a glyph of this size.
    // Worst case is if the whole glyph is encoded as runs of one pixel. There has
    // to be a gap of one pixel between each run, so there can only be half as many
    // runs as there are pixels.
    unsigned tempRunsSize = tr->charHeight * (tr->maxCharWidth / 2 + 1);
    EncodedRun *tempRuns = new EncodedRun [tempRunsSize];

    // Run-length encode each ASCII character
    for (int i = 32; i < 256; i++)
    {
        // Read back the bitmap and construct a run-length encoding
        memset(tempRuns, 0, tempRunsSize);
        EncodedRun *run = tempRuns;
        for (int y = 0; y < tr->charHeight; y++)
        {
            int x = 0;
            int bmpY = (i - 32) / 16 * tr->charHeight + y;
            while (x < tr->maxCharWidth)
            {
                // Skip blank pixels
                int bmpX = i % 16 * tr->maxCharWidth + x;
                while (GetPixel(tmpBitmap, bmpWidth, bmpX, bmpY) == 0)
                {
                    x++;
                    if (x >= tr->maxCharWidth)
                        break;
                    bmpX++;
                }

                // Have we got to the end of the line?
                if (x >= tr->maxCharWidth)
                    continue;

                run->startX = x;
                run->startY = y;
                run->runLen = 0;

                // Count non-blank pixels
                while (GetPixel(tmpBitmap, bmpWidth, bmpX, bmpY) != 0)
                {
                    x++;
                    run->runLen++;
                    if (x >= tr->maxCharWidth)
                        break;
                    bmpX++;
                }

                run++;
            }
        }

        // Create the glyph to store the encoded runs we've made
        Glyph *glyph = new Glyph(glyphWidths[i - 32]);
        tr->glyphs[i] = glyph;

        // Copy the runs into the glyph
        glyph->m_numRuns = run - tempRuns;
        glyph->m_pixelRuns = new EncodedRun [glyph->m_numRuns];
        memcpy(glyph->m_pixelRuns, tempRuns, glyph->m_numRuns * sizeof(EncodedRun));
    }

    delete [] tempRuns;
    delete [] tmpBitmap;

    return tr;
}

DfFont *LoadFontFromFile(char const *filename, int pixHeight)
{
    FILE *f = fopen(filename, "rb");
    if (!f) return NULL;

    char buf[5];
    fread(buf, 1, 5, f);
    if (memcmp(buf, "dfbf\0", 5) != 0) return NULL;

    unsigned char numFonts = 0;
    fread(&numFonts, 1, 1, f);

    unsigned int fileOffsets[257];
    fread(fileOffsets, 4, numFonts, f);
    fseek(f, 0, SEEK_END);
    fileOffsets[numFonts] = ftell(f);

    for (unsigned i = 0; i < numFonts; i++) {
        fseek(f, fileOffsets[i] + 1, SEEK_SET); // +1 skips the max width field.
        int thisPixHeight = fgetc(f);
        if (thisPixHeight == pixHeight) {
            fseek(f, fileOffsets[i], SEEK_SET);
            int fontBinSize = fileOffsets[i + 1] - fileOffsets[i];
            char *fontBuf = new char[fontBinSize];
            fread(fontBuf, 1, fontBinSize, f);
            DfFont *fnt = LoadFontFromMemory((unsigned int *)fontBuf, fontBinSize);
            delete[] fontBuf;
            return fnt;
        }
    }

    return NULL;
}

static int DrawTextSimpleClipped(DfFont *tr, DfColour col, DfBitmap *bmp, int _x, int y, char const *text, int maxChars)
{
    int x = _x;
    DfColour *startRow = bmp->pixels + y * bmp->width;
    int width = bmp->width;

    if (y + tr->charHeight < bmp->clipTop || y > bmp->clipBottom)
        return 0;

    for (int j = 0; text[j] && j < maxChars; j++)
    {
        if (x > bmp->clipRight)
            break;

        unsigned char c = text[j];
        Glyph *glyph = tr->glyphs[c];

        EncodedRun *rleBuf = glyph->m_pixelRuns;
        for (int i = 0; i < glyph->m_numRuns; i++)
        {
            int y3 = y + rleBuf->startY;
            if (y3 >= bmp->clipTop && y3 < bmp->clipBottom)
            {
                DfColour *thisRow = startRow + rleBuf->startY * width;
                for (unsigned i = 0; i < rleBuf->runLen; i++)
                {
                    int x3 = x + rleBuf->startX + i;
                    if (x3 >= bmp->clipLeft && x3 < bmp->clipRight)
                        thisRow[x3] = col;
                }
            }
            rleBuf++;
        }

        x += glyph->m_width;
    }

    return x - _x;
}

int DrawTextSimpleLen(DfFont *tr, DfColour col, DfBitmap *bmp, int _x, int y, char const *text, int maxChars)
{
    int x = _x;
    int width = bmp->width;

    if (x < bmp->clipLeft || y < bmp->clipTop || (y + tr->charHeight) > bmp->clipBottom)
        return DrawTextSimpleClipped(tr, col, bmp, _x, y, text, maxChars);

    DfColour *startRow = bmp->pixels + y * bmp->width;
    for (int j = 0; text[j] && j < maxChars; j++)
    {
        unsigned char c = text[j];
        if (x + (int)tr->glyphs[c]->m_width > bmp->clipRight)
            break;

        // Copy the glyph onto the stack for better cache performance. This increased the
        // performance from 13.8 to 14.4 million chars per second. Madness.
        Glyph glyph = *tr->glyphs[c];
        EncodedRun *rleBuf = glyph.m_pixelRuns;
        for (int i = 0; i < glyph.m_numRuns; i++)
        {
            DfColour *startPixel = startRow + rleBuf->startY * width + rleBuf->startX + x;
            for (unsigned i = 0; i < rleBuf->runLen; i++)
                startPixel[i] = col;
            rleBuf++;
        }

        x += glyph.m_width;
    }

    return x - _x;
}

int DrawTextSimple(DfFont *f, DfColour col, DfBitmap *bmp, int x, int y, char const *text)
{
    return DrawTextSimpleLen(f, col, bmp, x, y, text, 9999);
}

int DrawTextLeft(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);
    return DrawTextSimple(tr, c, bmp, x, y, buf);
}

int DrawTextRight(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);

    int width = GetTextWidth(tr, buf);
    return DrawTextSimple(tr, c, bmp, x - width, y, buf);
}

int DrawTextCentre(DfFont *tr, DfColour c, DfBitmap *bmp, int x, int y, char const *text, ...)
{
    char buf[512];
    va_list ap;
    va_start(ap, text);
    vsprintf(buf, text, ap);

    int width = GetTextWidth(tr, buf);
    return DrawTextSimple(tr, c, bmp, x - width/2, y, buf);
}

int GetTextWidth(DfFont *tr, char const *text, int len)
{
    len = IntMin((int)strlen(text), len);
    if (tr->fixedWidth)
    {
        return len * tr->maxCharWidth;
    }
    else
    {
        int width = 0;
        for (int i = 0; i < len; i++)
            width += tr->glyphs[text[i] & 0xff]->m_width;

        return width;
    }
}
<|endoftext|>