<commit_before>#include "circuits/circuit.h"
#include "matrix/matrix.h"
#include "gtest/gtest.h"
#include <iostream>
#include <stdio.h>

using namespace std;

TEST(ElementStampsTest, Resistor) {
    // Arrange
    Element resistor("R1", 4, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    resistor.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0,    0,    0, 0},
        {0,  0.25, -0.25, 0},
        {0, -0.25,  0.25, 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}
<commit_msg>Tests simple circuit stamps :princess:<commit_after>#include "circuits/circuit.h"
#include "matrix/matrix.h"
#include "gtest/gtest.h"
#include <iostream>
#include <stdio.h>

using namespace std;

TEST(ElementStampsTest, Resistor) {
    // Arrange
    Element resistor("R1", 4, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    resistor.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0,    0,    0, 0},
        {0,  0.25, -0.25, 0},
        {0, -0.25,  0.25, 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(CircuitStampsTest, SimpleCircuit) {
    // Arrange
    int numNodes = 6;
    int numElements = 9;
    int numVariables = 9;
    vector<Element> netlist(10);
    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);
    // From netlist data/simples.net
    // Changes order (not netlist parameters order)! Value first!
    //                  ( name, val, a, b, ... )
    netlist[1] = Element("R0102", 1, 1, 2);
    netlist[2] = Element("R0301", 1, 3, 1);
    netlist[3] = Element("R0403", 1, 4, 3);
    netlist[4] = Element("R0004", 1, 0, 4);
    netlist[5] = Element("R0502", 1, 5, 2);
    netlist[6] = Element("R0605", 1, 6, 5);
    netlist[7] = Element("O0300", 0, 3, 0, 1, 0); // OpAmps have value = 0!!!
    netlist[8] = Element("O0600", 0, 6, 0, 5, 4);
    netlist[9] = Element("V0200", 1, 2, 0);
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    int pivotNumVariables = numNodes;
    netlist[7].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[8].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[9].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    // Act
    applyStamps(numElements, numVariables, netlist, matrix);
    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  2 , -1 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 , -1 ,  2 ,  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  1 ,  0 },
        {  0 , -1 ,  0 ,  2 , -1 ,  0 ,  0 ,  1 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 , -1 ,  2 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  2 , -1 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  1 ,  0 ,  0 },
        {  0 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 , -1 },
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}
<|endoftext|>


<commit_before>// eigenfaces.cpp : eigenfaces alg for the face recognition
//                  -  Some code is from OpenCV src
//
// @author wenlong
//
// The PCA finds a linear combination of features that maximizes the total variance in data;
// It doesn't consider any classes and so a lot of discriminative information may be lost when throwing components away.
//
#include "stdafx.h"
#include "eigenfaces.h"

//typedef vector<vector<Mat> > MatMatrix ;
//typedef vector<vector<int> > IntMatrix ;

using namespace cv;
using namespace std;

//namespace fs = boost::filesystem;

// dataset in each subject
const int SUBJECT_DATA = 12;

//Preparing the data
//These two functions are from Face Recognition src in OpenCV doc
static Mat norm_0_255(InputArray _src) {
	Mat src = _src.getMat();
	// Create and return normalized image:
	Mat dst;
	switch (src.channels()) {
	case 1:
		cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
		break;
	case 3:
		cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
		break;
	default:
		src.copyTo(dst);
		break;
	}
	return dst;
}

static vector<string> split(const char *str, char c = '\\' )
{
	vector<string> result;

	do
	{
		const char *begin = str;

		while (*str != c && *str)
			str++;

		result.push_back(string(begin, str));
	} while (0 != *str++);

	return result;
}

static string get_dir(const string& filename, const string& outpath)
{
	//TODO: using the Boost for this function
	/*
	//int length = path.length();
	//boost::regex replaceRegex("\\\\");

	//string result = boost::regex_replace(path, replaceRegex, "/", boost::match_default | boost::format_all);

	//result = result.substr(0, result.rfind("/"));

	boost::filesystem::path p = path;
	boost::filesystem::path p1 = p.parent_path();
	boost::filesystem::path p2 = p1.filename();
	cout << p2 << endl;

	cout << p2.string() << endl;

	fs::path file = filename;
	string dir = file.parent_path().filename().string();
	cout << outpath + dir << endl;
	*/

	//e:\wenlong\documents\code\opencv\eigenfaces\x64\Debug\input_\crop_00005\crop_00005fa010_930831-new.jpg
	vector<string> s = split(filename.c_str());
	//cout << s[9] << endl;

	//get the full output name
	string output = outpath + s[9] + "\\";

	return output;
}

static void read_csv_(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
	std::ifstream file(filename.c_str(), ifstream::in);
	if (!file) {
		string error_message = "No valid input file was given, please check the given filename.";
		CV_Error(CV_StsBadArg, error_message);
	}

	string line, path, classlabel;
	while (getline(file, line)) {
		stringstream liness(line);
		getline(liness, path, separator);
		getline(liness, classlabel);
		if (!path.empty() && !classlabel.empty()) {
			//Mat im = imread(path, 0);
			//images.push_back(imread(path, 0));
			//Mat image = imread(path, CV_LOAD_IMAGE_GRAYSCALE);

			images.push_back(imread(path, CV_LOAD_IMAGE_GRAYSCALE));
            /*
			Mat im1 = im.clone();
			if ( !im1.isContinuous())
			{
			// .bmp files sometimes are 'padded' to multiples of 4
			// * convert the images to png, pbm or
			// * use im.clone() - the deep copy will force continuity
			//
			//Mat im = im.clone();
			cout <<"out" << endl;
			}
			*/

			labels.push_back(atoi(classlabel.c_str()));
		}
	}

}

static void get_result(vector<Mat>& images, vector<int>& labels, const string& output_folder)
{
    // quit if there are not enough images (at least 2 images to work)
	if (images.size() <= 1)
	{
		string error_message = " Needs more images to data set ...";
		CV_Error(CV_StsError, error_message);
	}

	// get the height from the first image for the output
	int height = images[0].rows;

	// For eigen and fisherfaces, the images have to flatten it to one row; the lbp one doesn't
	for (int index = 0; index < images.size(); ++index)
		images[index] = images[index].reshape(1, 1);

	// the last image in each dataset is the test data
	Mat testSample = images[images.size() - 1];
	int testLabel = labels[labels.size() - 1];
	images.pop_back();
	labels.pop_back();

	// create an Eigenfaces model for face recognition and train it with the images and labels
	// class FaceRecognizer : Algorithm
	// TODO: the FaceRecognizer class, and the derived classes
	Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
	model->train(images, labels);

	// predicts the label of a given test image
	//int predictedLabel = 0;
	//double confidence = 0.0;
	//model->predict(testSample, predictedLabel, confidence);
	int predictedLabel = model->predict(testSample);

	// the confidence
	string result_message = format("Predicted class = %d / Actual class = %d .", predictedLabel, testLabel);
	cout << result_message << endl;

	// get the eigenvalues of this Eigenfaces model
	Mat eigenvalues = model->getMat("eigenvalues");
	// the Eigenvectors
	Mat W = model->getMat("eigenvectors");
	// the sample mean from the training data
	Mat mean = model->getMat("mean");

	// display the mean	picture
	//if (argc == 2)
	//{
	//	imshow("mean", norm_0_255(mean.reshape(1, height)));
	//} else {
	imwrite(format("%s\\mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, height)));
	//}

	// display the Eigenfaces
	for (int i = 0; i < min(10, W.cols); i++)
	{
		string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
		cout << msg << endl;

		// get eigenvector #i
		Mat ev = W.col(i).clone();

		// reshape to original size & normalize to [0...255] for imshow
		//ev = ev.reshape(1, height);
		Mat grayscale = norm_0_255(ev.reshape(1, height));
		// show the image & apply a Jet colormap for better sensing
		Mat cgrayscale;
		applyColorMap(grayscale, cgrayscale, COLORMAP_JET);

		// display or save
		//if (argc == 2)
		//{
		//	imshow(format("eigenface_%d", i), cgrayscale);
		//} else {
		imwrite(format("%s\\eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
		//}
	}

}

static void read_csv(const string& filename, const string& output_folder, char separator = ';') {
	std::ifstream file(filename.c_str(), ifstream::in);
	if (!file) {
		string error_message = "No valid input file was given, please check the given filename.";
		CV_Error(CV_StsBadArg, error_message);
	}

	// The vectors hold the images and corresponding labels based on the csv format
	vector<Mat> images;
	vector<int> labels;
	//store the subjects
	//vector<vector<Mat> > mat_matrix;
	//vector<vector<int> > label_matrix;

	int num = 1;
	//the index of subject
	int index = 1;

	string line, path, classlabel;
	while (getline(file, line)) {
		stringstream liness(line);
		getline(liness, path, separator);
		getline(liness, classlabel);
		if (!path.empty() && !classlabel.empty()) {
			//Mat im = imread(path, 0);
			//images.push_back(imread(path, 0));
			Mat image = imread(path, CV_LOAD_IMAGE_GRAYSCALE);

			images.push_back(image);

			/*
			Mat im1 = im.clone();
			if ( !im1.isContinuous())
			{
			  .bmp files sometimes are 'padded' to multiples of 4
			  * convert the images to png, pbm or
			  * use im.clone() - the deep copy will force continuity

			Mat im = im.clone();
			cout <<"out" << endl;
			}
			*/

			labels.push_back(atoi(classlabel.c_str()));

			// for each subject
			if ((num % SUBJECT_DATA) == 0)
			{
				//mat_matrix.push_back(images);
				//label_matrix.push_back(labels);

				cout << "For the subject num: " << index << endl;

				//mkdir
				string dir = get_dir(path, output_folder);
				_mkdir(dir.c_str());

				// get the calculation results
				get_result(images, labels, dir);

				//
				images.clear();
				labels.clear();

				cout << "-----------------------------"<< endl;

				//next suject
				index++;
			}

			num++;
		}
	}

	/*
	//print out
	for (int i = 0; i < mat_matrix.size(); i++)
	{
		for (int j = 0; j < mat_matrix[i].size(); i++)
			cout << mat_matrix[i][j] <<":"<< label_matrix[i][j] << " ";

		cout << endl;
	}
	*/

}

int main(int argc, const char* argv[])
{
	/*
	if (argc < 2)
	{
		cout << "usage: " << argv[0] << " <csv.ext> <output_folder>" << endl;
		exit(1);
	}
	*/

	argv[1] = "e:\\wenlong\\documents\\code\\opencv\\eigenfaces\\x64\\Debug\\input_.txt";
	argv[2] = "E:\\wenlong\\documents\\code\\opencv\\eigenfaces\\x64\\Debug\\output\\";

	//string output_folder = ".";
	string output_folder = argv[2];

	/*
	if (argc == 3)
	{
		output_folder = string(argv[2]);
	}
	*/

	// get the path to the csv
	string fn_csv = string(argv[1]);

	// The vectors hold the images and corresponding labels based on the csv format
	//vector<Mat> images;
	//store the subjects
	//vector<vector<Mat> > mat_matrix;
	//vector<vector<int> > label_matrix;

	// read the csv file
	try {
		read_csv(fn_csv, output_folder);

	} catch (cv::Exception& e){
		cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
		exit(1);
	}

	// display if we are not writing to an output folder
	//if (argc == 2)
	//{
		waitKey(0);
	//}

	return 0;
}
<commit_msg>update<commit_after>// eigenfaces.cpp : eigenfaces alg for the face recognition
//                  -  Some code is from OpenCV src
//
// @author wenlong
//
// The PCA finds a linear combination of features that maximizes the total variance in data;
// It doesn't consider any classes and so a lot of discriminative information may be lost when throwing components away.
//
// TODO:
//      1. Generalization
//            - save the model of each subject
//            - use the trained model to test the test dataset
//
//      2. Calculate verification rate and false accept rate
//
#include "stdafx.h"
#include "eigenfaces.h"

//typedef vector<vector<Mat> > MatMatrix ;
//typedef vector<vector<int> > IntMatrix ;

using namespace cv;
using namespace std;

//namespace fs = boost::filesystem;

// dataset in each subject
const int SUBJECT_DATASET = 12;

// size of the training dataset
const int TRAINING_DATASET = 6;
// test dataset
const int TEST_DATASET = 6;

// feature num
//The number of components(read: Eigenfaces) kept for this Prinicpal Component Analysis.
//As a hint : Theres no rule how many components(read : Eigenfaces) should be kept for good reconstruction capabilities.
//It is based on your input data, so experiment with the number.
//Keeping 80 components should almost always be sufficient.
const int FEATURE_NUM = 80;

// threshold
double THRESHOLD = 0.5;

//Preparing the data
//The function is from Face Recognition src in OpenCV doc
static Mat norm_0_255(InputArray _src) {
	Mat src = _src.getMat();
	// Create and return normalized image:
	Mat dst;
	switch (src.channels()) {
	case 1:
		cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
		break;
	case 3:
		cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
		break;
	default:
		src.copyTo(dst);
		break;
	}
	return dst;
}

static vector<string> split(const char *str, char c = '\\' )
{
	vector<string> result;

	do
	{
		const char *begin = str;

		while (*str != c && *str)
			str++;

		result.push_back(string(begin, str));
	} while (0 != *str++);

	return result;
}

static string get_dir(const string& filename, const string& outpath)
{
	//TODO: using the Boost lib for this function
	/*
	//int length = path.length();
	//boost::regex replaceRegex("\\\\");

	//string result = boost::regex_replace(path, replaceRegex, "/", boost::match_default | boost::format_all);

	//result = result.substr(0, result.rfind("/"));

	boost::filesystem::path p = path;
	boost::filesystem::path p1 = p.parent_path();
	boost::filesystem::path p2 = p1.filename();
	cout << p2 << endl;

	cout << p2.string() << endl;

	fs::path file = filename;
	string dir = file.parent_path().filename().string();
	cout << outpath + dir << endl;
	*/

	//e:\wenlong\documents\code\opencv\eigenfaces\x64\Debug\input_\crop_00005\crop_00005fa010_930831-new.jpg
	vector<string> s = split(filename.c_str());
	//cout << s[9] << endl;

	//get the full output name
	string output = outpath + s[9] + "\\";

	return output;
}

static void read_csv_(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
	std::ifstream file(filename.c_str(), ifstream::in);
	if (!file) {
		string error_message = "No valid input file was given, please check the given filename.";
		CV_Error(CV_StsBadArg, error_message);
	}

	string line, path, classlabel;
	while (getline(file, line)) {
		stringstream liness(line);
		getline(liness, path, separator);
		getline(liness, classlabel);
		if (!path.empty() && !classlabel.empty()) {
			//Mat im = imread(path, 0);
			//images.push_back(imread(path, 0));
			//Mat image = imread(path, CV_LOAD_IMAGE_GRAYSCALE);

			images.push_back(imread(path, CV_LOAD_IMAGE_GRAYSCALE));
            /*
			Mat im1 = im.clone();
			if ( !im1.isContinuous())
			{
			// .bmp files sometimes are 'padded' to multiples of 4
			// * convert the images to png, pbm or
			// * use im.clone() - the deep copy will force continuity
			//
			//Mat im = im.clone();
			cout <<"out" << endl;
			}
			*/

			//The labels corresponding to the images
			labels.push_back(atoi(classlabel.c_str()));
		}
	}

}

static int write_file(const string& output_folder, const string& str)
{
	ofstream file;
	file.open(output_folder + "rate.txt");

	file << str << endl;

	file.close();
}

static string get_result(ofstream& logstream, vector<Mat>& images, vector<int>& labels, const string& output_folder)
{
    // quit if there are not enough images (at least 2 images to work)
	if (images.size() <= 1)
	{
		string error_message = " Needs more images to data set ...";
		CV_Error(CV_StsError, error_message);
	}

	// get the height from the first image for the output
	int height = images[0].rows;

	/*
	// the last image in each dataset is the test data
	Mat testSample = images[images.size() - 1];
	int testLabel = labels[labels.size() - 1];
	images.pop_back();
	labels.pop_back();
	*/

	vector<Mat> trainingSamples, testSamples;
	vector<int> trainingLabels, testLabels;

	for (int i = 0; i < images.size(); ++i)
	{
		//THE EIGENFACES METHOD MAKES THE ASSUMPTION, THAT THE TRAINING AND TEST IMAGES ARE OF EQUAL SIZE
		// For eigen and fisherfaces, the images have to flatten it to one row; the lbp one doesn't
        //images[i] = images[i].reshape(1, 1);

		// the traing dataset
		if (i < TRAINING_DATASET)
		{
			trainingSamples.push_back(images[i].reshape(1, 1));
			trainingLabels.push_back(labels[i]);
		}

		// the test dataset
		if (i >= TEST_DATASET)
		{
			testSamples.push_back(images[i].reshape(1,1));
			testLabels.push_back(labels[i]);
		}

	}

	/*  -----   train the model	 ----- */

    // create an Eigenfaces model for face recognition and train it with the images and labels
	// class FaceRecognizer : Algorithm
	// TODO: the FaceRecognizer class, and the derived classes
	//
	// The features num
	//The number of components (read: Eigenfaces) kept for this Prinicpal Component Analysis
	//int FEATURE_NUM = 10;
	// The threshold applied in the prediction.
	// If the distance to the nearest neighbor is larger than the threshold, this method returns -1
	//double threshold = 10.0;
	Ptr<FaceRecognizer> model = createEigenFaceRecognizer(FEATURE_NUM, THRESHOLD);

	model->train(trainingSamples, trainingLabels);

    /*  -----   test the model	 ----- */
	int num = 0;
	// test each image
	for (int i = 0; i < testSamples.size(); ++i)
	{
		// predicts the label of a given test image;
		// -1 as label, which indicates this face is unknown
		int predictedLabel = -1;
		// Associated confidence (e.g. distance) for the predicted label.
		double confidence = 0.0;
		model->predict(testSamples[i], predictedLabel, confidence);
		//int predictedLabel = model->predict(testSample);

		// the confidence
		string result_message = format("Predicted class = %d / Actual class = %d .", predictedLabel, testLabels[i]);
		cout << result_message << endl;
		logstream << result_message << endl;

		if ( predictedLabel == testLabels[i])
		{
			num++;
		}

   }

	double confidence_rate = num / (double)TEST_DATASET;
	string confidence_rate_message = format("%.2f", confidence_rate);
	cout << confidence_rate_message << endl;
	logstream << confidence_rate_message << endl;

	/*  -----   display the result	 ----- */

	// get the eigenvalues of this Eigenfaces model	in ordered descending
	Mat eigenvalues = model->getMat("eigenvalues");
	// the eigenvectors ordered by the eigenvalues
	Mat W = model->getMat("eigenvectors");
	// the sample mean from the training data
	Mat mean = model->getMat("mean");

	// display the mean	picture
	//if (argc == 2)
	//{
	//	imshow("mean", norm_0_255(mean.reshape(1, height)));
	//} else {
	imwrite(format("%s\\mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, height)));
	//}

	// display the Eigenfaces
	for (int i = 0; i < min(10, W.cols); i++)
	{
		string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
		cout << msg << endl;
		logstream << msg << endl;

		// get eigenvector #i
		Mat ev = W.col(i).clone();

		// reshape to original size & normalize to [0...255] for imshow
		//ev = ev.reshape(1, height);
		Mat grayscale = norm_0_255(ev.reshape(1, height));
		// show the image & apply a Jet colormap for better sensing
		Mat cgrayscale;
		applyColorMap(grayscale, cgrayscale, COLORMAP_JET);

		// display or save
		//if (argc == 2)
		//{
		//	imshow(format("eigenface_%d", i), cgrayscale);
		//} else {
		imwrite(format("%s\\eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
		//}
	}

	// write the file
	//ofstream file;
	//file.open(output_folder + "rate.txt");
	string write_content = to_string(testLabels[0]) + ":" + confidence_rate_message;
	//file << write_content << endl;
	//file.close();

	return write_content;
}

/*
   read_csv -
            - Load the dataset
*/
static void read_csv(ofstream& logstream, const string& filename, const string& output_folder, char separator = ';') {
	std::ifstream file(filename.c_str(), ifstream::in);
	if (!file) {
		string error_message = "No valid input file was given, please check the given filename.";
		CV_Error(CV_StsBadArg, error_message);
	}

	// open the file
	ofstream fstream;
	fstream.open(output_folder + "rate.txt");

    // The vectors hold the images and corresponding labels based on the csv format
	vector<Mat> images;
	vector<int> labels;
	//store the subjects
	//vector<vector<Mat> > mat_matrix;
	//vector<vector<int> > label_matrix;

	int num = 1;
	//the index of subject
	int index = 0;

	string line, path, classlabel;
	while (getline(file, line)) {
		stringstream liness(line);
		getline(liness, path, separator);
		getline(liness, classlabel);
		if (!path.empty() && !classlabel.empty()) {
			//Mat im = imread(path, 0);
			//images.push_back(imread(path, 0));
			Mat image = imread(path, CV_LOAD_IMAGE_GRAYSCALE);

			images.push_back(image);

			/*
			Mat im1 = im.clone();
			if ( !im1.isContinuous())
			{
			  .bmp files sometimes are 'padded' to multiples of 4
			  * convert the images to png, pbm or
			  * use im.clone() - the deep copy will force continuity

			Mat im = im.clone();
			cout <<"out" << endl;
			}
			*/

			labels.push_back(atoi(classlabel.c_str()));

			// for each subject
			if ((num % SUBJECT_DATASET) == 0)
			{
				//mat_matrix.push_back(images);
				//label_matrix.push_back(labels);

				cout << "For the subject num: " << index << endl;
				logstream << "For the subject num: " + to_string(index) << endl;

				//mkdir
				string dir = get_dir(path, output_folder);
				_mkdir(dir.c_str());

				// get the calculation results
				string str = get_result(logstream, images, labels, dir);

				fstream << str << endl;
				//
				images.clear();
				labels.clear();

				cout << "-----------------------------" << endl;
				logstream << "-----------------------------"  << endl;

				//next suject
				index++;
			}

			num++;
		}
	}

	/*
	//print out
	for (int i = 0; i < mat_matrix.size(); i++)
	{
		for (int j = 0; j < mat_matrix[i].size(); i++)
			cout << mat_matrix[i][j] <<":"<< label_matrix[i][j] << " ";

		cout << endl;
	}
	*/

	fstream.close();
}

int main(int argc, const char* argv[])
{
	/*
	if (argc < 2)
	{
		cout << "usage: " << argv[0] << " <csv.ext> <output_folder>" << endl;
		exit(1);
	}
	*/

	argv[1] = "e:\\wenlong\\documents\\code\\opencv\\eigenfaces\\x64\\Debug\\input_.txt";
	argv[2] = "E:\\wenlong\\documents\\code\\opencv\\eigenfaces\\x64\\Debug\\output\\";

	//string output_folder = ".";
	string output_folder = argv[2];

	/*
	if (argc == 3)
	{
		output_folder = string(argv[2]);
	}
	*/

	// get the path to the csv
	string fn_csv = string(argv[1]);

	//open the log file
	ofstream logstream;
	logstream.open(output_folder + "log.txt");

	// The vectors hold the images and corresponding labels based on the csv format
	//vector<Mat> images;
	//store the subjects
	//vector<vector<Mat> > mat_matrix;
	//vector<vector<int> > label_matrix;

	// read the csv file
	try {
		read_csv(logstream, fn_csv, output_folder);

	} catch (cv::Exception& e){
		cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
		exit(1);
	}

	// display if we are not writing to an output folder
	//if (argc == 2)
	//{
		waitKey(0);
	//}

	logstream.close();

	return 0;
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Guido Tack <tack@gecode.org>
 *  Modified:
 *     Laurent Perron (lperron@google.com)
 *
 *  Copyright:
 *     Guido Tack, 2007
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  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.
 *
 */

#include <iostream>
#include <fstream>
#include <cstring>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "flatzinc/flatzinc.h"

DEFINE_int32(log_frequency, 100000, "Search log frequency");
DEFINE_bool(log, false, "Show search log");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DECLARE_bool(log_prefix);

namespace operations_research {
void Run(const std::string& file) {
  FlatZincModel fz_model;
  if (file == "-") {
    fz_model.Parse(std::cin);
  } else {
    fz_model.Parse(file);
  }

  fz_model.Solve(FLAGS_log_frequency,
                 FLAGS_log,
                 FLAGS_all,
                 FLAGS_free,
                 FLAGS_num_solutions,
                 FLAGS_time_limit);
}
}

int main(int argc, char** argv) {
  FLAGS_log_prefix=false;
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::Run(argv[1]);
  return 0;
}
<commit_msg>support official flags -p, -f, -a<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Guido Tack <tack@gecode.org>
 *  Modified:
 *     Laurent Perron (lperron@google.com)
 *
 *  Copyright:
 *     Guido Tack, 2007
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  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.
 *
 */

#include <iostream>
#include <fstream>
#include <cstring>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "flatzinc/flatzinc.h"

DEFINE_int32(log_frequency, 100000, "Search log frequency");
DEFINE_bool(log, false, "Show search log");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DEFINE_int32(threads, 0, "threads");
DECLARE_bool(log_prefix);

namespace operations_research {
void Run(const std::string& file) {
  FlatZincModel fz_model;
  if (file == "-") {
    fz_model.Parse(std::cin);
  } else {
    fz_model.Parse(file);
  }

  fz_model.Solve(FLAGS_log_frequency,
                 FLAGS_log,
                 FLAGS_all,
                 FLAGS_free,
                 FLAGS_num_solutions,
                 FLAGS_time_limit);
}
}

int main(int argc, char** argv) {
  FLAGS_log_prefix=false;
  for (int i = 1; i < argc; ++i) {
    if (strcmp(argv[i], "-a") == 0) {
      argv[i] = "--all";
    }
    if (strcmp(argv[i], "-f") == 0) {
      argv[i] = "--free";
    }
    if (strcmp(argv[i], "-p") == 0) {
      argv[i] = "--threads";
    }
  }
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::Run(argv[1]);
  return 0;
}
<|endoftext|>


<commit_before>// =============================================================================
//  This file is part of:
//  Dynamic Adaptive System for Hierarchical Multipole Methods (DASHMM)
//
//  Copyright (c) 2015-2016, Trustees of Indiana University,
//  All rights reserved.
//
//  DASHMM is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  DASHMM 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with DASHMM. If not, see <http://www.gnu.org/licenses/>.
//
//  This software was created at the Indiana University Center for Research in
//  Extreme Scale Technologies (CREST).
// =============================================================================

#include "builtins/fmm97distro.h"

#include <algorithm>
#include <map>
#include <limits>

namespace dashmm {

void FMM97Distro::compute_distribution(DAG &dag) {
  // color all the DAG node
  for (size_t i = 0; i < dag.source_leaves.size(); ++i) {
    DAGNode *s = dag.source_leaves[i];
    s->color = 0;
    color(s);
  }

  // Confine M and I of the source tree
  for (size_t i = 0; i < dag.source_leaves.size(); ++i) {
    DAGNode *n = dag.source_leaves[i];
    assert(n->locality != -1);
    confine(n, 's');
  }

  // Confine L of the target tree
  for (size_t i = 0; i < dag.target_leaves.size(); ++i) {
    DAGNode *n = dag.target_leaves[i];
    assert(n->locality != -1);
    confine(n, 't');
  }

  // Make decision on I of the target tree
  for (size_t i = 0; i < dag.target_nodes.size(); ++i) {
    DAGNode *n = dag.target_nodes[i];
    if (n->locality == -1)
      assign(n);
  }
}

void FMM97Distro::color(DAGNode *s) {
  for (size_t i = 0; i < s->out_edges.size(); ++i) {
    DAGNode *t = s->out_edges[i].target;
    t->color = std::max(t->color, s->color + 1);
    color(t);
  }
}

void FMM97Distro::confine(DAGNode *n, char type) {
  assert(type == 's' || type == 't');

  // Note: there may be multiple times \param n is visited.

  if (type == 's') {
    for (size_t i = 0; i < n->out_edges.size(); ++i) {
      DAGNode *target = n->out_edges[i].target;
      Operation op = n->out_edges[i].op;
      bool terminate = true;

      if (target->locality == -1) {
        if (op == Operation::MtoM || op == Operation::MtoI)
          target->locality = n->locality;

        if (op == Operation::MtoM)
          terminate = false;
      } else if (op == Operation::StoM) {
        terminate = false;
      }

      if (terminate == false)
        confine(target, type);
    }
  } else {
    for (size_t i = 0; i < n->in_edges.size(); ++i) {
      DAGNode *source = n->in_edges[i].source;
      Operation op = n->in_edges[i].op;
      bool terminate = true;

      if (source->locality == -1) {
        if (op == Operation::LtoL) {
          source->locality = n->locality;
          terminate = false;
        }
      } else if (op == Operation::LtoT) {
        terminate = false;
      }

      if (terminate == false)
        confine(source, type);
    }
  }
}

void FMM97Distro::assign(DAGNode *n) {
  // \param n is the expansion LCO for an intermediate expansion of
  // the target tree.

  // Compute communication cost if \param n and the DAGNodes of its
  // \param out_edges are placed on different localities.
  int target_locality = n->out_edges[0].target->locality;
  int out_weight = n->out_edges.size() * n->out_edges[0].weight;

  // Categorize incoming edges
  std::map<int, int> color;
  std::map<int, int> weight;
  int in_weight = 0;

  for (size_t i = 0; i < n->in_edges.size(); ++i) {
    int w = n->in_edges[i].weight;
    int c = n->in_edges[i].source->color;
    int source_locality = n->in_edges[i].source->locality;

    color[source_locality] = std::max(color[source_locality], c);
    weight[source_locality] += w;
    in_weight += w;
  }

  int min_weight = std::numeric_limits<int>::max();
  int max_color = std::numeric_limits<int>::min();
  int locality = -1;

  for (auto i = weight.begin(); i != weight.end(); ++i) {
    int source_locality = i->first;
    int w = i->second + out_weight * (source_locality != target_locality);
    int c = color[source_locality];

    if (w < min_weight) {
      min_weight = w;
      max_color = c;
      locality = source_locality;
    } else if (w == min_weight &&  c > max_color) {
      max_color = c;
      locality = source_locality;
    }
  }

  n->locality = locality;
  assert(locality != -1);
}

} // dashmm
<commit_msg>temporary fix<commit_after>// =============================================================================
//  This file is part of:
//  Dynamic Adaptive System for Hierarchical Multipole Methods (DASHMM)
//
//  Copyright (c) 2015-2016, Trustees of Indiana University,
//  All rights reserved.
//
//  DASHMM is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  DASHMM 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with DASHMM. If not, see <http://www.gnu.org/licenses/>.
//
//  This software was created at the Indiana University Center for Research in
//  Extreme Scale Technologies (CREST).
// =============================================================================

#include <hpx/hpx.h>

#include "builtins/fmm97distro.h"

#include <algorithm>
#include <map>
#include <limits>

namespace dashmm {

void FMM97Distro::compute_distribution(DAG &dag) {
  // color all the DAG node
  for (size_t i = 0; i < dag.source_leaves.size(); ++i) {
    DAGNode *s = dag.source_leaves[i];
    s->color = 0;
    color(s);
  }

  // Confine M and I of the source tree
  for (size_t i = 0; i < dag.source_leaves.size(); ++i) {
    DAGNode *n = dag.source_leaves[i];
    assert(n->locality != -1);
    confine(n, 's');
  }

  // Assert all the source nodes have their locality fixed
  for (size_t i = 0; i < dag.source_nodes.size(); ++i) {
    DAGNode *n = dag.source_nodes[i];
    if (n->idx.level() < 3)
      n->locality = 0;
    assert(n->locality != -1);
  }

  // Confine L of the target tree
  for (size_t i = 0; i < dag.target_leaves.size(); ++i) {
    DAGNode *n = dag.target_leaves[i];
    assert(n->locality != -1);
    confine(n, 't');
  }

  for (size_t i = 0; i < dag.target_nodes.size(); ++i) {
    DAGNode *n = dag.target_nodes[i];
    if (n->idx.level() < 3)
      n->locality = 0;
    assert(n->locality != -1);
  }

  // Make decision on I of the target tree
  for (size_t i = 0; i < dag.target_nodes.size(); ++i) {
    DAGNode *n = dag.target_nodes[i];
    if (n->locality == -1)
      assign(n);
  }

  // Assert all the target nodes have their locality fixed
  for (size_t i = 0; i < dag.target_nodes.size(); ++i) {
    DAGNode *n = dag.target_nodes[i];
    assert(n->locality != -1);
  }
}

void FMM97Distro::color(DAGNode *s) {
  for (size_t i = 0; i < s->out_edges.size(); ++i) {
    DAGNode *t = s->out_edges[i].target;
    t->color = std::max(t->color, s->color + 1);
    color(t);
  }
}

void FMM97Distro::confine(DAGNode *n, char type) {
  assert(type == 's' || type == 't');

  // Note: there may be multiple times \param n is visited.

  if (type == 's') {
    for (size_t i = 0; i < n->out_edges.size(); ++i) {
      DAGNode *target = n->out_edges[i].target;
      Operation op = n->out_edges[i].op;
      bool terminate = true;

      if (target->locality == -1) {
        if (op == Operation::MtoM || op == Operation::MtoI)
          target->locality = n->locality;

        if (op == Operation::MtoM)
          terminate = false;
      } else if (op == Operation::StoM) {
        terminate = false;
      }

      if (terminate == false)
        confine(target, type);
    }
  } else {
    for (size_t i = 0; i < n->in_edges.size(); ++i) {
      DAGNode *source = n->in_edges[i].source;
      Operation op = n->in_edges[i].op;
      bool terminate = true;

      if (source->locality == -1) {
        if (op == Operation::LtoL) {
          source->locality = n->locality;
          terminate = false;
        }
      } else if (op == Operation::LtoT) {
        terminate = false;
      }

      if (terminate == false)
        confine(source, type);
    }
  }

  /*
  if (type == 's') {
    for (size_t i = 0; i < n->out_edges.size(); ++i) {
      DAGNode *target = n->out_edges[i].target;
      Operation op = n->out_edges[i].op;
      bool terminate = true;

      if (op == Operation::MtoI) {
        target->locality = n->locality;
      }

      if (op == Operation::MtoM) {
        if (n->locality > target->locality) {
          target->locality = n->locality;
          terminate = false;
        }
      }

      if (op == Operation::StoM)
        terminate = false;

      if (terminate == false)
        confine(target, type);
    }
  } else {
    for (size_t i = 0; i < n->in_edges.size(); ++i) {
      DAGNode *source = n->in_edges[i].source;
      Operation op = n->in_edges[i].op;
      bool terminate = true;

      if (op == Operation::LtoT)
        terminate = false;

      if (op == Operation::LtoL) {
        if (n->locality > source->locality) {
          source->locality = n->locality;
          terminate = false;
        }
      }

      if (terminate == false)
        confine(source, type);
    }
  }
  */
}

void FMM97Distro::assign(DAGNode *n) {
  // \param n is the expansion LCO for an intermediate expansion of
  // the target tree.

  // Compute communication cost if \param n and the DAGNodes of its
  // \param out_edges are placed on different localities.
  int target_locality = n->out_edges[0].target->locality;
  int out_weight = n->out_edges.size() * n->out_edges[0].weight;

  // Categorize incoming edges
  std::map<int, int> color;
  std::map<int, int> weight;
  int in_weight = 0;

  for (size_t i = 0; i < n->in_edges.size(); ++i) {
    int w = n->in_edges[i].weight;
    int c = n->in_edges[i].source->color;
    int source_locality = n->in_edges[i].source->locality;

    color[source_locality] = std::max(color[source_locality], c);
    weight[source_locality] += w;
    in_weight += w;
  }

  int min_weight = std::numeric_limits<int>::max();
  int max_color = std::numeric_limits<int>::min();
  int locality = -1;

  for (auto i = weight.begin(); i != weight.end(); ++i) {
    int source_locality = i->first;
    int w = i->second + out_weight * (source_locality != target_locality);
    int c = color[source_locality];

    if (w < min_weight) {
      min_weight = w;
      max_color = c;
      locality = source_locality;
    } else if (w == min_weight &&  c > max_color) {
      max_color = c;
      locality = source_locality;
    }
  }

  n->locality = locality;
  assert(locality != -1);
}

} // dashmm
<|endoftext|>


<commit_before>#include "amftest.hpp"

#include "deserializer.hpp"
#include "deserializationcontext.hpp"

#include "types/amfarray.hpp"
#include "types/amfbool.hpp"
#include "types/amfbytearray.hpp"
#include "types/amfdate.hpp"
#include "types/amfdictionary.hpp"
#include "types/amfdouble.hpp"
#include "types/amfinteger.hpp"
#include "types/amfnull.hpp"
#include "types/amfobject.hpp"
#include "types/amfstring.hpp"
#include "types/amfundefined.hpp"
#include "types/amfvector.hpp"
#include "types/amfxml.hpp"
#include "types/amfxmldocument.hpp"

#include "utils/amfitemptr.hpp"

template<typename T>
static void deserializesTo(const T& expected, v8 data, int left = 0) {
	SCOPED_TRACE(::testing::PrintToString(expected) + " = " + ::testing::PrintToString(data));

	auto it = data.cbegin();
	try {
		Deserializer d;
		T i = d.deserialize(it, data.cend()).as<T>();
		ASSERT_EQ(expected, i);
		T j = *d.deserialize(data).asPtr<T>();
		ASSERT_EQ(expected, j);
		DeserializationContext ctx;
		T k = Deserializer::deserialize(data, ctx).as<T>();
		ASSERT_EQ(expected, k);
	} catch(std::exception& e) {
		FAIL() << "Deserialization threw exception:\n"
		       << e.what() ;
	}

	ASSERT_EQ(left, data.cend() - it)
		<< "Expected " << left
		<< " bytes left, got " << (data.cend() - it)
		<< " bytes left";
}

TEST(DeserializerTest, Undefined) {
	deserializesTo(AmfUndefined(), { 0x00 });
	deserializesTo(AmfUndefined(), { 0x00, 0x00 }, 1);
}

TEST(DeserializerTest, Null) {
	deserializesTo(AmfNull(), { 0x01 });
	deserializesTo(AmfNull(), { 0x01, 0x01 }, 1);
}

TEST(DeserializerTest, Bool) {
	deserializesTo(AmfBool(false), { 0x02 });
	deserializesTo(AmfBool(false), { 0x02, 0x02 }, 1);
	deserializesTo(AmfBool(true), { 0x03 });
	deserializesTo(AmfBool(true), { 0x03, 0x03 }, 1);
}

TEST(DeserializerTest, Integer) {
	deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e });
	deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e, 0x04 }, 1);
	deserializesTo(AmfInteger(0xffffffe), { 0x04, 0xbf, 0xff, 0xff, 0xfe });
}

TEST(DeserializerTest, Double) {
	deserializesTo(AmfDouble(0.5), { 0x05, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
	deserializesTo(AmfDouble(0.5), { 0x05, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00 }, 3);
}

TEST(DeserializerTest, String) {
	deserializesTo(AmfString("foo"), { 0x06, 0x07, 0x66, 0x6f, 0x6f });
	deserializesTo(AmfString("foo"), { 0x06, 0x07, 0x66, 0x6f, 0x6f, 0x06 }, 1);
}

TEST(DeserializerTest, XmlDoc) {
	deserializesTo(AmfXmlDocument(""), { 0x07, 0x01 });
	deserializesTo(AmfXmlDocument(""), { 0x07, 0x01, 0x07 }, 1);
	deserializesTo(AmfXmlDocument("foo"), { 0x07, 0x07, 0x66, 0x6f, 0x6f });
}

TEST(DeserializerTest, Date) {
	deserializesTo(AmfDate(136969002755210ll), { 0x08, 0x01, 0x42, 0xdf, 0x24,
		0xa5, 0x30, 0x49, 0x22, 0x80 });
	deserializesTo(AmfDate(136969002755210ll), { 0x08, 0x01, 0x42, 0xdf, 0x24,
		0xa5, 0x30, 0x49, 0x22, 0x80, 0x08 }, 1);
}

TEST(DeserializerTest, Array) {
	deserializesTo(AmfArray(), { 0x09, 0x01, 0x01 });
	deserializesTo(AmfArray(std::vector<AmfInteger> { 1, 2, 3 } ), {
		0x09, 0x07, 0x01, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, Xml) {
	deserializesTo(AmfXml(""), { 0x0b, 0x01 });
	deserializesTo(AmfXml(""), { 0x0b, 0x01, 0x0b }, 1);
	deserializesTo(AmfXml("foo"), { 0x0b, 0x07, 0x66, 0x6f, 0x6f });
}

TEST(DeserializerTest, Object) {
	deserializesTo(AmfObject("", false, false), { 0x0a, 0x03, 0x01 });
	deserializesTo(AmfObject("", true, false), { 0x0a, 0x0b, 0x01, 0x01, 0xff }, 1);
}

TEST(DeserializerTest, ByteArray) {
	deserializesTo(AmfByteArray(v8 { 1, 2, 3 }), { 0x0c, 0x07, 0x01, 0x02, 0x03 });
	deserializesTo(AmfByteArray(v8 { 1, 2, 3 }), { 0x0c, 0x07, 0x01, 0x02, 0x03, 0x0c }, 1);
}

TEST(DeserializerTest, VectorInt) {
	deserializesTo(AmfVector<int> { { 1 }, false}, { 0x0d, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x01 });
	deserializesTo(AmfVector<int> { { 2, 3 }, true}, { 0x0d, 0x05, 0x01,
		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, VectorUint) {
	deserializesTo(AmfVector<unsigned int> { { 1 }, false}, { 0x0e, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x01 });
	deserializesTo(AmfVector<unsigned int> { { 2, 3 }, true}, { 0x0e, 0x05, 0x01,
		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, VectorDouble) {
	deserializesTo(AmfVector<double> { { 0.5 }, false }, { 0x0f, 0x03, 0x00,
		0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
	deserializesTo(AmfVector<double> { { -1.2 }, true }, { 0x0f, 0x03, 0x01,
		0xbf, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xff }, 1);
}

TEST(DeserializerTest, VectorAmfItem) {
	AmfVector<AmfInteger> v({1, 2, 3}, "foo", false);
	// Need to pass a AmfVector<AmfItem> to compare against, as that's what
	// Deserializer::deserialize returns
	AmfVector<AmfItem> vc = v;
	v8 data {
		0x10, 0x07, 0x00,
		0x07, 0x66, 0x6f, 0x6f,
		0x04, 0x01,
		0x04, 0x02,
		0x04, 0x03
	};

	deserializesTo(vc, data);
}

TEST(DeserializerTest, InstanceContext) {
	AmfByteArray ba(v8 { 0x1 });
	v8 data {
		0x0c, 0x03, 0x01,
		0x0c, 0x00,
	};

	Deserializer d;
	auto it = data.cbegin();
	auto end = data.cend();
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	ASSERT_EQ(data.cbegin() + 3, it);
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	ASSERT_EQ(end, it);
}

TEST(DeserializerTest, ClearContext) {
	AmfByteArray ba(v8 { 0x1 });
	v8 data {
		0x0c, 0x03, 0x01,
		0x0c, 0x00,
	};

	Deserializer d;
	auto it = data.cbegin();
	auto end = data.cend();
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	d.clearContext();
	ASSERT_THROW(d.deserialize(it, end), std::out_of_range);
}

TEST(DeserializerTest, UnknownType) {
	Deserializer d;
	ASSERT_THROW(d.deserialize({ AMF_DICTIONARY + 1 }), std::invalid_argument);
	ASSERT_THROW(d.deserialize({ 0xff }), std::invalid_argument);
}
<commit_msg>Add test for reference with incorrect type.<commit_after>#include "amftest.hpp"

#include "deserializer.hpp"
#include "deserializationcontext.hpp"

#include "types/amfarray.hpp"
#include "types/amfbool.hpp"
#include "types/amfbytearray.hpp"
#include "types/amfdate.hpp"
#include "types/amfdictionary.hpp"
#include "types/amfdouble.hpp"
#include "types/amfinteger.hpp"
#include "types/amfnull.hpp"
#include "types/amfobject.hpp"
#include "types/amfstring.hpp"
#include "types/amfundefined.hpp"
#include "types/amfvector.hpp"
#include "types/amfxml.hpp"
#include "types/amfxmldocument.hpp"

#include "utils/amfitemptr.hpp"

template<typename T>
static void deserializesTo(const T& expected, v8 data, int left = 0) {
	SCOPED_TRACE(::testing::PrintToString(expected) + " = " + ::testing::PrintToString(data));

	auto it = data.cbegin();
	try {
		Deserializer d;
		T i = d.deserialize(it, data.cend()).as<T>();
		ASSERT_EQ(expected, i);
		T j = *d.deserialize(data).asPtr<T>();
		ASSERT_EQ(expected, j);
		DeserializationContext ctx;
		T k = Deserializer::deserialize(data, ctx).as<T>();
		ASSERT_EQ(expected, k);
	} catch(std::exception& e) {
		FAIL() << "Deserialization threw exception:\n"
		       << e.what() ;
	}

	ASSERT_EQ(left, data.cend() - it)
		<< "Expected " << left
		<< " bytes left, got " << (data.cend() - it)
		<< " bytes left";
}

TEST(DeserializerTest, Undefined) {
	deserializesTo(AmfUndefined(), { 0x00 });
	deserializesTo(AmfUndefined(), { 0x00, 0x00 }, 1);
}

TEST(DeserializerTest, Null) {
	deserializesTo(AmfNull(), { 0x01 });
	deserializesTo(AmfNull(), { 0x01, 0x01 }, 1);
}

TEST(DeserializerTest, Bool) {
	deserializesTo(AmfBool(false), { 0x02 });
	deserializesTo(AmfBool(false), { 0x02, 0x02 }, 1);
	deserializesTo(AmfBool(true), { 0x03 });
	deserializesTo(AmfBool(true), { 0x03, 0x03 }, 1);
}

TEST(DeserializerTest, Integer) {
	deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e });
	deserializesTo(AmfInteger(0x7e), { 0x04, 0x7e, 0x04 }, 1);
	deserializesTo(AmfInteger(0xffffffe), { 0x04, 0xbf, 0xff, 0xff, 0xfe });
}

TEST(DeserializerTest, Double) {
	deserializesTo(AmfDouble(0.5), { 0x05, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
	deserializesTo(AmfDouble(0.5), { 0x05, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00 }, 3);
}

TEST(DeserializerTest, String) {
	deserializesTo(AmfString("foo"), { 0x06, 0x07, 0x66, 0x6f, 0x6f });
	deserializesTo(AmfString("foo"), { 0x06, 0x07, 0x66, 0x6f, 0x6f, 0x06 }, 1);
}

TEST(DeserializerTest, XmlDoc) {
	deserializesTo(AmfXmlDocument(""), { 0x07, 0x01 });
	deserializesTo(AmfXmlDocument(""), { 0x07, 0x01, 0x07 }, 1);
	deserializesTo(AmfXmlDocument("foo"), { 0x07, 0x07, 0x66, 0x6f, 0x6f });
}

TEST(DeserializerTest, Date) {
	deserializesTo(AmfDate(136969002755210ll), { 0x08, 0x01, 0x42, 0xdf, 0x24,
		0xa5, 0x30, 0x49, 0x22, 0x80 });
	deserializesTo(AmfDate(136969002755210ll), { 0x08, 0x01, 0x42, 0xdf, 0x24,
		0xa5, 0x30, 0x49, 0x22, 0x80, 0x08 }, 1);
}

TEST(DeserializerTest, Array) {
	deserializesTo(AmfArray(), { 0x09, 0x01, 0x01 });
	deserializesTo(AmfArray(std::vector<AmfInteger> { 1, 2, 3 } ), {
		0x09, 0x07, 0x01, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, Xml) {
	deserializesTo(AmfXml(""), { 0x0b, 0x01 });
	deserializesTo(AmfXml(""), { 0x0b, 0x01, 0x0b }, 1);
	deserializesTo(AmfXml("foo"), { 0x0b, 0x07, 0x66, 0x6f, 0x6f });
}

TEST(DeserializerTest, Object) {
	deserializesTo(AmfObject("", false, false), { 0x0a, 0x03, 0x01 });
	deserializesTo(AmfObject("", true, false), { 0x0a, 0x0b, 0x01, 0x01, 0xff }, 1);
}

TEST(DeserializerTest, ByteArray) {
	deserializesTo(AmfByteArray(v8 { 1, 2, 3 }), { 0x0c, 0x07, 0x01, 0x02, 0x03 });
	deserializesTo(AmfByteArray(v8 { 1, 2, 3 }), { 0x0c, 0x07, 0x01, 0x02, 0x03, 0x0c }, 1);
}

TEST(DeserializerTest, VectorInt) {
	deserializesTo(AmfVector<int> { { 1 }, false}, { 0x0d, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x01 });
	deserializesTo(AmfVector<int> { { 2, 3 }, true}, { 0x0d, 0x05, 0x01,
		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, VectorUint) {
	deserializesTo(AmfVector<unsigned int> { { 1 }, false}, { 0x0e, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x01 });
	deserializesTo(AmfVector<unsigned int> { { 2, 3 }, true}, { 0x0e, 0x05, 0x01,
		0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xff }, 1);
}

TEST(DeserializerTest, VectorDouble) {
	deserializesTo(AmfVector<double> { { 0.5 }, false }, { 0x0f, 0x03, 0x00,
		0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
	deserializesTo(AmfVector<double> { { -1.2 }, true }, { 0x0f, 0x03, 0x01,
		0xbf, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xff }, 1);
}

TEST(DeserializerTest, VectorAmfItem) {
	AmfVector<AmfInteger> v({1, 2, 3}, "foo", false);
	// Need to pass a AmfVector<AmfItem> to compare against, as that's what
	// Deserializer::deserialize returns
	AmfVector<AmfItem> vc = v;
	v8 data {
		0x10, 0x07, 0x00,
		0x07, 0x66, 0x6f, 0x6f,
		0x04, 0x01,
		0x04, 0x02,
		0x04, 0x03
	};

	deserializesTo(vc, data);
}

TEST(DeserializerTest, InstanceContext) {
	AmfByteArray ba(v8 { 0x1 });
	v8 data {
		0x0c, 0x03, 0x01,
		0x0c, 0x00,
	};

	Deserializer d;
	auto it = data.cbegin();
	auto end = data.cend();
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	ASSERT_EQ(data.cbegin() + 3, it);
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	ASSERT_EQ(end, it);
}

TEST(DeserializerTest, ClearContext) {
	AmfByteArray ba(v8 { 0x1 });
	v8 data {
		0x0c, 0x03, 0x01,
		0x0c, 0x00,
	};

	Deserializer d;
	auto it = data.cbegin();
	auto end = data.cend();
	ASSERT_EQ(ba, d.deserialize(it, end).as<AmfByteArray>());
	d.clearContext();
	ASSERT_THROW(d.deserialize(it, end), std::out_of_range);
}

TEST(DeserializerTest, UnknownType) {
	Deserializer d;
	ASSERT_THROW(d.deserialize({ AMF_DICTIONARY + 1 }), std::invalid_argument);
	ASSERT_THROW(d.deserialize({ 0xff }), std::invalid_argument);
}

TEST(DeserializerTest, IncorrectTypeRef) {
	Deserializer d;
	ASSERT_EQ(AmfArray(), d.deserialize(v8 { 0x09, 0x01, 0x01 }).as<AmfArray>());
	ASSERT_EQ(AmfArray(), d.deserialize(v8 { 0x09, 0x00 }).as<AmfArray>());
	ASSERT_THROW(d.deserialize(v8 { 0x10, 0x00 }), std::invalid_argument);
}
<|endoftext|>


<commit_before>#include <iostream>

int main() {
  std::cout << "Fractalogy!\n";

  return 0;
}

<commit_msg>Add the iteration function for the fractals<commit_after>#include <iostream>
#include <complex>

using std::cout;
using std::complex;
using std::exp;
using std::norm;

/// returns -1 on failing to escape
int iteration(complex<double> c, int limit = 1000) {
  int i = 0;
  double n;
  complex<double> z(0, 0);
  while ((n = norm(z)) < 4 && i < limit) {
    z = exp(z) - c;
    ++i;
  }

  if (n < 4)
    return -1;
  else
    return i;
}

int main() {
  std::cout << "Fractalogy!\n";
  double lower = -2, upper = 2;
  int width = 100, height = 100;
  for (int i = 0; i <= width; ++i) {
    for (int j = 0; j <= height; ++j) {
      complex<double> t;
      t = complex<double>(lower + (upper - lower) * i / width, lower + (upper - lower) * j / height);
      cout << iteration(t) << " ";
    }
    cout << std::endl;
  }

  return 0;
}

<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkPixelRef.h"

bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
    switch (bm.config()) {
        case SkBitmap::kA8_Config:
        case SkBitmap::kRGB_565_Config:
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
                return true;
        default:
            break;
    }
    return false;
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy) {
    fRawBitmap = src;
    fState.fTileModeX = (uint8_t)tmx;
    fState.fTileModeY = (uint8_t)tmy;
    fFlags = 0; // computed in setContext
}

SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    buffer.readBitmap(&fRawBitmap);
    fRawBitmap.setImmutable();
    fState.fTileModeX = buffer.readUInt();
    fState.fTileModeY = buffer.readUInt();
    fFlags = 0; // computed in setContext
}

SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
                                                   SkMatrix* texM,
                                                   TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fState.fTileModeX;
        xy[1] = (TileMode)fState.fTileModeY;
    }
    return kDefault_BitmapType;
}

void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);

    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fState.fTileModeX);
    buffer.writeUInt(fState.fTileModeY);
}

static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

bool SkBitmapProcShader::setContext(const SkBitmap& device,
                                    const SkPaint& paint,
                                    const SkMatrix& matrix) {
    // do this first, so we have a correct inverse matrix
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    fState.fOrigBitmap = fRawBitmap;
    fState.fOrigBitmap.lockPixels();
    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
        fState.fOrigBitmap.unlockPixels();
        return false;
    }

    const SkBitmap& bitmap = *fState.fBitmap;
    bool bitmapIsOpaque = bitmap.isOpaque();

    // update fFlags
    uint32_t flags = 0;
    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
        flags |= kOpaqueAlpha_Flag;
    }

    switch (bitmap.config()) {
        case SkBitmap::kRGB_565_Config:
            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
            break;
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
            if (bitmapIsOpaque) {
                flags |= kHasSpan16_Flag;
            }
            break;
        case SkBitmap::kA8_Config:
            break;  // never set kHasSpan16_Flag
        default:
            break;
    }

    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
        // gradients can auto-dither in their 16bit sampler, but we don't so
        // we clear the flag here.
        flags &= ~kHasSpan16_Flag;
    }

    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
    if (1 == bitmap.height() &&
            only_scale_and_translate(this->getTotalInverse())) {
        flags |= kConstInY32_Flag;
        if (flags & kHasSpan16_Flag) {
            flags |= kConstInY16_Flag;
        }
    }

    fFlags = flags;
    return true;
}

void SkBitmapProcShader::endContext() {
    fState.fOrigBitmap.unlockPixels();
    this->INHERITED::endContext();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    if (fState.getShaderProc32()) {
        *ctx = &fState;
        return (ShadeProc)fState.getShaderProc32();
    }
    return NULL;
}

void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc16()) {
        state.getShaderProc16()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    int max = fState.maxCountForBufferSize(sizeof(buffer));

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        mproc(state, buffer, n, x, y);
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        x += n;
        dstC += n;
    }
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.config()) {
        case SkBitmap::kARGB_8888_Config:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case SkBitmap::kRGB_565_Config:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case SkBitmap::kIndex8_Config:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

#include "SkTemplatesPriv.h"

static bool bitmapIsTooBig(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    const int maxSize = 65535;

    return bm.width() > maxSize || bm.height() > maxSize;
}

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy,
                                       void* storage, size_t storageSize) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmapIsTooBig(src)) {
        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    }
    else if (canUseColorShader(src, &color)) {
        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
                              (color));
    } else {
        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                              storageSize, (src, tmx, tmy));
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

static const char* gTileModeName[] = {
    "clamp", "repeat", "mirror"
};

bool SkBitmapProcShader::toDumpString(SkString* str) const {
    str->printf("BitmapShader: [%d %d %d",
                fRawBitmap.width(), fRawBitmap.height(),
                fRawBitmap.bytesPerPixel());

    // add the pixelref
    SkPixelRef* pr = fRawBitmap.pixelRef();
    if (pr) {
        const char* uri = pr->getURI();
        if (uri) {
            str->appendf(" \"%s\"", uri);
        }
    }

    // add the (optional) matrix
    {
        if (this->hasLocalMatrix()) {
            SkString info;
            this->getLocalMatrix().toDumpString(&info);
            str->appendf(" %s", info.c_str());
        }
    }

    str->appendf(" [%s %s]]",
                 gTileModeName[fState.fTileModeX],
                 gTileModeName[fState.fTileModeY]);
    return true;
}
///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "effects/GrSingleTextureEffect.h"
#include "SkGr.h"

GrEffect* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    if (this->hasLocalMatrix()) {
        SkMatrix inverse;
        if (!this->getLocalMatrix().invert(&inverse)) {
            return NULL;
        }
        matrix.preConcat(inverse);
    }
    SkShader::TileMode tm[] = {
        (TileMode)fState.fTileModeX,
        (TileMode)fState.fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture.
    GrTextureParams params(tm, paint.isFilterBitmap());
    GrTexture* texture = GrLockCachedBitmapTexture(context, fRawBitmap, &params);

    if (NULL == texture) {
        SkDebugf("Couldn't convert bitmap to texture.\n");
        return NULL;
    }

    GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params));
    GrUnlockCachedBitmapTexture(texture);
    return effect;
}
#endif
<commit_msg>call endContext() if we have to return false from setContext(), to keep the debugging fInSetContext flag up-to-date.<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkPixelRef.h"

bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
    switch (bm.config()) {
        case SkBitmap::kA8_Config:
        case SkBitmap::kRGB_565_Config:
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
                return true;
        default:
            break;
    }
    return false;
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy) {
    fRawBitmap = src;
    fState.fTileModeX = (uint8_t)tmx;
    fState.fTileModeY = (uint8_t)tmy;
    fFlags = 0; // computed in setContext
}

SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    buffer.readBitmap(&fRawBitmap);
    fRawBitmap.setImmutable();
    fState.fTileModeX = buffer.readUInt();
    fState.fTileModeY = buffer.readUInt();
    fFlags = 0; // computed in setContext
}

SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
                                                   SkMatrix* texM,
                                                   TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fState.fTileModeX;
        xy[1] = (TileMode)fState.fTileModeY;
    }
    return kDefault_BitmapType;
}

void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);

    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fState.fTileModeX);
    buffer.writeUInt(fState.fTileModeY);
}

static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

bool SkBitmapProcShader::setContext(const SkBitmap& device,
                                    const SkPaint& paint,
                                    const SkMatrix& matrix) {
    // do this first, so we have a correct inverse matrix
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    fState.fOrigBitmap = fRawBitmap;
    fState.fOrigBitmap.lockPixels();
    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
        fState.fOrigBitmap.unlockPixels();
        this->INHERITED::endContext();
        return false;
    }

    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
        fState.fOrigBitmap.unlockPixels();
        this->INHERITED::endContext();
        return false;
    }

    const SkBitmap& bitmap = *fState.fBitmap;
    bool bitmapIsOpaque = bitmap.isOpaque();

    // update fFlags
    uint32_t flags = 0;
    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
        flags |= kOpaqueAlpha_Flag;
    }

    switch (bitmap.config()) {
        case SkBitmap::kRGB_565_Config:
            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
            break;
        case SkBitmap::kIndex8_Config:
        case SkBitmap::kARGB_8888_Config:
            if (bitmapIsOpaque) {
                flags |= kHasSpan16_Flag;
            }
            break;
        case SkBitmap::kA8_Config:
            break;  // never set kHasSpan16_Flag
        default:
            break;
    }

    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
        // gradients can auto-dither in their 16bit sampler, but we don't so
        // we clear the flag here.
        flags &= ~kHasSpan16_Flag;
    }

    // if we're only 1-pixel heigh, and we don't rotate, then we can claim this
    if (1 == bitmap.height() &&
            only_scale_and_translate(this->getTotalInverse())) {
        flags |= kConstInY32_Flag;
        if (flags & kHasSpan16_Flag) {
            flags |= kConstInY16_Flag;
        }
    }

    fFlags = flags;
    return true;
}

void SkBitmapProcShader::endContext() {
    fState.fOrigBitmap.unlockPixels();
    this->INHERITED::endContext();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    if (fState.getShaderProc32()) {
        *ctx = &fState;
        return (ShadeProc)fState.getShaderProc32();
    }
    return NULL;
}

void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    const SkBitmapProcState& state = fState;
    if (state.getShaderProc16()) {
        state.getShaderProc16()(state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    int max = fState.maxCountForBufferSize(sizeof(buffer));

    SkASSERT(state.fBitmap->getPixels());
    SkASSERT(state.fBitmap->pixelRef() == NULL ||
             state.fBitmap->pixelRef()->isLocked());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        mproc(state, buffer, n, x, y);
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        x += n;
        dstC += n;
    }
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.config()) {
        case SkBitmap::kARGB_8888_Config:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case SkBitmap::kRGB_565_Config:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case SkBitmap::kIndex8_Config:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

#include "SkTemplatesPriv.h"

static bool bitmapIsTooBig(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    const int maxSize = 65535;

    return bm.width() > maxSize || bm.height() > maxSize;
}

SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                       TileMode tmx, TileMode tmy,
                                       void* storage, size_t storageSize) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmapIsTooBig(src)) {
        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    }
    else if (canUseColorShader(src, &color)) {
        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
                              (color));
    } else {
        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
                              storageSize, (src, tmx, tmy));
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

static const char* gTileModeName[] = {
    "clamp", "repeat", "mirror"
};

bool SkBitmapProcShader::toDumpString(SkString* str) const {
    str->printf("BitmapShader: [%d %d %d",
                fRawBitmap.width(), fRawBitmap.height(),
                fRawBitmap.bytesPerPixel());

    // add the pixelref
    SkPixelRef* pr = fRawBitmap.pixelRef();
    if (pr) {
        const char* uri = pr->getURI();
        if (uri) {
            str->appendf(" \"%s\"", uri);
        }
    }

    // add the (optional) matrix
    {
        if (this->hasLocalMatrix()) {
            SkString info;
            this->getLocalMatrix().toDumpString(&info);
            str->appendf(" %s", info.c_str());
        }
    }

    str->appendf(" [%s %s]]",
                 gTileModeName[fState.fTileModeX],
                 gTileModeName[fState.fTileModeY]);
    return true;
}
///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "effects/GrSingleTextureEffect.h"
#include "SkGr.h"

GrEffect* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    if (this->hasLocalMatrix()) {
        SkMatrix inverse;
        if (!this->getLocalMatrix().invert(&inverse)) {
            return NULL;
        }
        matrix.preConcat(inverse);
    }
    SkShader::TileMode tm[] = {
        (TileMode)fState.fTileModeX,
        (TileMode)fState.fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture.
    GrTextureParams params(tm, paint.isFilterBitmap());
    GrTexture* texture = GrLockCachedBitmapTexture(context, fRawBitmap, &params);

    if (NULL == texture) {
        SkDebugf("Couldn't convert bitmap to texture.\n");
        return NULL;
    }

    GrEffect* effect = SkNEW_ARGS(GrSingleTextureEffect, (texture, matrix, params));
    GrUnlockCachedBitmapTexture(texture);
    return effect;
}
#endif
<|endoftext|>


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

#include "SkBitmapProcShader.h"
#include "SkBitmapProcState.h"
#include "SkBitmapProvider.h"
#include "SkColorPriv.h"
#include "SkErrorInternals.h"
#include "SkPixelRef.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "SkGrPriv.h"
#include "effects/GrBicubicEffect.h"
#include "effects/GrSimpleTextureEffect.h"
#endif

size_t SkBitmapProcShader::ContextSize() {
    // The SkBitmapProcState is stored outside of the context object, with the context holding
    // a pointer to it.
    return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
                                       const SkMatrix* localMatrix)
        : INHERITED(localMatrix) {
    fRawBitmap = src;
    fTileModeX = (uint8_t)tmx;
    fTileModeY = (uint8_t)tmy;
}

bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fTileModeX;
        xy[1] = (TileMode)fTileModeY;
    }
    return true;
}

SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
    SkMatrix lm;
    buffer.readMatrix(&lm);
    SkBitmap bm;
    if (!buffer.readBitmap(&bm)) {
        return nullptr;
    }
    bm.setImmutable();
    TileMode mx = (TileMode)buffer.readUInt();
    TileMode my = (TileMode)buffer.readUInt();
    return SkShader::CreateBitmapShader(bm, mx, my, &lm);
}

void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
    buffer.writeMatrix(this->getLocalMatrix());
    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fTileModeX);
    buffer.writeUInt(fTileModeY);
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
                                                   TileMode tmx, TileMode tmy,
                                                   const SkBitmapProvider& provider,
                                                   const ContextRec& rec, void* storage) {
    SkMatrix totalInverse;
    // Do this first, so we know the matrix can be inverted.
    if (!shader.computeTotalInverse(rec, &totalInverse)) {
        return nullptr;
    }

    void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
    SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);

    SkASSERT(state);
    if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
        state->~SkBitmapProcState();
        return nullptr;
    }

    return new (storage) BitmapProcShaderContext(shader, rec, state);
}

SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
    return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
                       SkBitmapProvider(fRawBitmap), rec, storage);
}

SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader,
                                                                     const ContextRec& rec,
                                                                     SkBitmapProcState* state)
    : INHERITED(shader, rec)
    , fState(state)
{
    fFlags = 0;
    if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
        fFlags |= kOpaqueAlpha_Flag;
    }
}

SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
    // The bitmap proc state has been created outside of the context on memory that will be freed
    // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
    fState->~SkBitmapProcState();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
                                                            int count) {
    const SkBitmapProcState& state = *fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(&state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fPixmap.addr());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
    if (fState->getShaderProc32()) {
        *ctx = fState;
        return (ShadeProc)fState->getShaderProc32();
    }
    return nullptr;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    // HWUI does not support color shaders (see b/22390304)
    return false;
#endif

    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.colorType()) {
        case kN32_SkColorType:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case kRGB_565_SkColorType:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case kIndex_8_SkColorType:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

static bool bitmap_is_too_big(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    static const int kMaxSize = 65535;

    return bm.width() > kMaxSize || bm.height() > kMaxSize;
}

SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
                               SkShader::TileMode tmy, const SkMatrix* localMatrix,
                               SkTBlitterAllocator* allocator) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmap_is_too_big(src)) {
        if (nullptr == allocator) {
            shader = new SkEmptyShader;
        } else {
            shader = allocator->createT<SkEmptyShader>();
        }
    } else if (can_use_color_shader(src, &color)) {
        if (nullptr == allocator) {
            shader = new SkColorShader(color);
        } else {
            shader = allocator->createT<SkColorShader>(color);
        }
    } else {
        if (nullptr == allocator) {
            shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
        } else {
            shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
        }
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

#ifndef SK_IGNORE_TO_STRING
void SkBitmapProcShader::toString(SkString* str) const {
    static const char* gTileModeName[SkShader::kTileModeCount] = {
        "clamp", "repeat", "mirror"
    };

    str->append("BitmapShader: (");

    str->appendf("(%s, %s)",
                 gTileModeName[fTileModeX],
                 gTileModeName[fTileModeY]);

    str->append(" ");
    fRawBitmap.toString(str);

    this->INHERITED::toString(str);

    str->append(")");
}
#endif

///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "SkGr.h"
#include "effects/GrSimpleTextureEffect.h"

const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
                                             const SkMatrix& viewM, const SkMatrix* localMatrix,
                                             SkFilterQuality filterQuality) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    SkMatrix lmInverse;
    if (!this->getLocalMatrix().invert(&lmInverse)) {
        return nullptr;
    }
    if (localMatrix) {
        SkMatrix inv;
        if (!localMatrix->invert(&inv)) {
            return nullptr;
        }
        lmInverse.postConcat(inv);
    }
    matrix.preConcat(lmInverse);

    SkShader::TileMode tm[] = {
        (TileMode)fTileModeX,
        (TileMode)fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture. In two places below
    // we check the matrix scale factors to determine how to interpret the filter quality setting.
    // This completely ignores the complexity of the drawVertices case where explicit local coords
    // are provided by the caller.
    bool doBicubic;
    GrTextureParams::FilterMode textureFilterMode =
            GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
                                            &doBicubic);
    GrTextureParams params(tm, textureFilterMode);
    SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));

    if (!texture) {
        SkErrorInternals::SetError( kInternalError_SkError,
                                    "Couldn't convert bitmap to texture.");
        return nullptr;
    }

    SkAutoTUnref<const GrFragmentProcessor> inner;
    if (doBicubic) {
        inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
    } else {
        inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
    }

    if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
        return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(inner);
}

#endif
<commit_msg>restore lost optimization when the shader can report const_in_y<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBitmapProcShader.h"
#include "SkBitmapProcState.h"
#include "SkBitmapProvider.h"
#include "SkColorPriv.h"
#include "SkErrorInternals.h"
#include "SkPixelRef.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "SkGrPriv.h"
#include "effects/GrBicubicEffect.h"
#include "effects/GrSimpleTextureEffect.h"
#endif

size_t SkBitmapProcShader::ContextSize() {
    // The SkBitmapProcState is stored outside of the context object, with the context holding
    // a pointer to it.
    return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
}

SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
                                       const SkMatrix* localMatrix)
        : INHERITED(localMatrix) {
    fRawBitmap = src;
    fTileModeX = (uint8_t)tmx;
    fTileModeY = (uint8_t)tmy;
}

bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
    if (texture) {
        *texture = fRawBitmap;
    }
    if (texM) {
        texM->reset();
    }
    if (xy) {
        xy[0] = (TileMode)fTileModeX;
        xy[1] = (TileMode)fTileModeY;
    }
    return true;
}

SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
    SkMatrix lm;
    buffer.readMatrix(&lm);
    SkBitmap bm;
    if (!buffer.readBitmap(&bm)) {
        return nullptr;
    }
    bm.setImmutable();
    TileMode mx = (TileMode)buffer.readUInt();
    TileMode my = (TileMode)buffer.readUInt();
    return SkShader::CreateBitmapShader(bm, mx, my, &lm);
}

void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
    buffer.writeMatrix(this->getLocalMatrix());
    buffer.writeBitmap(fRawBitmap);
    buffer.writeUInt(fTileModeX);
    buffer.writeUInt(fTileModeY);
}

bool SkBitmapProcShader::isOpaque() const {
    return fRawBitmap.isOpaque();
}

SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
                                                   TileMode tmx, TileMode tmy,
                                                   const SkBitmapProvider& provider,
                                                   const ContextRec& rec, void* storage) {
    SkMatrix totalInverse;
    // Do this first, so we know the matrix can be inverted.
    if (!shader.computeTotalInverse(rec, &totalInverse)) {
        return nullptr;
    }

    void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
    SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);

    SkASSERT(state);
    if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
        state->~SkBitmapProcState();
        return nullptr;
    }

    return new (storage) BitmapProcShaderContext(shader, rec, state);
}

SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
    return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
                       SkBitmapProvider(fRawBitmap), rec, storage);
}

static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}

SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader,
                                                                     const ContextRec& rec,
                                                                     SkBitmapProcState* state)
    : INHERITED(shader, rec)
    , fState(state)
{
    fFlags = 0;
    if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
        fFlags |= kOpaqueAlpha_Flag;
    }

    if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
        fFlags |= kConstInY32_Flag;
    }
}

SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
    // The bitmap proc state has been created outside of the context on memory that will be freed
    // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
    fState->~SkBitmapProcState();
}

#define BUF_MAX     128

#define TEST_BUFFER_OVERRITEx

#ifdef TEST_BUFFER_OVERRITE
    #define TEST_BUFFER_EXTRA   32
    #define TEST_PATTERN    0x88888888
#else
    #define TEST_BUFFER_EXTRA   0
#endif

void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
                                                            int count) {
    const SkBitmapProcState& state = *fState;
    if (state.getShaderProc32()) {
        state.getShaderProc32()(&state, x, y, dstC, count);
        return;
    }

    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);

    SkASSERT(state.fPixmap.addr());

    for (;;) {
        int n = count;
        if (n > max) {
            n = max;
        }
        SkASSERT(n > 0 && n < BUF_MAX*2);
#ifdef TEST_BUFFER_OVERRITE
        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
            buffer[BUF_MAX + i] = TEST_PATTERN;
        }
#endif
        mproc(state, buffer, n, x, y);
#ifdef TEST_BUFFER_OVERRITE
        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
        }
#endif
        sproc(state, buffer, n, dstC);

        if ((count -= n) == 0) {
            break;
        }
        SkASSERT(count > 0);
        x += n;
        dstC += n;
    }
}

SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
    if (fState->getShaderProc32()) {
        *ctx = fState;
        return (ShadeProc)fState->getShaderProc32();
    }
    return nullptr;
}

///////////////////////////////////////////////////////////////////////////////

#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
#include "SkEmptyShader.h"

// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    // HWUI does not support color shaders (see b/22390304)
    return false;
#endif

    if (1 != bm.width() || 1 != bm.height()) {
        return false;
    }

    SkAutoLockPixels alp(bm);
    if (!bm.readyToDraw()) {
        return false;
    }

    switch (bm.colorType()) {
        case kN32_SkColorType:
            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
            return true;
        case kRGB_565_SkColorType:
            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
            return true;
        case kIndex_8_SkColorType:
            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
            return true;
        default: // just skip the other configs for now
            break;
    }
    return false;
}

static bool bitmap_is_too_big(const SkBitmap& bm) {
    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    // communicates between its matrix-proc and its sampler-proc. Until we can
    // widen that, we have to reject bitmaps that are larger.
    //
    static const int kMaxSize = 65535;

    return bm.width() > kMaxSize || bm.height() > kMaxSize;
}

SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
                               SkShader::TileMode tmy, const SkMatrix* localMatrix,
                               SkTBlitterAllocator* allocator) {
    SkShader* shader;
    SkColor color;
    if (src.isNull() || bitmap_is_too_big(src)) {
        if (nullptr == allocator) {
            shader = new SkEmptyShader;
        } else {
            shader = allocator->createT<SkEmptyShader>();
        }
    } else if (can_use_color_shader(src, &color)) {
        if (nullptr == allocator) {
            shader = new SkColorShader(color);
        } else {
            shader = allocator->createT<SkColorShader>(color);
        }
    } else {
        if (nullptr == allocator) {
            shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
        } else {
            shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
        }
    }
    return shader;
}

///////////////////////////////////////////////////////////////////////////////

#ifndef SK_IGNORE_TO_STRING
void SkBitmapProcShader::toString(SkString* str) const {
    static const char* gTileModeName[SkShader::kTileModeCount] = {
        "clamp", "repeat", "mirror"
    };

    str->append("BitmapShader: (");

    str->appendf("(%s, %s)",
                 gTileModeName[fTileModeX],
                 gTileModeName[fTileModeY]);

    str->append(" ");
    fRawBitmap.toString(str);

    this->INHERITED::toString(str);

    str->append(")");
}
#endif

///////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrTextureAccess.h"
#include "SkGr.h"
#include "effects/GrSimpleTextureEffect.h"

const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
                                             const SkMatrix& viewM, const SkMatrix* localMatrix,
                                             SkFilterQuality filterQuality) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    SkMatrix lmInverse;
    if (!this->getLocalMatrix().invert(&lmInverse)) {
        return nullptr;
    }
    if (localMatrix) {
        SkMatrix inv;
        if (!localMatrix->invert(&inv)) {
            return nullptr;
        }
        lmInverse.postConcat(inv);
    }
    matrix.preConcat(lmInverse);

    SkShader::TileMode tm[] = {
        (TileMode)fTileModeX,
        (TileMode)fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture. In two places below
    // we check the matrix scale factors to determine how to interpret the filter quality setting.
    // This completely ignores the complexity of the drawVertices case where explicit local coords
    // are provided by the caller.
    bool doBicubic;
    GrTextureParams::FilterMode textureFilterMode =
            GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
                                            &doBicubic);
    GrTextureParams params(tm, textureFilterMode);
    SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));

    if (!texture) {
        SkErrorInternals::SetError( kInternalError_SkError,
                                    "Couldn't convert bitmap to texture.");
        return nullptr;
    }

    SkAutoTUnref<const GrFragmentProcessor> inner;
    if (doBicubic) {
        inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
    } else {
        inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
    }

    if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
        return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(inner);
}

#endif
<|endoftext|>