<commit_before>// ----------------------------------------------------
// $Maintainer: Marcel Schumann $
// $Authors: Marcel Schumann $
// ----------------------------------------------------

#include <BALL/SCORING/COMMON/scoringOptimizer.h>
#include <BALL/DOCKING/COMMON/structurePreparer.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/MOLFile.h>
#include <BALL/FORMAT/MOL2File.h>
#include <BALL/FORMAT/SDFile.h>

#include <BALL/SCORING/FUNCTIONS/MMScoring.h>
#include <BALL/SCORING/FUNCTIONS/PLPScoring.h>
#include <BALL/SCORING/FUNCTIONS/PBScoring.h>
#include <BALL/KERNEL/PTE.h>

using namespace BALL;
using namespace std;

static double getMean(const list<double>& v);
static double getCovariance(const list<double>& v1, const list<double>& v2, double mean1, double mean2);
static double getStddev(const list<double>& m, double mean);
static double getSumOfSquares(const list<double>& m, double mean);

ScoringOptimizer::ScoringOptimizer(Options& options, bool train)
{
	scoring_function_name_ = options.get("scoring_type");
	options_ = options;
	train_ = train;
}

void ScoringOptimizer::addComplex(String name, String receptor_file, String ligand_file, double binding_free_energy)
{
	Complex c;
	c.name = name;
	c.receptor_file = receptor_file;
	c.ligand_file = ligand_file;
	c.binding_free_energy = binding_free_energy;
	complexes_.push_back(c);
}

void ScoringOptimizer::evaluate(double* correlation, double* R2, double* RMSE, Size* no_valid_complexes)
{
	StructurePreparer sp;
	if (scoring_function_name_.hasSubstring("PLP"))
	{
		sp.setScoringType("PLP");
	}

	result_.predictions.clear();
	result_.target_names.clear();
	result_.expected_affinities.clear();
	result_.score_contributions.clear();
	result_.score_contribution_names.clear();

	Size skipped_complexes = 0;
	Size atom_overlaps = 0;
	Size ignored_outliers = 0;
	Size i = 0;
	double sum_squared_errors = 0;

	for (list < Complex > ::iterator it = complexes_.begin(); it != complexes_.end(); it++, i++)
	{
		cout<<"==== evaluating complex "<<i<<", "<<it->name<<" ========="<<endl;

		ScoringFunction* scoring_function = NULL;

		try
		{
			System ligand;
			Molecule* mol = 0;
			System receptor;
			PDBFile p(it->receptor_file);
			p >> receptor;
			String par_file = options_.get("filename");
			sp.prepare(&receptor, par_file);
			SDFile* sdf = 0;

			if (it->ligand_file.hasSubstring(".mol2"))
			{
				MOL2File m(it->ligand_file);
				m >> ligand;
			}
			else if (it->ligand_file.hasSubstring(".mol"))
			{
				MOLFile m(it->ligand_file);
				m >> ligand;
			}
			else if (it->ligand_file.hasSubstring(".sdf"))
			{
				sdf = new SDFile(it->ligand_file);
				mol = sdf->read();
				ligand.insert(*mol);
			}

			scoring_function = createScoringFunction(receptor, ligand);
			bool finished = 0;
			double threshold = 1000;
			if (!train_) threshold = 0;

			for (Size m = 0; !finished; m++)
			{
				sp.prepare(&ligand, par_file);

				if (train_) scoring_function->unsetTrainingParameters();

				scoring_function->setLigand(ligand); ///

				double score;

				scoring_function->update();
				score = scoring_function->updateScore();
				scoring_function->printResult(true);

// 				int heavy_atoms=0;
// 				for(AtomIterator ait=ligand.beginAtom();+ait;++ait)
// 				{
// 					if(ait->getElement().getSymbol()!="H")
// 					{
// 						heavy_atoms++;
// 					}
// 				}
// 				score = (1./(pow(heavy_atoms,1./3)))*score;

				if (score >= 0.99*1e10)
				{
					cout<<"Atom-overlaps found!! Ignoring this complex!"<<endl;
					atom_overlaps++;
					if (!sdf) break;
					else
					{
						//delete mol;
						mol = sdf->read();
						if (mol == 0) break;
						ligand.clear();
						ligand.insert(*mol);
						continue;
					}
				}

				if (score >= threshold)
				{
					cout<<"Score>="<<threshold<<", considering this complex as outlier and ignoring it!"<<endl;
					ignored_outliers++;
					if (!sdf) break;
					else
					{
						//delete mol;
						mol = sdf->read();
						if (mol == 0) break;
						ligand.clear();
						ligand.insert(*mol);
						continue;
					}
				}

				double binding_free_energy = it->binding_free_energy;
				if (sdf) binding_free_energy = String(mol->getProperty("binding free energy").getString()).toDouble();
				String name = it->name;
				if (sdf) name += ", "+String(m);

				result_.predictions.push_back(score);
				result_.expected_affinities.push_back(binding_free_energy);
				result_.target_names.push_back(name);
				sum_squared_errors += pow(score-binding_free_energy, 2);

				vector<double> v;
				result_.score_contributions.push_back(v);
				scoring_function->getScoreContributions(result_.score_contributions[result_.score_contributions.size()-1], result_.score_contribution_names);

				if (!sdf) finished = true;
				else
				{
					//delete mol;
					mol = sdf->read();
					if (mol == 0) break;
					ligand.clear();
					ligand.insert(*mol);
				}
			}
			delete sdf;
		}
		catch(BALL::Exception::GeneralException e)
		{
			cout<<e.getName()<<" : "<<e.getMessage()<<endl;
			cout<<"Error for this complex, skipping it!"<<endl;
			delete scoring_function;
			skipped_complexes++;
			continue;
		}

		delete scoring_function;
	}

	double mean_expected = getMean(result_.expected_affinities);
	double mean_predicted = getMean(result_.predictions);

	double covar = getCovariance(result_.expected_affinities, result_.predictions, mean_expected, mean_predicted);
	double stddev_expected = getStddev(result_.expected_affinities, mean_expected);
	double stddev_predicted = getStddev(result_.predictions, mean_predicted);

	double cor = covar/(stddev_expected*stddev_predicted);

	cout<<endl<<"number of skipped complexes="<<skipped_complexes<<endl<<endl;
	cout<<"number of ignored outliers="<<ignored_outliers<<endl;
	cout<<endl<<"number of complexes with atom overlaps="<<atom_overlaps<<endl<<endl;

	cout << "Correlation between score and experimentally determined affinity = "<<cor<<endl<<endl;

	double r2 = 1 - (sum_squared_errors/getSumOfSquares(result_.expected_affinities, mean_expected));
	cout<<"sum_squared_errors="<<sum_squared_errors<<endl;
	cout<<"sum_squared_response_meandev="<<getSumOfSquares(result_.expected_affinities, mean_expected)<<endl;

	*no_valid_complexes = result_.predictions.size();
	cout<<"N = "<<result_.predictions.size()<<endl;
	cout<<"R2 = "<<r2<<endl;
	double rmse = sqrt(sum_squared_errors/result_.predictions.size());
	cout<<"RMSE = "<<rmse<<endl;

	if (correlation != 0) *correlation = cor;
	if (R2 != 0) *R2 = r2;
	if (RMSE != 0) *RMSE = rmse;
}

const ScoringOptimizer::Result* ScoringOptimizer::getResult()
{
	return &result_;
}

void ScoringOptimizer::printMatrix(ostream& out)
{
	out<<"target name\t";
	for (Size i = 0; i < result_.score_contribution_names.size(); i++)
	{
		out<<result_.score_contribution_names[i]<<"\t";
	}
	out<<"binding free energy";
	out<<endl;

	list<String>::iterator it1 = result_.target_names.begin();
	list<double>::iterator it2 = result_.expected_affinities.begin();
	for (Size i = 0; i < result_.score_contributions.size(); i++, it1++, it2++) // for each evaluated complex
	{
		out<<*it1<<"\t"; //name
		for (Size j = 0; j < result_.score_contributions[i].size(); j++)
		{
			out<<result_.score_contributions[i][j]<<"\t";
		}

		out<<*it2<<endl; // exp. affinity
	}
	out<<endl;
}

ScoringFunction* ScoringOptimizer::createScoringFunction(System& receptor, System& ligand)
{
	ScoringFunction* scoring_function;

	if (scoring_function_name_ == "MM")
	{
		scoring_function = new MMScoring(receptor, ligand, options_);
	}
	else if (scoring_function_name_ == "PLP")
	{
		scoring_function = new PLPScoring(receptor, ligand, options_);
	}
	else if (scoring_function_name_ == "PB")
	{
		scoring_function = new PBScoring(receptor, ligand, options_);
	}
	else
	{
		String mess="ScoringFunction type \'"+scoring_function_name_+"\' unsupported!";
		throw Exception::GeneralException(__FILE__, __LINE__, "IMeedyDock error", mess);
	}

	return scoring_function;
}

double getMean(const list<double>& v)
{
	double sum = 0;
	for (list < double > ::const_iterator it = v.begin(); it != v.end(); it++)
	{
		sum += *it;
	}
	return sum/v.size();
}

double getCovariance(const list<double>& v1, const list<double>& v2, double mean1, double mean2)
{
	if (v1.size() != v2.size())
	{
		throw BALL::Exception::GeneralException(__FILE__, __LINE__, "getCovariance() error!", "Error within covariance calculation: lists have unequal length!");
	}

	if (mean1 == -1) mean1 = getMean(v1);
	if (mean2 == -1) mean2 = getMean(v2);
	double sum_of_squares = 0;

	list<double>::const_iterator it1 = v1.begin();
	list<double>::const_iterator it2 = v2.begin();
	for (; it1 != v1.end() && it2 != v2.end(); it1++, it2++)
	{
		sum_of_squares += (*it1-mean1)*(*it2-mean2);
	}
	return sum_of_squares/(v1.size()-1);
}

double getSumOfSquares(const list<double>& m, double mean)
{
	if (mean == -1) mean = getMean(m);
	double sum_of_squares = 0;

	for (list < double > ::const_iterator it = m.begin(); it != m.end(); it++)
	{
		sum_of_squares += pow(*it-mean, 2);
	}
	return sum_of_squares;
}

double getStddev(const list<double>& m, double mean)
{
	if (mean == -1) mean = getMean(m);
	double sum_of_squares = 0;

	for (list < double > ::const_iterator it = m.begin(); it != m.end(); it++)
	{
		sum_of_squares += pow(*it-mean, 2);
	}

	double var = sum_of_squares/(m.size()-1);
	return sqrt(var);
}
<commit_msg>Fix horrible numerical code in ScoringOptimizer<commit_after>// ----------------------------------------------------
// $Maintainer: Marcel Schumann $
// $Authors: Marcel Schumann $
// ----------------------------------------------------

#include <BALL/SCORING/COMMON/scoringOptimizer.h>
#include <BALL/DOCKING/COMMON/structurePreparer.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/MOLFile.h>
#include <BALL/FORMAT/MOL2File.h>
#include <BALL/FORMAT/SDFile.h>

#include <BALL/SCORING/FUNCTIONS/MMScoring.h>
#include <BALL/SCORING/FUNCTIONS/PLPScoring.h>
#include <BALL/SCORING/FUNCTIONS/PBScoring.h>
#include <BALL/KERNEL/PTE.h>

using namespace BALL;
using namespace std;

static double getMean(const list<double>& v);
static double getCovariance(const list<double>& v1, const list<double>& v2, double mean1, double mean2);
static double getStddev(const list<double>& m, double mean);
static double getSumOfSquares(const list<double>& m, double mean);

ScoringOptimizer::ScoringOptimizer(Options& options, bool train)
{
	scoring_function_name_ = options.get("scoring_type");
	options_ = options;
	train_ = train;
}

void ScoringOptimizer::addComplex(String name, String receptor_file, String ligand_file, double binding_free_energy)
{
	Complex c;
	c.name = name;
	c.receptor_file = receptor_file;
	c.ligand_file = ligand_file;
	c.binding_free_energy = binding_free_energy;
	complexes_.push_back(c);
}

void ScoringOptimizer::evaluate(double* correlation, double* R2, double* RMSE, Size* no_valid_complexes)
{
	StructurePreparer sp;
	if (scoring_function_name_.hasSubstring("PLP"))
	{
		sp.setScoringType("PLP");
	}

	result_.predictions.clear();
	result_.target_names.clear();
	result_.expected_affinities.clear();
	result_.score_contributions.clear();
	result_.score_contribution_names.clear();

	Size skipped_complexes = 0;
	Size atom_overlaps = 0;
	Size ignored_outliers = 0;
	Size i = 0;
	double sum_squared_errors = 0;

	for (list < Complex > ::iterator it = complexes_.begin(); it != complexes_.end(); it++, i++)
	{
		cout<<"==== evaluating complex "<<i<<", "<<it->name<<" ========="<<endl;

		ScoringFunction* scoring_function = NULL;

		try
		{
			System ligand;
			Molecule* mol = 0;
			System receptor;
			PDBFile p(it->receptor_file);
			p >> receptor;
			String par_file = options_.get("filename");
			sp.prepare(&receptor, par_file);
			SDFile* sdf = 0;

			if (it->ligand_file.hasSubstring(".mol2"))
			{
				MOL2File m(it->ligand_file);
				m >> ligand;
			}
			else if (it->ligand_file.hasSubstring(".mol"))
			{
				MOLFile m(it->ligand_file);
				m >> ligand;
			}
			else if (it->ligand_file.hasSubstring(".sdf"))
			{
				sdf = new SDFile(it->ligand_file);
				mol = sdf->read();
				ligand.insert(*mol);
			}

			scoring_function = createScoringFunction(receptor, ligand);
			bool finished = 0;
			double threshold = 1000;
			if (!train_) threshold = 0;

			for (Size m = 0; !finished; m++)
			{
				sp.prepare(&ligand, par_file);

				if (train_) scoring_function->unsetTrainingParameters();

				scoring_function->setLigand(ligand); ///

				double score;

				scoring_function->update();
				score = scoring_function->updateScore();
				scoring_function->printResult(true);

// 				int heavy_atoms=0;
// 				for(AtomIterator ait=ligand.beginAtom();+ait;++ait)
// 				{
// 					if(ait->getElement().getSymbol()!="H")
// 					{
// 						heavy_atoms++;
// 					}
// 				}
// 				score = (1./(pow(heavy_atoms,1./3)))*score;

				if (score >= 0.99*1e10)
				{
					cout<<"Atom-overlaps found!! Ignoring this complex!"<<endl;
					atom_overlaps++;
					if (!sdf) break;
					else
					{
						//delete mol;
						mol = sdf->read();
						if (mol == 0) break;
						ligand.clear();
						ligand.insert(*mol);
						continue;
					}
				}

				if (score >= threshold)
				{
					cout<<"Score>="<<threshold<<", considering this complex as outlier and ignoring it!"<<endl;
					ignored_outliers++;
					if (!sdf) break;
					else
					{
						//delete mol;
						mol = sdf->read();
						if (mol == 0) break;
						ligand.clear();
						ligand.insert(*mol);
						continue;
					}
				}

				double binding_free_energy = it->binding_free_energy;
				if (sdf) binding_free_energy = String(mol->getProperty("binding free energy").getString()).toDouble();
				String name = it->name;
				if (sdf) name += ", "+String(m);

				result_.predictions.push_back(score);
				result_.expected_affinities.push_back(binding_free_energy);
				result_.target_names.push_back(name);
				sum_squared_errors += pow(score-binding_free_energy, 2);

				vector<double> v;
				result_.score_contributions.push_back(v);
				scoring_function->getScoreContributions(result_.score_contributions[result_.score_contributions.size()-1], result_.score_contribution_names);

				if (!sdf) finished = true;
				else
				{
					//delete mol;
					mol = sdf->read();
					if (mol == 0) break;
					ligand.clear();
					ligand.insert(*mol);
				}
			}
			delete sdf;
		}
		catch(BALL::Exception::GeneralException e)
		{
			cout<<e.getName()<<" : "<<e.getMessage()<<endl;
			cout<<"Error for this complex, skipping it!"<<endl;
			delete scoring_function;
			skipped_complexes++;
			continue;
		}

		delete scoring_function;
	}

	double mean_expected = getMean(result_.expected_affinities);
	double mean_predicted = getMean(result_.predictions);

	double covar = getCovariance(result_.expected_affinities, result_.predictions, mean_expected, mean_predicted);
	double stddev_expected = getStddev(result_.expected_affinities, mean_expected);
	double stddev_predicted = getStddev(result_.predictions, mean_predicted);

	double cor = covar/(stddev_expected*stddev_predicted);

	cout<<endl<<"number of skipped complexes="<<skipped_complexes<<endl<<endl;
	cout<<"number of ignored outliers="<<ignored_outliers<<endl;
	cout<<endl<<"number of complexes with atom overlaps="<<atom_overlaps<<endl<<endl;

	cout << "Correlation between score and experimentally determined affinity = "<<cor<<endl<<endl;

	double r2 = 1 - (sum_squared_errors/getSumOfSquares(result_.expected_affinities, mean_expected));
	cout<<"sum_squared_errors="<<sum_squared_errors<<endl;
	cout<<"sum_squared_response_meandev="<<getSumOfSquares(result_.expected_affinities, mean_expected)<<endl;

	*no_valid_complexes = result_.predictions.size();
	cout<<"N = "<<result_.predictions.size()<<endl;
	cout<<"R2 = "<<r2<<endl;
	double rmse = sqrt(sum_squared_errors/result_.predictions.size());
	cout<<"RMSE = "<<rmse<<endl;

	if (correlation != 0) *correlation = cor;
	if (R2 != 0) *R2 = r2;
	if (RMSE != 0) *RMSE = rmse;
}

const ScoringOptimizer::Result* ScoringOptimizer::getResult()
{
	return &result_;
}

void ScoringOptimizer::printMatrix(ostream& out)
{
	out<<"target name\t";
	for (Size i = 0; i < result_.score_contribution_names.size(); i++)
	{
		out<<result_.score_contribution_names[i]<<"\t";
	}
	out<<"binding free energy";
	out<<endl;

	list<String>::iterator it1 = result_.target_names.begin();
	list<double>::iterator it2 = result_.expected_affinities.begin();
	for (Size i = 0; i < result_.score_contributions.size(); i++, it1++, it2++) // for each evaluated complex
	{
		out<<*it1<<"\t"; //name
		for (Size j = 0; j < result_.score_contributions[i].size(); j++)
		{
			out<<result_.score_contributions[i][j]<<"\t";
		}

		out<<*it2<<endl; // exp. affinity
	}
	out<<endl;
}

ScoringFunction* ScoringOptimizer::createScoringFunction(System& receptor, System& ligand)
{
	ScoringFunction* scoring_function;

	if (scoring_function_name_ == "MM")
	{
		scoring_function = new MMScoring(receptor, ligand, options_);
	}
	else if (scoring_function_name_ == "PLP")
	{
		scoring_function = new PLPScoring(receptor, ligand, options_);
	}
	else if (scoring_function_name_ == "PB")
	{
		scoring_function = new PBScoring(receptor, ligand, options_);
	}
	else
	{
		String mess="ScoringFunction type \'"+scoring_function_name_+"\' unsupported!";
		throw Exception::GeneralException(__FILE__, __LINE__, "IMeedyDock error", mess);
	}

	return scoring_function;
}

double getMean(const list<double>& v)
{
	double sum = 0;
	for (list < double > ::const_iterator it = v.begin(); it != v.end(); it++)
	{
		sum += *it;
	}
	return sum/v.size();
}

double getCovariance(const list<double>& v1, const list<double>& v2, double mean1, double mean2)
{
	if (v1.size() != v2.size())
	{
		throw BALL::Exception::GeneralException(__FILE__, __LINE__, "getCovariance() error!", "Error within covariance calculation: lists have unequal length!");
	}

	if (mean1 == -1) mean1 = getMean(v1);
	if (mean2 == -1) mean2 = getMean(v2);
	double sum_of_squares = 0;

	list<double>::const_iterator it1 = v1.begin();
	list<double>::const_iterator it2 = v2.begin();
	for (; it1 != v1.end() && it2 != v2.end(); it1++, it2++)
	{
		sum_of_squares += (*it1-mean1)*(*it2-mean2);
	}
	return sum_of_squares/(v1.size()-1);
}

/*
 * Compute the sum of squares using the compensated algorithm as described int
 * Chan et al. "UPDATING FORMULAE AND A PAIRWISE ALGORITHM FOR COMPUTING SAMPLE
 * VARIANCES", 1979
 */
void getSumOfSquaresHelper(const list<double>& m, double mean, double& sum_of_squares, double& compensate, size_t& size)
{
	if (mean == -1.0) mean = getMean(m);

	sum_of_squares = 0.0;
	compensate = 0.0;
	size = 0;

	for (list < double > ::const_iterator it = m.begin(); it != m.end(); it++)
	{
		double diff = *it - mean;
		compensate += diff;
		sum_of_squares += diff * diff;
		++size;
	}
}

double getSumOfSquares(const list<double>& m, double mean)
{
	double sum_of_squares = 0.0;
	double compensate = 0.0;
	size_t size = 0;

	getSumOfSquaresHelper(m, mean, sum_of_squares, compensate, size);

	if(size == 0)
	{
		return 0;
	}

	return sum_of_squares - compensate * compensate / size;
}

double getStddev(const list<double>& m, double mean)
{
	double sum_of_squares = 0.0;
	double compensate = 0.0;
	size_t size = 0;

	getSumOfSquaresHelper(m, mean, sum_of_squares, compensate, size);

	if(size <= 1)
	{
		return 0.0;
	}

	return sqrt((sum_of_squares - compensate * compensate / size) / (size - 1));
}
<|endoftext|>


<commit_before><commit_msg>Fixed compile error.<commit_after><|endoftext|>


<commit_before><commit_msg>レイヤーの不具合修正<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: streamwrap.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: fs $ $Date: 2001-05-30 11:32:19 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _UTL_STREAM_WRAPPER_HXX_
#include <unotools/streamwrap.hxx>
#endif

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

namespace utl
{

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;

//==================================================================
//= OInputStreamWrapper
//==================================================================
DBG_NAME(OInputStreamWrapper)
//------------------------------------------------------------------
OInputStreamWrapper::OInputStreamWrapper( SvStream& _rStream )
                 :m_pSvStream(&_rStream)
                 ,m_bSvStreamOwner(sal_False)
{
    DBG_CTOR(OInputStreamWrapper,NULL);

}

//------------------------------------------------------------------
OInputStreamWrapper::OInputStreamWrapper( SvStream* pStream, sal_Bool bOwner )
                 :m_pSvStream( pStream )
                 ,m_bSvStreamOwner( bOwner )
{
    DBG_CTOR(OInputStreamWrapper,NULL);

}

//------------------------------------------------------------------
OInputStreamWrapper::~OInputStreamWrapper()
{
    if( m_bSvStreamOwner )
        delete m_pSvStream;

    DBG_DTOR(OInputStreamWrapper,NULL);
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
                throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    checkConnected();

    if (nBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));

    ::osl::MutexGuard aGuard( m_aMutex );

    aData.realloc(nBytesToRead);

    sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
    checkError();

    // Wenn gelesene Zeichen < MaxLength, staruno::Sequence anpassen
    if (nRead < (sal_uInt32)nBytesToRead)
        aData.realloc( nRead );

    return nRead;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    checkError();

    if (nMaxBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));

    if (m_pSvStream->IsEof())
    {
        aData.realloc(0);
        return 0;
    }
    else
        return readBytes(aData, nMaxBytesToRead);
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamWrapper::skipBytes(sal_Int32 nBytesToSkip) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkError();

#ifdef DBG_UTIL
    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
#endif

    m_pSvStream->SeekRel(nBytesToSkip);
    checkError();

#ifdef DBG_UTIL
    nCurrentPos = m_pSvStream->Tell();
#endif
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::available() throw( stario::NotConnectedException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    checkError();

    sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
    m_pSvStream->Seek(nPos);
    checkError();

    return nAvailable;
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamWrapper::closeInput() throw( stario::NotConnectedException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    if (m_bSvStreamOwner)
        delete m_pSvStream;

    m_pSvStream = NULL;
}

//------------------------------------------------------------------------------
void OInputStreamWrapper::checkConnected() const
{
    if (!m_pSvStream)
        throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this)));
}

//------------------------------------------------------------------------------
void OInputStreamWrapper::checkError() const
{
    checkConnected();

    if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
        // TODO: really evaluate the error
        throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this)));
}

//==================================================================
//= OSeekableInputStreamWrapper
//==================================================================
//------------------------------------------------------------------------------
OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream& _rStream)
    :OInputStreamWrapper(_rStream)
{
}

//------------------------------------------------------------------------------
OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream* _pStream, sal_Bool _bOwner)
    :OInputStreamWrapper(_pStream, _bOwner)
{
}

//------------------------------------------------------------------------------
Any SAL_CALL OSeekableInputStreamWrapper::queryInterface( const Type& _rType ) throw (RuntimeException)
{
    Any aReturn = OInputStreamWrapper::queryInterface(_rType);
    if (!aReturn.hasValue())
        aReturn = OSeekableInputStreamWrapper_Base::queryInterface(_rType);
    return aReturn;
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::acquire(  ) throw ()
{
    OInputStreamWrapper::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::release(  ) throw ()
{
    OInputStreamWrapper::release();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    m_pSvStream->Seek((sal_uInt32)_nLocation);
    checkError();
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getPosition(  ) throw (IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();
    return (sal_Int64)nPos;
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getLength(  ) throw (IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    sal_uInt32 nEndPos = m_pSvStream->Tell();
    m_pSvStream->Seek(nCurrentPos);

    checkError();

    return (sal_Int64)nEndPos;
}

//==================================================================
//= OOutputStreamWrapper
//==================================================================
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    sal_uInt32 nWritten = rStream.Write(aData.getConstArray(),aData.getLength());
    ErrCode err = rStream.GetError();
    if  (   (ERRCODE_NONE != err)
        ||  (nWritten != (sal_uInt32)aData.getLength())
        )
    {
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
    }
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::flush() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    rStream.Flush();
    if (rStream.GetError() != ERRCODE_NONE)
        throw stario::NotConnectedException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::closeOutput() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
}

} // namespace utl

<commit_msg>INTEGRATION: CWS dba14 (1.3.192); FILE MERGED 2004/07/15 15:04:24 fs 1.3.192.1: #i31536# +OSeekableOutputStreamWrapper<commit_after>/*************************************************************************
 *
 *  $RCSfile: streamwrap.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-23 10:44:08 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _UTL_STREAM_WRAPPER_HXX_
#include <unotools/streamwrap.hxx>
#endif

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

namespace utl
{

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;

//==================================================================
//= OInputStreamWrapper
//==================================================================
DBG_NAME(OInputStreamWrapper)
//------------------------------------------------------------------
OInputStreamWrapper::OInputStreamWrapper( SvStream& _rStream )
                 :m_pSvStream(&_rStream)
                 ,m_bSvStreamOwner(sal_False)
{
    DBG_CTOR(OInputStreamWrapper,NULL);

}

//------------------------------------------------------------------
OInputStreamWrapper::OInputStreamWrapper( SvStream* pStream, sal_Bool bOwner )
                 :m_pSvStream( pStream )
                 ,m_bSvStreamOwner( bOwner )
{
    DBG_CTOR(OInputStreamWrapper,NULL);

}

//------------------------------------------------------------------
OInputStreamWrapper::~OInputStreamWrapper()
{
    if( m_bSvStreamOwner )
        delete m_pSvStream;

    DBG_DTOR(OInputStreamWrapper,NULL);
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
                throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    checkConnected();

    if (nBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));

    ::osl::MutexGuard aGuard( m_aMutex );

    aData.realloc(nBytesToRead);

    sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
    checkError();

    // Wenn gelesene Zeichen < MaxLength, staruno::Sequence anpassen
    if (nRead < (sal_uInt32)nBytesToRead)
        aData.realloc( nRead );

    return nRead;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    checkError();

    if (nMaxBytesToRead < 0)
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));

    if (m_pSvStream->IsEof())
    {
        aData.realloc(0);
        return 0;
    }
    else
        return readBytes(aData, nMaxBytesToRead);
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamWrapper::skipBytes(sal_Int32 nBytesToSkip) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkError();

#ifdef DBG_UTIL
    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
#endif

    m_pSvStream->SeekRel(nBytesToSkip);
    checkError();

#ifdef DBG_UTIL
    nCurrentPos = m_pSvStream->Tell();
#endif
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL OInputStreamWrapper::available() throw( stario::NotConnectedException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    checkError();

    sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
    m_pSvStream->Seek(nPos);
    checkError();

    return nAvailable;
}

//------------------------------------------------------------------------------
void SAL_CALL OInputStreamWrapper::closeInput() throw( stario::NotConnectedException, staruno::RuntimeException )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    if (m_bSvStreamOwner)
        delete m_pSvStream;

    m_pSvStream = NULL;
}

//------------------------------------------------------------------------------
void OInputStreamWrapper::checkConnected() const
{
    if (!m_pSvStream)
        throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this)));
}

//------------------------------------------------------------------------------
void OInputStreamWrapper::checkError() const
{
    checkConnected();

    if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
        // TODO: really evaluate the error
        throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this)));
}

//==================================================================
//= OSeekableInputStreamWrapper
//==================================================================
//------------------------------------------------------------------------------
OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream& _rStream)
    :OInputStreamWrapper(_rStream)
{
}

//------------------------------------------------------------------------------
OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream* _pStream, sal_Bool _bOwner)
    :OInputStreamWrapper(_pStream, _bOwner)
{
}

//------------------------------------------------------------------------------
Any SAL_CALL OSeekableInputStreamWrapper::queryInterface( const Type& _rType ) throw (RuntimeException)
{
    Any aReturn = OInputStreamWrapper::queryInterface(_rType);
    if (!aReturn.hasValue())
        aReturn = OSeekableInputStreamWrapper_Base::queryInterface(_rType);
    return aReturn;
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::acquire(  ) throw ()
{
    OInputStreamWrapper::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::release(  ) throw ()
{
    OInputStreamWrapper::release();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableInputStreamWrapper::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    m_pSvStream->Seek((sal_uInt32)_nLocation);
    checkError();
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getPosition(  ) throw (IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();
    return (sal_Int64)nPos;
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getLength(  ) throw (IOException, RuntimeException)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    sal_uInt32 nEndPos = m_pSvStream->Tell();
    m_pSvStream->Seek(nCurrentPos);

    checkError();

    return (sal_Int64)nEndPos;
}

//==================================================================
//= OOutputStreamWrapper
//==================================================================
//------------------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    sal_uInt32 nWritten = rStream.Write(aData.getConstArray(),aData.getLength());
    ErrCode err = rStream.GetError();
    if  (   (ERRCODE_NONE != err)
        ||  (nWritten != (sal_uInt32)aData.getLength())
        )
    {
        throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this));
    }
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::flush() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
    rStream.Flush();
    checkError();
}

//------------------------------------------------------------------
void SAL_CALL OOutputStreamWrapper::closeOutput() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException )
{
}

//------------------------------------------------------------------------------
void OOutputStreamWrapper::checkError() const
{
    if (rStream.GetError() != ERRCODE_NONE)
        // TODO: really evaluate the error
        throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this)));
}

//==================================================================
//= OSeekableOutputStreamWrapper
//==================================================================
//------------------------------------------------------------------------------
OSeekableOutputStreamWrapper::OSeekableOutputStreamWrapper(SvStream& _rStream)
    :OOutputStreamWrapper(_rStream)
{
}

//------------------------------------------------------------------------------
Any SAL_CALL OSeekableOutputStreamWrapper::queryInterface( const Type& _rType ) throw (RuntimeException)
{
    Any aReturn = OOutputStreamWrapper::queryInterface(_rType);
    if (!aReturn.hasValue())
        aReturn = OSeekableOutputStreamWrapper_Base::queryInterface(_rType);
    return aReturn;
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableOutputStreamWrapper::acquire(  ) throw ()
{
    OOutputStreamWrapper::acquire();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableOutputStreamWrapper::release(  ) throw ()
{
    OOutputStreamWrapper::release();
}

//------------------------------------------------------------------------------
void SAL_CALL OSeekableOutputStreamWrapper::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
{
    rStream.Seek((sal_uInt32)_nLocation);
    checkError();
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableOutputStreamWrapper::getPosition(  ) throw (IOException, RuntimeException)
{
    sal_uInt32 nPos = rStream.Tell();
    checkError();
    return (sal_Int64)nPos;
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL OSeekableOutputStreamWrapper::getLength(  ) throw (IOException, RuntimeException)
{
    sal_uInt32 nCurrentPos = rStream.Tell();
    checkError();

    rStream.Seek(STREAM_SEEK_TO_END);
    sal_uInt32 nEndPos = rStream.Tell();
    rStream.Seek(nCurrentPos);

    checkError();

    return (sal_Int64)nEndPos;
}

} // namespace utl

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/rendering/RenderGeometryMap.h"

#include "core/frame/LocalFrame.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
#include "platform/geometry/TransformState.h"
#include "wtf/TemporaryChange.h"

namespace WebCore {

RenderGeometryMap::RenderGeometryMap(MapCoordinatesFlags flags)
    : m_insertionPosition(kNotFound)
    , m_nonUniformStepsCount(0)
    , m_transformedStepsCount(0)
    , m_fixedStepsCount(0)
    , m_mapCoordinatesFlags(flags)
{
}

RenderGeometryMap::~RenderGeometryMap()
{
}

void RenderGeometryMap::mapToContainer(TransformState& transformState, const RenderLayerModelObject* container) const
{
    // If the mapping includes something like columns, we have to go via renderers.
    if (hasNonUniformStep()) {
        m_mapping.last().m_renderer->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags);
        transformState.flatten();
        return;
    }

    bool inFixed = false;
#if !ASSERT_DISABLED
    bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_renderer == container);
#endif

    for (int i = m_mapping.size() - 1; i >= 0; --i) {
        const RenderGeometryMapStep& currentStep = m_mapping[i];

        // If container is the root RenderView (step 0) we want to apply its fixed position offset.
        if (i > 0 && currentStep.m_renderer == container) {
#if !ASSERT_DISABLED
            foundContainer = true;
#endif
            break;
        }

        // If this box has a transform, it acts as a fixed position container
        // for fixed descendants, which prevents the propagation of 'fixed'
        // unless the layer itself is also fixed position.
        if (i && currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
            inFixed = false;
        else if (currentStep.m_isFixedPosition)
            inFixed = true;

        ASSERT(!i == isTopmostRenderView(currentStep.m_renderer));

        if (!i) {
            // A null container indicates mapping through the root RenderView, so including its transform (the page scale).
            if (!container && currentStep.m_transform)
                transformState.applyTransform(*currentStep.m_transform.get());
        } else {
            TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
            if (currentStep.m_transform)
                transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
            else
                transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
        }

        if (inFixed && !currentStep.m_offsetForFixedPosition.isZero()) {
            ASSERT(currentStep.m_renderer->isRenderView());
            transformState.move(currentStep.m_offsetForFixedPosition);
        }
    }

    ASSERT(foundContainer);
    transformState.flatten();
}

FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLayerModelObject* container) const
{
    FloatPoint result;

    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer)))
        result = p + m_accumulatedOffset;
    else {
        TransformState transformState(TransformState::ApplyTransformDirection, p);
        mapToContainer(transformState, container);
        result = transformState.lastPlanarPoint();
    }

#if !ASSERT_DISABLED
    if (m_mapping.size() > 0) {
        const RenderObject* lastRenderer = m_mapping.last().m_renderer;
        const RenderLayer* layer = lastRenderer->enclosingLayer();

        // Bounds for invisible layers are intentionally not calculated, and are
        // therefore not necessarily expected to be correct here. This is ok,
        // because they will be recomputed if the layer becomes visible.
        if (!layer || !layer->subtreeIsInvisible()) {
            FloatPoint rendererMappedResult = lastRenderer->localToAbsolute(p, m_mapCoordinatesFlags);

            ASSERT(roundedIntPoint(rendererMappedResult) == roundedIntPoint(result));
        }
    }
#endif

    return result;
}

#ifndef NDEBUG
// Handy function to call from gdb while debugging mismatched point/rect errors.
void RenderGeometryMap::dumpSteps() const
{
    fprintf(stderr, "RenderGeometryMap::dumpSteps accumulatedOffset=%d,%d\n", m_accumulatedOffset.width().toInt(), m_accumulatedOffset.height().toInt());
    for (int i = m_mapping.size() - 1; i >= 0; --i) {
        fprintf(stderr, " [%d] %s: offset=%d,%d", i, m_mapping[i].m_renderer->debugName().ascii().data(), m_mapping[i].m_offset.width().toInt(), m_mapping[i].m_offset.height().toInt());
        if (m_mapping[i].m_hasTransform)
            fprintf(stderr, " hasTransform");
        fprintf(stderr, "\n");
    }
}
#endif

FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const
{
    FloatRect result;

    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) {
        result = rect;
        result.move(m_accumulatedOffset);
    } else {
        TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
        mapToContainer(transformState, container);
        result = transformState.lastPlanarQuad().boundingBox();
    }

#if !ASSERT_DISABLED
    if (m_mapping.size() > 0) {
        const RenderObject* lastRenderer = m_mapping.last().m_renderer;
        const RenderLayer* layer = lastRenderer->enclosingLayer();

        // Bounds for invisible layers are intentionally not calculated, and are
        // therefore not necessarily expected to be correct here. This is ok,
        // because they will be recomputed if the layer becomes visible.
        if (!layer->subtreeIsInvisible() && lastRenderer->style()->visibility() == VISIBLE) {
            FloatRect rendererMappedResult = lastRenderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox();

            // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
            // Taking FloatQuad bounds avoids spurious assertions because of that.
            ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox()));
        }
    }
#endif

    return result;
}

void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderLayerModelObject* ancestorRenderer)
{
    // We need to push mappings in reverse order here, so do insertions rather than appends.
    TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
    do {
        renderer = renderer->pushMappingToContainer(ancestorRenderer, *this);
    } while (renderer && renderer != ancestorRenderer);

    ASSERT(m_mapping.isEmpty() || isTopmostRenderView(m_mapping[0].m_renderer));
}

static bool canMapBetweenRenderers(const RenderObject* renderer, const RenderObject* ancestor)
{
    for (const RenderObject* current = renderer; ; current = current->parent()) {
        const RenderStyle* style = current->style();
        if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode())
            return false;

        if (current->hasColumns() || current->hasTransform() || current->isRenderFlowThread() || current->isSVGRoot())
            return false;

        if (current == ancestor)
            break;
    }

    return true;
}

void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer)
{
    const RenderObject* renderer = layer->renderer();

    bool crossDocument = ancestorLayer && layer->renderer()->frame() != ancestorLayer->renderer()->frame();
    ASSERT(!crossDocument || m_mapCoordinatesFlags & TraverseDocumentBoundaries);

    // We have to visit all the renderers to detect flipped blocks. This might defeat the gains
    // from mapping via layers.
    bool canConvertInLayerTree = (ancestorLayer && !crossDocument) ? canMapBetweenRenderers(layer->renderer(), ancestorLayer->renderer()) : false;

//    fprintf(stderr, "RenderGeometryMap::pushMappingsToAncestor from layer %p to layer %p, canConvertInLayerTree=%d\n", layer, ancestorLayer, canConvertInLayerTree);

    if (canConvertInLayerTree) {
        LayoutPoint layerOffset;
        layer->convertToLayerCoords(ancestorLayer, layerOffset);

        // The RenderView must be pushed first.
        if (!m_mapping.size()) {
            ASSERT(ancestorLayer->renderer()->isRenderView());
            pushMappingsToAncestor(ancestorLayer->renderer(), 0);
        }

        TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
        push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false);
        return;
    }
    const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
    pushMappingsToAncestor(renderer, ancestorRenderer);
}

void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
{
//    fprintf(stderr, "RenderGeometryMap::push %p %d,%d isNonUniform=%d\n", renderer, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform);

    ASSERT(m_insertionPosition != kNotFound);
    ASSERT(!renderer->isRenderView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
    ASSERT(offsetForFixedPosition.isZero() || renderer->isRenderView());

    m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));

    RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
    step.m_offset = offsetFromContainer;
    step.m_offsetForFixedPosition = offsetForFixedPosition;

    stepInserted(step);
}

void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
{
    ASSERT(m_insertionPosition != kNotFound);
    ASSERT(!renderer->isRenderView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
    ASSERT(offsetForFixedPosition.isZero() || renderer->isRenderView());

    m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));

    RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
    step.m_offsetForFixedPosition = offsetForFixedPosition;

    if (!t.isIntegerTranslation())
        step.m_transform = adoptPtr(new TransformationMatrix(t));
    else
        step.m_offset = LayoutSize(t.e(), t.f());

    stepInserted(step);
}

void RenderGeometryMap::popMappingsToAncestor(const RenderLayerModelObject* ancestorRenderer)
{
    ASSERT(m_mapping.size());

    while (m_mapping.size() && m_mapping.last().m_renderer != ancestorRenderer) {
        stepRemoved(m_mapping.last());
        m_mapping.removeLast();
    }
}

void RenderGeometryMap::popMappingsToAncestor(const RenderLayer* ancestorLayer)
{
    const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
    popMappingsToAncestor(ancestorRenderer);
}

void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step)
{
    m_accumulatedOffset += step.m_offset;

    if (step.m_isNonUniform)
        ++m_nonUniformStepsCount;

    if (step.m_transform)
        ++m_transformedStepsCount;

    if (step.m_isFixedPosition)
        ++m_fixedStepsCount;
}

void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step)
{
    m_accumulatedOffset -= step.m_offset;

    if (step.m_isNonUniform) {
        ASSERT(m_nonUniformStepsCount);
        --m_nonUniformStepsCount;
    }

    if (step.m_transform) {
        ASSERT(m_transformedStepsCount);
        --m_transformedStepsCount;
    }

    if (step.m_isFixedPosition) {
        ASSERT(m_fixedStepsCount);
        --m_fixedStepsCount;
    }
}

#if !ASSERT_DISABLED
bool RenderGeometryMap::isTopmostRenderView(const RenderObject* renderer) const
{
    if (!renderer->isRenderView())
        return false;

    // If we're not working with multiple RenderViews, then any view is considered
    // "topmost" (to preserve original behavior).
    if (!(m_mapCoordinatesFlags & TraverseDocumentBoundaries))
        return true;

    return renderer->frame()->isMainFrame();
}
#endif

} // namespace WebCore
<commit_msg>Use localToContainerPoint when checking mapToContainer result<commit_after>/*
 * Copyright (C) 2012 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/rendering/RenderGeometryMap.h"

#include "core/frame/LocalFrame.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
#include "platform/geometry/TransformState.h"
#include "wtf/TemporaryChange.h"

namespace WebCore {

RenderGeometryMap::RenderGeometryMap(MapCoordinatesFlags flags)
    : m_insertionPosition(kNotFound)
    , m_nonUniformStepsCount(0)
    , m_transformedStepsCount(0)
    , m_fixedStepsCount(0)
    , m_mapCoordinatesFlags(flags)
{
}

RenderGeometryMap::~RenderGeometryMap()
{
}

void RenderGeometryMap::mapToContainer(TransformState& transformState, const RenderLayerModelObject* container) const
{
    // If the mapping includes something like columns, we have to go via renderers.
    if (hasNonUniformStep()) {
        m_mapping.last().m_renderer->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags);
        transformState.flatten();
        return;
    }

    bool inFixed = false;
#if !ASSERT_DISABLED
    bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_renderer == container);
#endif

    for (int i = m_mapping.size() - 1; i >= 0; --i) {
        const RenderGeometryMapStep& currentStep = m_mapping[i];

        // If container is the root RenderView (step 0) we want to apply its fixed position offset.
        if (i > 0 && currentStep.m_renderer == container) {
#if !ASSERT_DISABLED
            foundContainer = true;
#endif
            break;
        }

        // If this box has a transform, it acts as a fixed position container
        // for fixed descendants, which prevents the propagation of 'fixed'
        // unless the layer itself is also fixed position.
        if (i && currentStep.m_hasTransform && !currentStep.m_isFixedPosition)
            inFixed = false;
        else if (currentStep.m_isFixedPosition)
            inFixed = true;

        ASSERT(!i == isTopmostRenderView(currentStep.m_renderer));

        if (!i) {
            // A null container indicates mapping through the root RenderView, so including its transform (the page scale).
            if (!container && currentStep.m_transform)
                transformState.applyTransform(*currentStep.m_transform.get());
        } else {
            TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
            if (currentStep.m_transform)
                transformState.applyTransform(*currentStep.m_transform.get(), accumulate);
            else
                transformState.move(currentStep.m_offset.width(), currentStep.m_offset.height(), accumulate);
        }

        if (inFixed && !currentStep.m_offsetForFixedPosition.isZero()) {
            ASSERT(currentStep.m_renderer->isRenderView());
            transformState.move(currentStep.m_offsetForFixedPosition);
        }
    }

    ASSERT(foundContainer);
    transformState.flatten();
}

FloatPoint RenderGeometryMap::mapToContainer(const FloatPoint& p, const RenderLayerModelObject* container) const
{
    FloatPoint result;

    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer)))
        result = p + m_accumulatedOffset;
    else {
        TransformState transformState(TransformState::ApplyTransformDirection, p);
        mapToContainer(transformState, container);
        result = transformState.lastPlanarPoint();
    }

#if !ASSERT_DISABLED
    if (m_mapping.size() > 0) {
        const RenderObject* lastRenderer = m_mapping.last().m_renderer;
        const RenderLayer* layer = lastRenderer->enclosingLayer();

        // Bounds for invisible layers are intentionally not calculated, and are
        // therefore not necessarily expected to be correct here. This is ok,
        // because they will be recomputed if the layer becomes visible.
        if (!layer || !layer->subtreeIsInvisible()) {
            FloatPoint rendererMappedResult = lastRenderer->localToContainerPoint(p, container, m_mapCoordinatesFlags);

            ASSERT(roundedIntPoint(rendererMappedResult) == roundedIntPoint(result));
        }
    }
#endif

    return result;
}

#ifndef NDEBUG
// Handy function to call from gdb while debugging mismatched point/rect errors.
void RenderGeometryMap::dumpSteps() const
{
    fprintf(stderr, "RenderGeometryMap::dumpSteps accumulatedOffset=%d,%d\n", m_accumulatedOffset.width().toInt(), m_accumulatedOffset.height().toInt());
    for (int i = m_mapping.size() - 1; i >= 0; --i) {
        fprintf(stderr, " [%d] %s: offset=%d,%d", i, m_mapping[i].m_renderer->debugName().ascii().data(), m_mapping[i].m_offset.width().toInt(), m_mapping[i].m_offset.height().toInt());
        if (m_mapping[i].m_hasTransform)
            fprintf(stderr, " hasTransform");
        fprintf(stderr, "\n");
    }
}
#endif

FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const
{
    FloatRect result;

    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) {
        result = rect;
        result.move(m_accumulatedOffset);
    } else {
        TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
        mapToContainer(transformState, container);
        result = transformState.lastPlanarQuad().boundingBox();
    }

#if !ASSERT_DISABLED
    if (m_mapping.size() > 0) {
        const RenderObject* lastRenderer = m_mapping.last().m_renderer;
        const RenderLayer* layer = lastRenderer->enclosingLayer();

        // Bounds for invisible layers are intentionally not calculated, and are
        // therefore not necessarily expected to be correct here. This is ok,
        // because they will be recomputed if the layer becomes visible.
        if (!layer->subtreeIsInvisible() && lastRenderer->style()->visibility() == VISIBLE) {
            FloatRect rendererMappedResult = lastRenderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox();

            // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
            // Taking FloatQuad bounds avoids spurious assertions because of that.
            ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox()));
        }
    }
#endif

    return result;
}

void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderLayerModelObject* ancestorRenderer)
{
    // We need to push mappings in reverse order here, so do insertions rather than appends.
    TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
    do {
        renderer = renderer->pushMappingToContainer(ancestorRenderer, *this);
    } while (renderer && renderer != ancestorRenderer);

    ASSERT(m_mapping.isEmpty() || isTopmostRenderView(m_mapping[0].m_renderer));
}

static bool canMapBetweenRenderers(const RenderObject* renderer, const RenderObject* ancestor)
{
    for (const RenderObject* current = renderer; ; current = current->parent()) {
        const RenderStyle* style = current->style();
        if (style->position() == FixedPosition || style->isFlippedBlocksWritingMode())
            return false;

        if (current->hasColumns() || current->hasTransform() || current->isRenderFlowThread() || current->isSVGRoot())
            return false;

        if (current == ancestor)
            break;
    }

    return true;
}

void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer)
{
    const RenderObject* renderer = layer->renderer();

    bool crossDocument = ancestorLayer && layer->renderer()->frame() != ancestorLayer->renderer()->frame();
    ASSERT(!crossDocument || m_mapCoordinatesFlags & TraverseDocumentBoundaries);

    // We have to visit all the renderers to detect flipped blocks. This might defeat the gains
    // from mapping via layers.
    bool canConvertInLayerTree = (ancestorLayer && !crossDocument) ? canMapBetweenRenderers(layer->renderer(), ancestorLayer->renderer()) : false;

//    fprintf(stderr, "RenderGeometryMap::pushMappingsToAncestor from layer %p to layer %p, canConvertInLayerTree=%d\n", layer, ancestorLayer, canConvertInLayerTree);

    if (canConvertInLayerTree) {
        LayoutPoint layerOffset;
        layer->convertToLayerCoords(ancestorLayer, layerOffset);

        // The RenderView must be pushed first.
        if (!m_mapping.size()) {
            ASSERT(ancestorLayer->renderer()->isRenderView());
            pushMappingsToAncestor(ancestorLayer->renderer(), 0);
        }

        TemporaryChange<size_t> positionChange(m_insertionPosition, m_mapping.size());
        push(renderer, toLayoutSize(layerOffset), /*accumulatingTransform*/ true, /*isNonUniform*/ false, /*isFixedPosition*/ false, /*hasTransform*/ false);
        return;
    }
    const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
    pushMappingsToAncestor(renderer, ancestorRenderer);
}

void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
{
//    fprintf(stderr, "RenderGeometryMap::push %p %d,%d isNonUniform=%d\n", renderer, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform);

    ASSERT(m_insertionPosition != kNotFound);
    ASSERT(!renderer->isRenderView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
    ASSERT(offsetForFixedPosition.isZero() || renderer->isRenderView());

    m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));

    RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
    step.m_offset = offsetFromContainer;
    step.m_offsetForFixedPosition = offsetForFixedPosition;

    stepInserted(step);
}

void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition)
{
    ASSERT(m_insertionPosition != kNotFound);
    ASSERT(!renderer->isRenderView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries);
    ASSERT(offsetForFixedPosition.isZero() || renderer->isRenderView());

    m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform));

    RenderGeometryMapStep& step = m_mapping[m_insertionPosition];
    step.m_offsetForFixedPosition = offsetForFixedPosition;

    if (!t.isIntegerTranslation())
        step.m_transform = adoptPtr(new TransformationMatrix(t));
    else
        step.m_offset = LayoutSize(t.e(), t.f());

    stepInserted(step);
}

void RenderGeometryMap::popMappingsToAncestor(const RenderLayerModelObject* ancestorRenderer)
{
    ASSERT(m_mapping.size());

    while (m_mapping.size() && m_mapping.last().m_renderer != ancestorRenderer) {
        stepRemoved(m_mapping.last());
        m_mapping.removeLast();
    }
}

void RenderGeometryMap::popMappingsToAncestor(const RenderLayer* ancestorLayer)
{
    const RenderLayerModelObject* ancestorRenderer = ancestorLayer ? ancestorLayer->renderer() : 0;
    popMappingsToAncestor(ancestorRenderer);
}

void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step)
{
    m_accumulatedOffset += step.m_offset;

    if (step.m_isNonUniform)
        ++m_nonUniformStepsCount;

    if (step.m_transform)
        ++m_transformedStepsCount;

    if (step.m_isFixedPosition)
        ++m_fixedStepsCount;
}

void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step)
{
    m_accumulatedOffset -= step.m_offset;

    if (step.m_isNonUniform) {
        ASSERT(m_nonUniformStepsCount);
        --m_nonUniformStepsCount;
    }

    if (step.m_transform) {
        ASSERT(m_transformedStepsCount);
        --m_transformedStepsCount;
    }

    if (step.m_isFixedPosition) {
        ASSERT(m_fixedStepsCount);
        --m_fixedStepsCount;
    }
}

#if !ASSERT_DISABLED
bool RenderGeometryMap::isTopmostRenderView(const RenderObject* renderer) const
{
    if (!renderer->isRenderView())
        return false;

    // If we're not working with multiple RenderViews, then any view is considered
    // "topmost" (to preserve original behavior).
    if (!(m_mapCoordinatesFlags & TraverseDocumentBoundaries))
        return true;

    return renderer->frame()->isMainFrame();
}
#endif

} // namespace WebCore
<|endoftext|>


<commit_before>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "TelepathyQt4/simple-stream-tube-handler.h"

#include "TelepathyQt4/_gen/simple-stream-tube-handler.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/Account>
#include <TelepathyQt4/ChannelClassSpec>
#include <TelepathyQt4/PendingComposite>
#include <TelepathyQt4/PendingReady>
#include <TelepathyQt4/StreamTubeChannel>

namespace Tp
{

namespace
{
    ChannelClassSpecList buildFilter(const QStringList &p2pServices,
            const QStringList &roomServices, bool requested)
    {
        ChannelClassSpecList filter;

        foreach (const QString &service, p2pServices)
        {
            filter.append(requested ?
                    ChannelClassSpec::outgoingStreamTube(service) :
                    ChannelClassSpec::incomingStreamTube(service));
        }

        foreach (const QString &service, roomServices)
        {
            filter.append(requested ?
                    ChannelClassSpec::outgoingRoomStreamTube(service) :
                    ChannelClassSpec::incomingRoomStreamTube(service));
        }

        return filter;
    }
}

SharedPtr<SimpleStreamTubeHandler> SimpleStreamTubeHandler::create(
        const QStringList &p2pServices,
        const QStringList &roomServices,
        bool requested,
        bool monitorConnections,
        bool bypassApproval)
{
    return SharedPtr<SimpleStreamTubeHandler>(
            new SimpleStreamTubeHandler(
                p2pServices,
                roomServices,
                requested,
                monitorConnections,
                bypassApproval));
}

SimpleStreamTubeHandler::SimpleStreamTubeHandler(
        const QStringList &p2pServices,
        const QStringList &roomServices,
        bool requested,
        bool monitorConnections,
        bool bypassApproval)
: AbstractClient(),
    AbstractClientHandler(buildFilter(p2pServices, roomServices, requested)),
    mMonitorConnections(monitorConnections),
    mBypassApproval(bypassApproval)
{
}

SimpleStreamTubeHandler::~SimpleStreamTubeHandler()
{
    if (!mTubes.empty()) {
        debug() << "~SSTubeHandler(): Closing" << mTubes.size() << "leftover tubes";

        foreach (const StreamTubeChannelPtr &tube, mTubes.keys()) {
            tube->requestClose();
        }
    }
}

void SimpleStreamTubeHandler::handleChannels(
        const MethodInvocationContextPtr<> &context,
        const AccountPtr &account,
        const ConnectionPtr &connection,
        const QList<ChannelPtr> &channels,
        const QList<ChannelRequestPtr> &requestsSatisfied,
        const QDateTime &userActionTime,
        const HandlerInfo &handlerInfo)
{
    debug() << "SimpleStreamTubeHandler::handleChannels() invoked for " <<
        channels.size() << "channels on account" << account->objectPath();

    SharedPtr<InvocationData> invocation(new InvocationData());
    QList<PendingOperation *> readyOps;

    foreach (const ChannelPtr &chan, channels) {
        StreamTubeChannelPtr tube = StreamTubeChannelPtr::qObjectCast(chan);

        if (!tube) {
            const QString channelType =
                chan->immutableProperties()[QLatin1String(
                        TELEPATHY_INTERFACE_CHANNEL ".ChannelType")].toString();

            if (channelType != TP_QT4_IFACE_CHANNEL_TYPE_STREAM_TUBE) {
                debug() << "We got a non-StreamTube channel" << chan->objectPath() <<
                    "of type" << channelType << ", ignoring";
            } else {
                warning() << "The channel factory used for a simple StreamTube handler must" <<
                    "construct StreamTubeChannel subclasses for stream tubes";
            }
            continue;
        }

        Features features = StreamTubeChannel::FeatureStreamTube;
        if (mMonitorConnections) {
            features.insert(StreamTubeChannel::FeatureConnectionMonitoring);
        }
        readyOps.append(tube->becomeReady(features));

        invocation->tubes.append(tube);
    }

    invocation->ctx = context;
    invocation->acc = account;
    invocation->time = userActionTime;

    if (!requestsSatisfied.isEmpty()) {
        invocation->hints = requestsSatisfied.first()->hints();
    }

    mInvocations.append(invocation);

    if (invocation->tubes.isEmpty()) {
        warning() << "SSTH::HandleChannels got no suitable channels, admitting we're Confused";
        invocation->readyOp = 0;
        invocation->error = TP_QT4_ERROR_CONFUSED;
        invocation->message = QLatin1String("Got no suitable channels");
        onReadyOpFinished(0);
    } else {
        invocation->readyOp = new PendingComposite(readyOps, SharedPtr<SimpleStreamTubeHandler>(this));
        connect(invocation->readyOp,
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(onReadyOpFinished(Tp::PendingOperation*)));
    }
}

void SimpleStreamTubeHandler::onReadyOpFinished(Tp::PendingOperation *op)
{
    Q_ASSERT(!mInvocations.isEmpty());
    Q_ASSERT(!op || op->isFinished());

    for (QLinkedList<SharedPtr<InvocationData> >::iterator i = mInvocations.begin();
            op != 0 && i != mInvocations.end(); ++i) {
        if ((*i)->readyOp != op) {
            continue;
        }

        (*i)->readyOp = 0;

        if (op->isError()) {
            warning() << "Preparing proxies for SSTubeHandler failed with" << op->errorName()
                << op->errorMessage();
            (*i)->error = op->errorName();
            (*i)->message = op->errorMessage();
        }

        break;
    }

    while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) {
        SharedPtr<InvocationData> invocation = mInvocations.takeFirst();

        if (!invocation->error.isEmpty()) {
            // We guarantee that the proxies were ready - so we can't invoke the client if they
            // weren't made ready successfully. Fix the introspection code if this happens :)
            invocation->ctx->setFinishedWithError(invocation->error, invocation->message);
            continue;
        }

        debug() << "Emitting SSTubeHandler::invokedForTube for" << invocation->tubes.size()
            << "tubes";

        foreach (const StreamTubeChannelPtr &tube, invocation->tubes) {
            if (!tube->isValid()) {
                debug() << "Skipping already invalidated tube" << tube->objectPath();
                continue;
            }

            if (!mTubes.contains(tube)) {
                connect(tube.data(),
                        SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
                        SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString)));

                mTubes.insert(tube, invocation->acc);
            }

            emit invokedForTube(
                    invocation->acc,
                    tube,
                    invocation->time,
                    invocation->hints);
        }

        invocation->ctx->setFinished();
    }
}

void SimpleStreamTubeHandler::onTubeInvalidated(DBusProxy *proxy,
        const QString &errorName, const QString &errorMessage)
{
    StreamTubeChannelPtr tube(qobject_cast<StreamTubeChannel *>(proxy));

    Q_ASSERT(!tube.isNull());
    Q_ASSERT(mTubes.contains(tube));

    debug() << "Tube" << tube->objectPath() << "invalidated - " << errorName << ':' << errorMessage;

    AccountPtr acc = mTubes.value(tube);
    mTubes.remove(tube);

    emit tubeInvalidated(
            acc,
            tube,
            errorName,
            errorMessage);
}

} // Tp
<commit_msg>SSTH: Add a TODO to use Channel::channelType() in handleChannels whenever that becomes possible<commit_after>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "TelepathyQt4/simple-stream-tube-handler.h"

#include "TelepathyQt4/_gen/simple-stream-tube-handler.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/Account>
#include <TelepathyQt4/ChannelClassSpec>
#include <TelepathyQt4/PendingComposite>
#include <TelepathyQt4/PendingReady>
#include <TelepathyQt4/StreamTubeChannel>

namespace Tp
{

namespace
{
    ChannelClassSpecList buildFilter(const QStringList &p2pServices,
            const QStringList &roomServices, bool requested)
    {
        ChannelClassSpecList filter;

        foreach (const QString &service, p2pServices)
        {
            filter.append(requested ?
                    ChannelClassSpec::outgoingStreamTube(service) :
                    ChannelClassSpec::incomingStreamTube(service));
        }

        foreach (const QString &service, roomServices)
        {
            filter.append(requested ?
                    ChannelClassSpec::outgoingRoomStreamTube(service) :
                    ChannelClassSpec::incomingRoomStreamTube(service));
        }

        return filter;
    }
}

SharedPtr<SimpleStreamTubeHandler> SimpleStreamTubeHandler::create(
        const QStringList &p2pServices,
        const QStringList &roomServices,
        bool requested,
        bool monitorConnections,
        bool bypassApproval)
{
    return SharedPtr<SimpleStreamTubeHandler>(
            new SimpleStreamTubeHandler(
                p2pServices,
                roomServices,
                requested,
                monitorConnections,
                bypassApproval));
}

SimpleStreamTubeHandler::SimpleStreamTubeHandler(
        const QStringList &p2pServices,
        const QStringList &roomServices,
        bool requested,
        bool monitorConnections,
        bool bypassApproval)
: AbstractClient(),
    AbstractClientHandler(buildFilter(p2pServices, roomServices, requested)),
    mMonitorConnections(monitorConnections),
    mBypassApproval(bypassApproval)
{
}

SimpleStreamTubeHandler::~SimpleStreamTubeHandler()
{
    if (!mTubes.empty()) {
        debug() << "~SSTubeHandler(): Closing" << mTubes.size() << "leftover tubes";

        foreach (const StreamTubeChannelPtr &tube, mTubes.keys()) {
            tube->requestClose();
        }
    }
}

void SimpleStreamTubeHandler::handleChannels(
        const MethodInvocationContextPtr<> &context,
        const AccountPtr &account,
        const ConnectionPtr &connection,
        const QList<ChannelPtr> &channels,
        const QList<ChannelRequestPtr> &requestsSatisfied,
        const QDateTime &userActionTime,
        const HandlerInfo &handlerInfo)
{
    debug() << "SimpleStreamTubeHandler::handleChannels() invoked for " <<
        channels.size() << "channels on account" << account->objectPath();

    SharedPtr<InvocationData> invocation(new InvocationData());
    QList<PendingOperation *> readyOps;

    foreach (const ChannelPtr &chan, channels) {
        StreamTubeChannelPtr tube = StreamTubeChannelPtr::qObjectCast(chan);

        if (!tube) {
            // TODO: if Channel ever starts utilizing its immutable props for the immutable
            // accessors, use Channel::channelType() here
            const QString channelType =
                chan->immutableProperties()[QLatin1String(
                        TELEPATHY_INTERFACE_CHANNEL ".ChannelType")].toString();

            if (channelType != TP_QT4_IFACE_CHANNEL_TYPE_STREAM_TUBE) {
                debug() << "We got a non-StreamTube channel" << chan->objectPath() <<
                    "of type" << channelType << ", ignoring";
            } else {
                warning() << "The channel factory used for a simple StreamTube handler must" <<
                    "construct StreamTubeChannel subclasses for stream tubes";
            }
            continue;
        }

        Features features = StreamTubeChannel::FeatureStreamTube;
        if (mMonitorConnections) {
            features.insert(StreamTubeChannel::FeatureConnectionMonitoring);
        }
        readyOps.append(tube->becomeReady(features));

        invocation->tubes.append(tube);
    }

    invocation->ctx = context;
    invocation->acc = account;
    invocation->time = userActionTime;

    if (!requestsSatisfied.isEmpty()) {
        invocation->hints = requestsSatisfied.first()->hints();
    }

    mInvocations.append(invocation);

    if (invocation->tubes.isEmpty()) {
        warning() << "SSTH::HandleChannels got no suitable channels, admitting we're Confused";
        invocation->readyOp = 0;
        invocation->error = TP_QT4_ERROR_CONFUSED;
        invocation->message = QLatin1String("Got no suitable channels");
        onReadyOpFinished(0);
    } else {
        invocation->readyOp = new PendingComposite(readyOps, SharedPtr<SimpleStreamTubeHandler>(this));
        connect(invocation->readyOp,
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(onReadyOpFinished(Tp::PendingOperation*)));
    }
}

void SimpleStreamTubeHandler::onReadyOpFinished(Tp::PendingOperation *op)
{
    Q_ASSERT(!mInvocations.isEmpty());
    Q_ASSERT(!op || op->isFinished());

    for (QLinkedList<SharedPtr<InvocationData> >::iterator i = mInvocations.begin();
            op != 0 && i != mInvocations.end(); ++i) {
        if ((*i)->readyOp != op) {
            continue;
        }

        (*i)->readyOp = 0;

        if (op->isError()) {
            warning() << "Preparing proxies for SSTubeHandler failed with" << op->errorName()
                << op->errorMessage();
            (*i)->error = op->errorName();
            (*i)->message = op->errorMessage();
        }

        break;
    }

    while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) {
        SharedPtr<InvocationData> invocation = mInvocations.takeFirst();

        if (!invocation->error.isEmpty()) {
            // We guarantee that the proxies were ready - so we can't invoke the client if they
            // weren't made ready successfully. Fix the introspection code if this happens :)
            invocation->ctx->setFinishedWithError(invocation->error, invocation->message);
            continue;
        }

        debug() << "Emitting SSTubeHandler::invokedForTube for" << invocation->tubes.size()
            << "tubes";

        foreach (const StreamTubeChannelPtr &tube, invocation->tubes) {
            if (!tube->isValid()) {
                debug() << "Skipping already invalidated tube" << tube->objectPath();
                continue;
            }

            if (!mTubes.contains(tube)) {
                connect(tube.data(),
                        SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
                        SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString)));

                mTubes.insert(tube, invocation->acc);
            }

            emit invokedForTube(
                    invocation->acc,
                    tube,
                    invocation->time,
                    invocation->hints);
        }

        invocation->ctx->setFinished();
    }
}

void SimpleStreamTubeHandler::onTubeInvalidated(DBusProxy *proxy,
        const QString &errorName, const QString &errorMessage)
{
    StreamTubeChannelPtr tube(qobject_cast<StreamTubeChannel *>(proxy));

    Q_ASSERT(!tube.isNull());
    Q_ASSERT(mTubes.contains(tube));

    debug() << "Tube" << tube->objectPath() << "invalidated - " << errorName << ':' << errorMessage;

    AccountPtr acc = mTubes.value(tube);
    mTubes.remove(tube);

    emit tubeInvalidated(
            acc,
            tube,
            errorName,
            errorMessage);
}

} // Tp
<|endoftext|>