<commit_before>/*  junctions_extractor.h -- Declarations for `junctions extract` command

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

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 <algorithm>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include "common.h"
#include "junctions_extractor.h"
#include "sam.h"
#include "hts.h"
#include "faidx.h"
#include "kstring.h"

using namespace std;

//Parse the options passed to this tool
int JunctionsExtractor::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    stringstream help_ss;
    while((c = getopt(argc, argv, "ha:i:I:o:r:")) != -1) {
        switch(c) {
            case 'a':
                min_anchor_length_ = atoi(optarg);
                break;
            case 'i':
                min_intron_length_ = atoi(optarg);
                break;
            case 'I':
                max_intron_length_ = atoi(optarg);
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            case 'r':
                region_ = string(optarg);
                break;
            case 'h':
                usage(help_ss);
                throw cmdline_help_exception(help_ss.str());
            case '?':
            default:
                throw runtime_error("Error parsing inputs!");
        }
    }
    if(argc == optind) {
        throw runtime_error("\nError parsing inputs!");
    }
    bam_ = string(argv[optind]);
    cerr << endl << "Minimum junction anchor length: " << min_anchor_length_;
    cerr << endl << "Minimum intron length: " << min_intron_length_;
    cerr << endl << "Maximum intron length: " << max_intron_length_;
    cerr << endl << "Alignment: " << bam_;
    cerr << endl << "Output file: " << output_file_;
    cerr << endl;
    return 0;
}

//Usage statement for this tool
int JunctionsExtractor::usage(ostream& out) {
    out << "\nUsage:\t\t" << "regtools junctions extract [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    return 0;
}

//Get the BAM filename
string JunctionsExtractor::get_bam() {
    return bam_;
}

//Name the junction based on the number of junctions
// in the map.
string JunctionsExtractor::get_new_junction_name() {
    int index = junctions_.size() + 1;
    stringstream name_ss;
    name_ss << "JUNC" << setfill('0') << setw(8) << index;
    return name_ss.str();
}

//Do some basic qc on the junction
bool JunctionsExtractor::junction_qc(Junction &j1) {
    if(j1.end - j1.start < min_intron_length_ ||
       j1.end - j1.start > max_intron_length_) {
        return false;
    }
    if(j1.start - j1.thick_start >= min_anchor_length_)
        j1.has_left_min_anchor = true;
    if(j1.thick_end - j1.end >= min_anchor_length_)
        j1.has_right_min_anchor = true;
    return true;
}

//Add a junction to the junctions map
//The read_count field is the number of reads supporting the junction.
int JunctionsExtractor::add_junction(Junction j1) {
    //Check junction_qc
    if(!junction_qc(j1)) {
        return 0;
    }

    //Construct key chr:start-end:strand
    stringstream s1;
    string start, end;
    s1 << j1.start; start = s1.str();
    s1 << j1.end; end = s1.str();
    string key = j1.chrom + string(":") + start + "-" + end + ":" + j1.strand;

    //Check if new junction
    if(!junctions_.count(key)) {
        j1.name = get_new_junction_name();
        j1.read_count = 1;
    } else { //existing junction
        Junction j0 = junctions_[key];
        //increment read count
        j1.read_count = j0.read_count + 1;
        //Keep the same name
        j1.name = j0.name;
        //Check if thick starts are any better
        if(j0.thick_start < j1.thick_start)
            j1.thick_start = j0.thick_start;
        if(j0.thick_end > j1.thick_end)
            j1.thick_end = j0.thick_end;
        //preserve min anchor information
        j1.has_left_min_anchor = j1.has_left_min_anchor || j0.has_left_min_anchor;
        j1.has_right_min_anchor = j1.has_right_min_anchor || j0.has_right_min_anchor;
    }
    //Add junction and check anchor while printing.
    junctions_[key] = j1;
    return 0;
}

//Print one junction
void JunctionsExtractor::print_one_junction(const Junction j1, ostream& out) {
    out << j1.chrom <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.name << "\t" << j1.read_count << "\t" << j1.strand <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.color << "\t" << j1.nblocks <<
        "\t" << j1.start - j1.thick_start << "," << j1.thick_end - j1.end <<
        "\t" << "0," << j1.end - j1.thick_start << endl;
}

//Print all the junctions - this function needs work
void JunctionsExtractor::print_all_junctions(ostream& out) {
    ofstream fout;
    if(output_file_ != string("NA")) {
        fout.open(output_file_.c_str());
    }
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    for(vector<Junction> :: iterator it = junctions_vector_.begin();
        it != junctions_vector_.end(); it++) {
        Junction j1 = *it;
        if(j1.has_left_min_anchor && j1.has_right_min_anchor) {
            if(fout.is_open())
                print_one_junction(j1, fout);
            else
                print_one_junction(j1, out);
        }
    }
    if(fout.is_open())
        fout.close();
}

//Get the strand from the XS aux tag
void JunctionsExtractor::set_junction_strand(bam1_t *aln, Junction& j1) {
    uint8_t *p = bam_aux_get(aln, "XS");
    if(p != NULL) {
        char strand = bam_aux2A(p);
        strand ? j1.strand = string(1, strand) : j1.strand = string(1, '?');
    } else {
        j1.strand = string(1, '?');
        return;
    }
}

//Parse junctions from the read and store in junction map
int JunctionsExtractor::parse_alignment_into_junctions(bam_hdr_t *header, bam1_t *aln) {
    int n_cigar = aln->core.n_cigar;
    if (n_cigar <= 1) // max one cigar operation exists(likely all matches)
        return 0;

    int chr_id = aln->core.tid;
    int read_pos = aln->core.pos;
    string chr(header->target_name[chr_id]);
    uint32_t *cigar = bam_get_cigar(aln);

    /*
    //Skip duplicates
    int flag = aln->core.flag;
    if(flag & 1024) {
        cerr << "Skipping read_pos " << read_pos << " flag " << flag << endl;
        return 0;
    }
    */

    Junction j1;
    j1.chrom = chr;
    j1.start = read_pos; //maintain start pos of junction
    j1.thick_start = read_pos;
    set_junction_strand(aln, j1);
    bool started_junction = false;
    for (int i = 0; i < n_cigar; ++i) {
        char op =
               bam_cigar_opchr(cigar[i]);
        int len =
               bam_cigar_oplen(cigar[i]);
        switch(op) {
            case 'N':
                if(!started_junction) {
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //Start the first one and remains started
                    started_junction = true;
                } else {
                    //Add the previous junction
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    j1.thick_start = j1.end;
                    j1.start = j1.thick_end;
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //For clarity - the next junction is now open
                    started_junction = true;
                }
                break;
            case '=':
            case 'M':
                if(!started_junction)
                    j1.start += len;
                else
                    j1.thick_end += len;
                break;
            //No mismatches allowed in anchor
            case 'D':
            case 'X':
                if(!started_junction) {
                    j1.start += len;
                    j1.thick_start = j1.start;
                } else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end + len;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'I':
            case 'S':
                if(!started_junction)
                    j1.thick_start = j1.start;
                else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'H':
                break;
            default:
                cerr << "Unknown cigar " << op;
                break;
        }
    }
    if(started_junction) {
        try {
            add_junction(j1);
        } catch (const std::logic_error& e) {
            cout << e.what() << '\n';
        }
    }
    return 0;
}

//The workhorse - identifies junctions from BAM
int JunctionsExtractor::identify_junctions_from_BAM() {
    if(!bam_.empty()) {
        //open BAM for reading
        samFile *in = sam_open(bam_.c_str(), "r");
        if(in == NULL) {
            throw runtime_error("Unable to open BAM/SAM file.");
        }
        //Load the index
        hts_idx_t *idx = sam_index_load(in, bam_.c_str());
        if(idx == NULL) {
            throw runtime_error("Unable to open BAM/SAM index."
                                " Make sure alignments are indexed");
        }
        //Get the header
        bam_hdr_t *header = sam_hdr_read(in);
        //Initialize iterator
        hts_itr_t *iter = NULL;
        //Move the iterator to the region we are interested in
        iter  = sam_itr_querys(idx, header, region_.c_str());
        if(header == NULL || iter == NULL) {
            sam_close(in);
            throw runtime_error("Unable to iterate to region within BAM.");
        }
        //Initiate the alignment record
        bam1_t *aln = bam_init1();
        while(sam_itr_next(in, iter, aln) >= 0) {
            parse_alignment_into_junctions(header, aln);
        }
        hts_itr_destroy(iter);
        hts_idx_destroy(idx);
        bam_destroy1(aln);
        bam_hdr_destroy(header);
        sam_close(in);
    }
    return 0;
}

//Create the junctions vector from the map
void JunctionsExtractor::create_junctions_vector() {
    for(map<string, Junction> :: iterator it = junctions_.begin();
        it != junctions_.end(); it++) {
        Junction j1 = it->second;
        junctions_vector_.push_back(j1);
    }
}

//Sort all the junctions by their position
void JunctionsExtractor::sort_junctions() {
    sort(junctions_vector_.begin(), junctions_vector_.end(), compare_junctions);
    junctions_sorted_ = true;
}
<commit_msg>Fix option parsing.<commit_after>/*  junctions_extractor.h -- Declarations for `junctions extract` command

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

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 <algorithm>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include "common.h"
#include "junctions_extractor.h"
#include "sam.h"
#include "hts.h"
#include "faidx.h"
#include "kstring.h"

using namespace std;

//Parse the options passed to this tool
int JunctionsExtractor::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    stringstream help_ss;
    while((c = getopt(argc, argv, "ha:i:I:o:r:")) != -1) {
        switch(c) {
            case 'a':
                min_anchor_length_ = atoi(optarg);
                break;
            case 'i':
                min_intron_length_ = atoi(optarg);
                break;
            case 'I':
                max_intron_length_ = atoi(optarg);
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            case 'r':
                region_ = string(optarg);
                break;
            case 'h':
                usage(help_ss);
                throw cmdline_help_exception(help_ss.str());
            case '?':
            default:
                throw runtime_error("Error parsing inputs!");
        }
    }
    if(argc - optind >= 1) {
        bam_ = string(argv[optind++]);
    }
    if(optind < argc || bam_ == "NA") {
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << endl << "Minimum junction anchor length: " << min_anchor_length_;
    cerr << endl << "Minimum intron length: " << min_intron_length_;
    cerr << endl << "Maximum intron length: " << max_intron_length_;
    cerr << endl << "Alignment: " << bam_;
    cerr << endl << "Output file: " << output_file_;
    cerr << endl;
    return 0;
}

//Usage statement for this tool
int JunctionsExtractor::usage(ostream& out) {
    out << "\nUsage:\t\t" << "regtools junctions extract [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    return 0;
}

//Get the BAM filename
string JunctionsExtractor::get_bam() {
    return bam_;
}

//Name the junction based on the number of junctions
// in the map.
string JunctionsExtractor::get_new_junction_name() {
    int index = junctions_.size() + 1;
    stringstream name_ss;
    name_ss << "JUNC" << setfill('0') << setw(8) << index;
    return name_ss.str();
}

//Do some basic qc on the junction
bool JunctionsExtractor::junction_qc(Junction &j1) {
    if(j1.end - j1.start < min_intron_length_ ||
       j1.end - j1.start > max_intron_length_) {
        return false;
    }
    if(j1.start - j1.thick_start >= min_anchor_length_)
        j1.has_left_min_anchor = true;
    if(j1.thick_end - j1.end >= min_anchor_length_)
        j1.has_right_min_anchor = true;
    return true;
}

//Add a junction to the junctions map
//The read_count field is the number of reads supporting the junction.
int JunctionsExtractor::add_junction(Junction j1) {
    //Check junction_qc
    if(!junction_qc(j1)) {
        return 0;
    }

    //Construct key chr:start-end:strand
    stringstream s1;
    string start, end;
    s1 << j1.start; start = s1.str();
    s1 << j1.end; end = s1.str();
    string key = j1.chrom + string(":") + start + "-" + end + ":" + j1.strand;

    //Check if new junction
    if(!junctions_.count(key)) {
        j1.name = get_new_junction_name();
        j1.read_count = 1;
    } else { //existing junction
        Junction j0 = junctions_[key];
        //increment read count
        j1.read_count = j0.read_count + 1;
        //Keep the same name
        j1.name = j0.name;
        //Check if thick starts are any better
        if(j0.thick_start < j1.thick_start)
            j1.thick_start = j0.thick_start;
        if(j0.thick_end > j1.thick_end)
            j1.thick_end = j0.thick_end;
        //preserve min anchor information
        j1.has_left_min_anchor = j1.has_left_min_anchor || j0.has_left_min_anchor;
        j1.has_right_min_anchor = j1.has_right_min_anchor || j0.has_right_min_anchor;
    }
    //Add junction and check anchor while printing.
    junctions_[key] = j1;
    return 0;
}

//Print one junction
void JunctionsExtractor::print_one_junction(const Junction j1, ostream& out) {
    out << j1.chrom <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.name << "\t" << j1.read_count << "\t" << j1.strand <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.color << "\t" << j1.nblocks <<
        "\t" << j1.start - j1.thick_start << "," << j1.thick_end - j1.end <<
        "\t" << "0," << j1.end - j1.thick_start << endl;
}

//Print all the junctions - this function needs work
void JunctionsExtractor::print_all_junctions(ostream& out) {
    ofstream fout;
    if(output_file_ != string("NA")) {
        fout.open(output_file_.c_str());
    }
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    for(vector<Junction> :: iterator it = junctions_vector_.begin();
        it != junctions_vector_.end(); it++) {
        Junction j1 = *it;
        if(j1.has_left_min_anchor && j1.has_right_min_anchor) {
            if(fout.is_open())
                print_one_junction(j1, fout);
            else
                print_one_junction(j1, out);
        }
    }
    if(fout.is_open())
        fout.close();
}

//Get the strand from the XS aux tag
void JunctionsExtractor::set_junction_strand(bam1_t *aln, Junction& j1) {
    uint8_t *p = bam_aux_get(aln, "XS");
    if(p != NULL) {
        char strand = bam_aux2A(p);
        strand ? j1.strand = string(1, strand) : j1.strand = string(1, '?');
    } else {
        j1.strand = string(1, '?');
        return;
    }
}

//Parse junctions from the read and store in junction map
int JunctionsExtractor::parse_alignment_into_junctions(bam_hdr_t *header, bam1_t *aln) {
    int n_cigar = aln->core.n_cigar;
    if (n_cigar <= 1) // max one cigar operation exists(likely all matches)
        return 0;

    int chr_id = aln->core.tid;
    int read_pos = aln->core.pos;
    string chr(header->target_name[chr_id]);
    uint32_t *cigar = bam_get_cigar(aln);

    /*
    //Skip duplicates
    int flag = aln->core.flag;
    if(flag & 1024) {
        cerr << "Skipping read_pos " << read_pos << " flag " << flag << endl;
        return 0;
    }
    */

    Junction j1;
    j1.chrom = chr;
    j1.start = read_pos; //maintain start pos of junction
    j1.thick_start = read_pos;
    set_junction_strand(aln, j1);
    bool started_junction = false;
    for (int i = 0; i < n_cigar; ++i) {
        char op =
               bam_cigar_opchr(cigar[i]);
        int len =
               bam_cigar_oplen(cigar[i]);
        switch(op) {
            case 'N':
                if(!started_junction) {
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //Start the first one and remains started
                    started_junction = true;
                } else {
                    //Add the previous junction
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    j1.thick_start = j1.end;
                    j1.start = j1.thick_end;
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //For clarity - the next junction is now open
                    started_junction = true;
                }
                break;
            case '=':
            case 'M':
                if(!started_junction)
                    j1.start += len;
                else
                    j1.thick_end += len;
                break;
            //No mismatches allowed in anchor
            case 'D':
            case 'X':
                if(!started_junction) {
                    j1.start += len;
                    j1.thick_start = j1.start;
                } else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end + len;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'I':
            case 'S':
                if(!started_junction)
                    j1.thick_start = j1.start;
                else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'H':
                break;
            default:
                cerr << "Unknown cigar " << op;
                break;
        }
    }
    if(started_junction) {
        try {
            add_junction(j1);
        } catch (const std::logic_error& e) {
            cout << e.what() << '\n';
        }
    }
    return 0;
}

//The workhorse - identifies junctions from BAM
int JunctionsExtractor::identify_junctions_from_BAM() {
    if(!bam_.empty()) {
        //open BAM for reading
        samFile *in = sam_open(bam_.c_str(), "r");
        if(in == NULL) {
            throw runtime_error("Unable to open BAM/SAM file.");
        }
        //Load the index
        hts_idx_t *idx = sam_index_load(in, bam_.c_str());
        if(idx == NULL) {
            throw runtime_error("Unable to open BAM/SAM index."
                                " Make sure alignments are indexed");
        }
        //Get the header
        bam_hdr_t *header = sam_hdr_read(in);
        //Initialize iterator
        hts_itr_t *iter = NULL;
        //Move the iterator to the region we are interested in
        iter  = sam_itr_querys(idx, header, region_.c_str());
        if(header == NULL || iter == NULL) {
            sam_close(in);
            throw runtime_error("Unable to iterate to region within BAM.");
        }
        //Initiate the alignment record
        bam1_t *aln = bam_init1();
        while(sam_itr_next(in, iter, aln) >= 0) {
            parse_alignment_into_junctions(header, aln);
        }
        hts_itr_destroy(iter);
        hts_idx_destroy(idx);
        bam_destroy1(aln);
        bam_hdr_destroy(header);
        sam_close(in);
    }
    return 0;
}

//Create the junctions vector from the map
void JunctionsExtractor::create_junctions_vector() {
    for(map<string, Junction> :: iterator it = junctions_.begin();
        it != junctions_.end(); it++) {
        Junction j1 = it->second;
        junctions_vector_.push_back(j1);
    }
}

//Sort all the junctions by their position
void JunctionsExtractor::sort_junctions() {
    sort(junctions_vector_.begin(), junctions_vector_.end(), compare_junctions);
    junctions_sorted_ = true;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <libtorrent/kademlia/traversal_algorithm.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/session_status.hpp>

#include <boost/bind.hpp>

namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(traversal)
#endif

observer_ptr traversal_algorithm::new_observer(void* ptr
	, udp::endpoint const& ep, node_id const& id)
{
	observer_ptr o(new (ptr) null_observer(boost::intrusive_ptr<traversal_algorithm>(this), ep, id));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	return o;
}

void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
{
	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocate_observer();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] failed to "
			"allocate memory for observer. aborting!";
#endif
		done();
		return;
	}
	observer_ptr o = new_observer(ptr, addr, id);
	if (id.is_all_zeros())
	{
		o->set_id(generate_id());
		o->flags |= observer::flag_no_id;
	}

	o->flags |= flags;

	std::vector<observer_ptr>::iterator i = std::lower_bound(
		m_results.begin()
		, m_results.end()
		, o
		, boost::bind(
			compare_ref
			, boost::bind(&observer::id, _1)
			, boost::bind(&observer::id, _2)
			, m_target
		)
	);

	if (i == m_results.end() || (*i)->id() != id)
	{
		TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
			, boost::bind(&observer::id, _1) == id) == m_results.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] adding result: " << id << " " << addr;
#endif
		i = m_results.insert(i, o);
	}

	if (m_results.size() > 100) m_results.resize(100);
}

void traversal_algorithm::start()
{
	// in case the routing table is empty, use the
	// router nodes in the table
	if (m_results.empty()) add_router_entries();
	init();
	add_requests();
}

void* traversal_algorithm::allocate_observer()
{
	return m_node.m_rpc.allocate_observer();
}

void traversal_algorithm::free_observer(void* ptr)
{
	m_node.m_rpc.free_observer(ptr);
}

void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << "] WARNING: "
			"node returned a list which included a node with id 0";
#endif
	add_entry(id, addr, 0);
}

void traversal_algorithm::finished(observer_ptr o)
{
#ifdef TORRENT_DEBUG
	std::vector<observer_ptr>::iterator i = std::find(
		m_results.begin(), m_results.end(), o);

	TORRENT_ASSERT(i != m_results.end());
#endif

	// if this flag is set, it means we increased the
	// branch factor for it, and we should restore it
	if (o->flags & observer::flag_short_timeout)
		--m_branch_factor;

	o->flags |= observer::flag_alive;

	++m_responses;
	--m_invoke_count;
	TORRENT_ASSERT(m_invoke_count >= 0);
	add_requests();
	if (m_invoke_count == 0) done();
}

// prevent request means that the total number of requests has
// overflown. This query failed because it was the oldest one.
// So, if this is true, don't make another request
void traversal_algorithm::failed(observer_ptr o, int flags)
{
	TORRENT_ASSERT(m_invoke_count >= 0);

	if (m_results.empty()) return;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	if (flags & short_timeout)
	{
		// short timeout means that it has been more than
		// two seconds since we sent the request, and that
		// we'll most likely not get a response. But, in case
		// we do get a late response, keep the handler
		// around for some more, but open up the slot
		// by increasing the branch factor
		if ((o->flags & observer::flag_short_timeout) == 0)
			++m_branch_factor;
		o->flags |= observer::flag_short_timeout;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] first chance timeout: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
	}
	else
	{
		o->flags |= observer::flag_failed;
		// if this flag is set, it means we increased the
		// branch factor for it, and we should restore it
		if (o->flags & observer::flag_short_timeout)
			--m_branch_factor;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] failed: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
		// don't tell the routing table about
		// node ids that we just generated ourself
		if ((o->flags & observer::flag_no_id) == 0)
			m_node.m_table.node_failed(o->id());
		++m_timeouts;
		--m_invoke_count;
		TORRENT_ASSERT(m_invoke_count >= 0);
	}

	if (flags & prevent_request)
	{
		--m_branch_factor;
		if (m_branch_factor <= 0) m_branch_factor = 1;
	}
	add_requests();
	if (m_invoke_count == 0) done();
}

void traversal_algorithm::done()
{
	// delete all our references to the observer objects so
	// they will in turn release the traversal algorithm
	m_results.clear();
}

namespace
{
	bool bitwise_nand(unsigned char lhs, unsigned char rhs)
	{
		return (lhs & rhs) == 0;
	}
}

void traversal_algorithm::add_requests()
{
	int results_target = m_node.m_table.bucket_size();

	// Find the first node that hasn't already been queried.
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end
		&& results_target > 0 && m_invoke_count < m_branch_factor; ++i)
	{
		if ((*i)->flags & observer::flag_alive) --results_target;
		if ((*i)->flags & observer::flag_queried) continue;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "]"
			<< " nodes-left: " << (m_results.end() - i)
			<< " invoke-count: " << m_invoke_count
			<< " branch-factor: " << m_branch_factor;
#endif

		if (invoke(*i))
		{
			TORRENT_ASSERT(m_invoke_count >= 0);
			++m_invoke_count;
			(*i)->flags |= observer::flag_queried;
		}
	}
}

void traversal_algorithm::add_router_entries()
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " using router nodes to initiate traversal algorithm. "
		<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
#endif
	for (routing_table::router_iterator i = m_node.m_table.router_begin()
		, end(m_node.m_table.router_end()); i != end; ++i)
	{
		add_entry(node_id(0), *i, observer::flag_initial);
	}
}

void traversal_algorithm::init()
{
	// update the last activity of this bucket
	m_node.m_table.touch_bucket(m_target);
	m_branch_factor = m_node.branch_factor();
	m_node.add_traversal_algorithm(this);
}

traversal_algorithm::~traversal_algorithm()
{
	m_node.remove_traversal_algorithm(this);
}

void traversal_algorithm::status(dht_lookup& l)
{
	l.timeouts = m_timeouts;
	l.responses = m_responses;
	l.outstanding_requests = m_invoke_count;
	l.branch_factor = m_branch_factor;
	l.type = name();
	l.nodes_left = 0;
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end; ++i)
	{
		if ((*i)->flags & observer::flag_queried) continue;
		++l.nodes_left;
	}
}

} } // namespace libtorrent::dht

<commit_msg>dht assert fix<commit_after>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <libtorrent/kademlia/traversal_algorithm.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/session_status.hpp>

#include <boost/bind.hpp>

namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(traversal)
#endif

observer_ptr traversal_algorithm::new_observer(void* ptr
	, udp::endpoint const& ep, node_id const& id)
{
	observer_ptr o(new (ptr) null_observer(boost::intrusive_ptr<traversal_algorithm>(this), ep, id));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	return o;
}

void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
{
	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocate_observer();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] failed to "
			"allocate memory for observer. aborting!";
#endif
		done();
		return;
	}
	observer_ptr o = new_observer(ptr, addr, id);
	if (id.is_all_zeros())
	{
		o->set_id(generate_id());
		o->flags |= observer::flag_no_id;
	}

	o->flags |= flags;

	std::vector<observer_ptr>::iterator i = std::lower_bound(
		m_results.begin()
		, m_results.end()
		, o
		, boost::bind(
			compare_ref
			, boost::bind(&observer::id, _1)
			, boost::bind(&observer::id, _2)
			, m_target
		)
	);

	if (i == m_results.end() || (*i)->id() != id)
	{
		TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
			, boost::bind(&observer::id, _1) == id) == m_results.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] adding result: " << id << " " << addr;
#endif
		i = m_results.insert(i, o);
	}

	if (m_results.size() > 100) m_results.resize(100);
}

void traversal_algorithm::start()
{
	// in case the routing table is empty, use the
	// router nodes in the table
	if (m_results.empty()) add_router_entries();
	init();
	add_requests();
}

void* traversal_algorithm::allocate_observer()
{
	return m_node.m_rpc.allocate_observer();
}

void traversal_algorithm::free_observer(void* ptr)
{
	m_node.m_rpc.free_observer(ptr);
}

void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << "] WARNING: "
			"node returned a list which included a node with id 0";
#endif
	add_entry(id, addr, 0);
}

void traversal_algorithm::finished(observer_ptr o)
{
#ifdef TORRENT_DEBUG
	std::vector<observer_ptr>::iterator i = std::find(
		m_results.begin(), m_results.end(), o);

	TORRENT_ASSERT(i != m_results.end() || m_results.size() == 100);
#endif

	// if this flag is set, it means we increased the
	// branch factor for it, and we should restore it
	if (o->flags & observer::flag_short_timeout)
		--m_branch_factor;

	o->flags |= observer::flag_alive;

	++m_responses;
	--m_invoke_count;
	TORRENT_ASSERT(m_invoke_count >= 0);
	add_requests();
	if (m_invoke_count == 0) done();
}

// prevent request means that the total number of requests has
// overflown. This query failed because it was the oldest one.
// So, if this is true, don't make another request
void traversal_algorithm::failed(observer_ptr o, int flags)
{
	TORRENT_ASSERT(m_invoke_count >= 0);

	if (m_results.empty()) return;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	if (flags & short_timeout)
	{
		// short timeout means that it has been more than
		// two seconds since we sent the request, and that
		// we'll most likely not get a response. But, in case
		// we do get a late response, keep the handler
		// around for some more, but open up the slot
		// by increasing the branch factor
		if ((o->flags & observer::flag_short_timeout) == 0)
			++m_branch_factor;
		o->flags |= observer::flag_short_timeout;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] first chance timeout: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
	}
	else
	{
		o->flags |= observer::flag_failed;
		// if this flag is set, it means we increased the
		// branch factor for it, and we should restore it
		if (o->flags & observer::flag_short_timeout)
			--m_branch_factor;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] failed: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
		// don't tell the routing table about
		// node ids that we just generated ourself
		if ((o->flags & observer::flag_no_id) == 0)
			m_node.m_table.node_failed(o->id());
		++m_timeouts;
		--m_invoke_count;
		TORRENT_ASSERT(m_invoke_count >= 0);
	}

	if (flags & prevent_request)
	{
		--m_branch_factor;
		if (m_branch_factor <= 0) m_branch_factor = 1;
	}
	add_requests();
	if (m_invoke_count == 0) done();
}

void traversal_algorithm::done()
{
	// delete all our references to the observer objects so
	// they will in turn release the traversal algorithm
	m_results.clear();
}

namespace
{
	bool bitwise_nand(unsigned char lhs, unsigned char rhs)
	{
		return (lhs & rhs) == 0;
	}
}

void traversal_algorithm::add_requests()
{
	int results_target = m_node.m_table.bucket_size();

	// Find the first node that hasn't already been queried.
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end
		&& results_target > 0 && m_invoke_count < m_branch_factor; ++i)
	{
		if ((*i)->flags & observer::flag_alive) --results_target;
		if ((*i)->flags & observer::flag_queried) continue;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "]"
			<< " nodes-left: " << (m_results.end() - i)
			<< " invoke-count: " << m_invoke_count
			<< " branch-factor: " << m_branch_factor;
#endif

		if (invoke(*i))
		{
			TORRENT_ASSERT(m_invoke_count >= 0);
			++m_invoke_count;
			(*i)->flags |= observer::flag_queried;
		}
	}
}

void traversal_algorithm::add_router_entries()
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " using router nodes to initiate traversal algorithm. "
		<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
#endif
	for (routing_table::router_iterator i = m_node.m_table.router_begin()
		, end(m_node.m_table.router_end()); i != end; ++i)
	{
		add_entry(node_id(0), *i, observer::flag_initial);
	}
}

void traversal_algorithm::init()
{
	// update the last activity of this bucket
	m_node.m_table.touch_bucket(m_target);
	m_branch_factor = m_node.branch_factor();
	m_node.add_traversal_algorithm(this);
}

traversal_algorithm::~traversal_algorithm()
{
	m_node.remove_traversal_algorithm(this);
}

void traversal_algorithm::status(dht_lookup& l)
{
	l.timeouts = m_timeouts;
	l.responses = m_responses;
	l.outstanding_requests = m_invoke_count;
	l.branch_factor = m_branch_factor;
	l.type = name();
	l.nodes_left = 0;
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end; ++i)
	{
		if ((*i)->flags & observer::flag_queried) continue;
		++l.nodes_left;
	}
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before>#include <bitcoin/consensus/libethash/internal.h>
#include <bitcoin/consensus/libdevcore/Guards.h>
#include <bitcoin/consensus/libdevcore/Log.h>
#include <bitcoin/consensus/libdevcore/SHA3.h>
#include <bitcoin/bitcoin/chain/header.hpp>
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <array>
#include <thread>
#include <bitcoin/consensus/miner/MinerAux.h>

using namespace dev;
using namespace std;

MinerAux* dev::MinerAux::s_this = nullptr;

MinerAux::~MinerAux()
{
}

MinerAux* MinerAux::get()
{
    static std::once_flag flag;
    std::call_once(flag, []{s_this = new MinerAux();});
    return s_this;
}

LightType MinerAux::get_light(h256& _seedHash)
{
	UpgradableGuard l(get()->x_lights);
	if (get()->m_lights.count(_seedHash))
		return get()->m_lights.at(_seedHash);
	UpgradeGuard l2(l);
	return (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
}

//static std::function<int(unsigned)> s_dagCallback;

static int dagCallbackShim(unsigned _p)
{
	return 0;
}
FullType MinerAux::get_full(h256& _seedHash)
{
	FullType ret;
	auto l = get_light(_seedHash);
	DEV_GUARDED(get()->x_fulls)
	if ((ret = get()->m_fulls[_seedHash].lock()))
	{
		//get()->m_lastUsedFull = ret;
		return ret;
	}
	//s_dagCallback = _f;
	ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
	DEV_GUARDED(get()->x_fulls)
	get()->m_fulls[_seedHash] = ret;
	return ret;
}

ethash_return_value_t MinerAux::search(libbitcoin::chain::header& header, std::function<bool (void)> is_exit)
{
	auto tid = std::this_thread::get_id();
	static std::mt19937_64 s_eng((utcTime() + std::hash<decltype(tid)>()(tid)));
	uint64_t tryNonce = s_eng();
	ethash_return_value ethashReturn;
	FullType dag;
	unsigned hashCount = 1;
	h256 seed = HeaderAux::seedHash(header);
	h256 header_hash = HeaderAux::hashHead(header);
	h256 boundary = HeaderAux::boundary(header);

	dag = get_full(seed);

	for (; ; tryNonce++, hashCount++)
	{
		ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)header_hash.data(), tryNonce);
		h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
		if (value <= boundary )
			break;
		if(is_exit() == true)
		{
			ethashReturn.success = false;
			break;
		}
	}

	return ethashReturn;
}

bool MinerAux::verifySeal(libbitcoin::chain::header& _header)
{
	dev::Result result;
	h256 seedHash = HeaderAux::seedHash(_header);
	h256 headerHash  = HeaderAux::hashHead(_header);
	Nonce nonce = _header.getNonce();
	DEV_GUARDED(get()->x_fulls)
	if (FullType dag = get()->m_fulls[seedHash].lock())
	{
		result = dag->compute(headerHash, nonce);
		return ( result.value <= dev::HeaderAux::boundary(_header) && result.mixHash == _header.getMixhash() );
	}
	result = get()->get_light(seedHash)->compute(headerHash, nonce);
	return ( result.value <= dev::HeaderAux::boundary(_header) && result.mixHash == _header.getMixhash() );
}

<commit_msg>rm consensus/miner/MinerAux.cpp<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/texture_manager.h"
#include "base/bits.h"

namespace gpu {
namespace gles2 {

static GLsizei ComputeMipMapCount(
    GLsizei width, GLsizei height, GLsizei depth) {
  return 1 + base::bits::Log2Floor(std::max(std::max(width, height), depth));
}

static size_t GLTargetToFaceIndex(GLenum target) {
  switch (target) {
    case GL_TEXTURE_2D:
      return 0;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
      return 0;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
      return 1;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
      return 2;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
      return 3;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
      return 4;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
      return 5;
    default:
      NOTREACHED();
      return 0;
  }
}

static size_t FaceIndexToGLTarget(size_t index) {
  switch (index) {
    case 0:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
    case 1:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
    case 2:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
    case 3:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
    case 4:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
    case 5:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
    default:
      NOTREACHED();
      return 0;
  }
}

void TextureManager::TextureInfo::MarkMipmapsGenerated() {
  DCHECK(CanGenerateMipmaps());
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const TextureInfo::LevelInfo& info1 = level_infos_[ii][0];
    GLsizei width = info1.width;
    GLsizei height = info1.height;
    GLsizei depth = info1.depth;
    int num_mips = ComputeMipMapCount(width, height, depth);
    for (int level = 1; level < num_mips; ++level) {
      width = std::max(1, width >> 1);
      height = std::max(1, height >> 1);
      depth = std::max(1, depth >> 1);
      SetLevelInfo(target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
                                              FaceIndexToGLTarget(ii),
                   level,
                   info1.internal_format,
                   width,
                   height,
                   depth,
                   info1.border,
                   info1.format,
                   info1.type);
    }
  }
}

bool TextureManager::TextureInfo::CanGenerateMipmaps() const {
  if (npot()) {
    return false;
  }
  const TextureInfo::LevelInfo& first = level_infos_[0][0];
  // TODO(gman): Check internal_format, format and type.
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const LevelInfo& info = level_infos_[ii][0];
    if (!info.valid ||
        info.width != first.width &&
        info.height != first.height &&
        info.depth != 1 &&
        info.format != first.format &&
        info.internal_format != first.internal_format &&
        info.type != first.type) {
        return false;
    }
  }
  return true;
}

void TextureManager::TextureInfo::SetLevelInfo(
    GLenum target,
    GLint level,
    GLint internal_format,
    GLsizei width,
    GLsizei height,
    GLsizei depth,
    GLint border,
    GLenum format,
    GLenum type) {
  DCHECK_GE(level, 0);
  DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
            level_infos_.size());
  DCHECK_LT(static_cast<size_t>(level),
            level_infos_[GLTargetToFaceIndex(target)].size());
  DCHECK_GE(width, 0);
  DCHECK_GE(height, 0);
  DCHECK_GE(depth, 0);
  TextureInfo::LevelInfo& info =
      level_infos_[GLTargetToFaceIndex(target)][level];
  info.valid = true;
  info.internal_format = internal_format;
  info.width = width;
  info.height = height;
  info.depth = depth;
  info.border = border;
  info.format = format;
  info.type = type;
  max_level_set_ = std::max(max_level_set_, level);
  Update();
}

void TextureManager::TextureInfo::Update() {
  // Update npot status.
  npot_ = false;
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const TextureInfo::LevelInfo& info = level_infos_[ii][0];
    if (((info.width & (info.width - 1)) != 0) ||
        ((info.height & (info.height - 1)) != 0) ||
        ((info.depth & (info.depth - 1)) != 0)) {
      npot_ = true;
      break;
    }
  }

  // Update texture_complete status.
  const TextureInfo::LevelInfo& first_face = level_infos_[0][0];
  texture_complete_ =
      (max_level_set_ == ComputeMipMapCount(first_face.width,
                                            first_face.height,
                                            first_face.depth) - 1) &&
      max_level_set_ >= 0;
  cube_complete_ = (level_infos_.size() == 6) &&
                   (first_face.width == first_face.height);
  for (size_t ii = 0;
       ii < level_infos_.size() && cube_complete_ && texture_complete_;
       ++ii) {
    const TextureInfo::LevelInfo& level0 = level_infos_[ii][0];
    if (!level0.valid ||
        level0.width != first_face.width ||
        level0.height != first_face.height ||
        level0.depth != 1 ||
        level0.internal_format != first_face.internal_format ||
        level0.format != first_face.format ||
        level0.type != first_face.type) {
      cube_complete_ = false;
    }
    // Get level0 dimensions
    GLsizei width = level0.width;
    GLsizei height = level0.height;
    GLsizei depth = level0.depth;
    for (GLint jj = 0; jj <= max_level_set_; ++jj) {
      // compute required size for mip.
      width = std::max(1, width >> 1);
      height = std::max(1, height >> 1);
      depth = std::max(1, depth >> 1);
      const TextureInfo::LevelInfo& info = level_infos_[ii][jj];
      if (!info.valid ||
          info.width != width ||
          info.height != height ||
          info.depth != depth ||
          info.internal_format != level0.internal_format ||
          info.format != level0.format ||
          info.type != level0.type) {
        texture_complete_ = false;
        break;
      }
    }
  }
}

TextureManager::TextureManager(
    GLint max_texture_size, GLint max_cube_map_texture_size)
    : max_texture_size_(max_texture_size),
      max_cube_map_texture_size_(max_cube_map_texture_size),
      max_levels_(ComputeMipMapCount(max_texture_size,
                                     max_texture_size,
                                     max_texture_size)),
      max_cube_map_levels_(ComputeMipMapCount(max_cube_map_texture_size,
                                              max_cube_map_texture_size,
                                              max_cube_map_texture_size)) {
}

void TextureManager::CreateTextureInfo(GLuint texture) {
  TextureInfo* info = new TextureInfo(texture);
  std::pair<TextureInfoMap::iterator, bool> result =
      texture_infos_.insert(
          std::make_pair(texture, linked_ptr<TextureInfo>(info)));
  DCHECK(result.second);
}

TextureManager::TextureInfo* TextureManager::GetTextureInfo(
    GLuint texture) {
  TextureInfoMap::iterator it = texture_infos_.find(texture);
  return it != texture_infos_.end() ? &(*it->second) : NULL;
}

void TextureManager::RemoveTextureInfo(GLuint texture_id) {
  texture_infos_.erase(texture_id);
}

}  // namespace gles2
}  // namespace gpu

<commit_msg>Fix for build breakage<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/texture_manager.h"
#include "base/bits.h"

namespace gpu {
namespace gles2 {

static GLsizei ComputeMipMapCount(
    GLsizei width, GLsizei height, GLsizei depth) {
  return 1 + base::bits::Log2Floor(std::max(std::max(width, height), depth));
}

static size_t GLTargetToFaceIndex(GLenum target) {
  switch (target) {
    case GL_TEXTURE_2D:
      return 0;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
      return 0;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
      return 1;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
      return 2;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
      return 3;
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
      return 4;
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
      return 5;
    default:
      NOTREACHED();
      return 0;
  }
}

static size_t FaceIndexToGLTarget(size_t index) {
  switch (index) {
    case 0:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
    case 1:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
    case 2:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
    case 3:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
    case 4:
      return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
    case 5:
      return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
    default:
      NOTREACHED();
      return 0;
  }
}

void TextureManager::TextureInfo::MarkMipmapsGenerated() {
  DCHECK(CanGenerateMipmaps());
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const TextureInfo::LevelInfo& info1 = level_infos_[ii][0];
    GLsizei width = info1.width;
    GLsizei height = info1.height;
    GLsizei depth = info1.depth;
    int num_mips = ComputeMipMapCount(width, height, depth);
    for (int level = 1; level < num_mips; ++level) {
      width = std::max(1, width >> 1);
      height = std::max(1, height >> 1);
      depth = std::max(1, depth >> 1);
      SetLevelInfo(target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
                                              FaceIndexToGLTarget(ii),
                   level,
                   info1.internal_format,
                   width,
                   height,
                   depth,
                   info1.border,
                   info1.format,
                   info1.type);
    }
  }
}

bool TextureManager::TextureInfo::CanGenerateMipmaps() const {
  if (npot()) {
    return false;
  }
  const TextureInfo::LevelInfo& first = level_infos_[0][0];
  // TODO(gman): Check internal_format, format and type.
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const LevelInfo& info = level_infos_[ii][0];
    if ((!info.valid) ||
        (info.width != first.width) ||
        (info.height != first.height) ||
        (info.depth != 1) ||
        (info.format != first.format) ||
        (info.internal_format != first.internal_format) ||
        (info.type != first.type)) {
        return false;
    }
  }
  return true;
}

void TextureManager::TextureInfo::SetLevelInfo(
    GLenum target,
    GLint level,
    GLint internal_format,
    GLsizei width,
    GLsizei height,
    GLsizei depth,
    GLint border,
    GLenum format,
    GLenum type) {
  DCHECK_GE(level, 0);
  DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
            level_infos_.size());
  DCHECK_LT(static_cast<size_t>(level),
            level_infos_[GLTargetToFaceIndex(target)].size());
  DCHECK_GE(width, 0);
  DCHECK_GE(height, 0);
  DCHECK_GE(depth, 0);
  TextureInfo::LevelInfo& info =
      level_infos_[GLTargetToFaceIndex(target)][level];
  info.valid = true;
  info.internal_format = internal_format;
  info.width = width;
  info.height = height;
  info.depth = depth;
  info.border = border;
  info.format = format;
  info.type = type;
  max_level_set_ = std::max(max_level_set_, level);
  Update();
}

void TextureManager::TextureInfo::Update() {
  // Update npot status.
  npot_ = false;
  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
    const TextureInfo::LevelInfo& info = level_infos_[ii][0];
    if (((info.width & (info.width - 1)) != 0) ||
        ((info.height & (info.height - 1)) != 0) ||
        ((info.depth & (info.depth - 1)) != 0)) {
      npot_ = true;
      break;
    }
  }

  // Update texture_complete status.
  const TextureInfo::LevelInfo& first_face = level_infos_[0][0];
  texture_complete_ =
      (max_level_set_ == ComputeMipMapCount(first_face.width,
                                            first_face.height,
                                            first_face.depth) - 1) &&
      max_level_set_ >= 0;
  cube_complete_ = (level_infos_.size() == 6) &&
                   (first_face.width == first_face.height);
  for (size_t ii = 0;
       ii < level_infos_.size() && cube_complete_ && texture_complete_;
       ++ii) {
    const TextureInfo::LevelInfo& level0 = level_infos_[ii][0];
    if (!level0.valid ||
        level0.width != first_face.width ||
        level0.height != first_face.height ||
        level0.depth != 1 ||
        level0.internal_format != first_face.internal_format ||
        level0.format != first_face.format ||
        level0.type != first_face.type) {
      cube_complete_ = false;
    }
    // Get level0 dimensions
    GLsizei width = level0.width;
    GLsizei height = level0.height;
    GLsizei depth = level0.depth;
    for (GLint jj = 0; jj <= max_level_set_; ++jj) {
      // compute required size for mip.
      width = std::max(1, width >> 1);
      height = std::max(1, height >> 1);
      depth = std::max(1, depth >> 1);
      const TextureInfo::LevelInfo& info = level_infos_[ii][jj];
      if (!info.valid ||
          info.width != width ||
          info.height != height ||
          info.depth != depth ||
          info.internal_format != level0.internal_format ||
          info.format != level0.format ||
          info.type != level0.type) {
        texture_complete_ = false;
        break;
      }
    }
  }
}

TextureManager::TextureManager(
    GLint max_texture_size, GLint max_cube_map_texture_size)
    : max_texture_size_(max_texture_size),
      max_cube_map_texture_size_(max_cube_map_texture_size),
      max_levels_(ComputeMipMapCount(max_texture_size,
                                     max_texture_size,
                                     max_texture_size)),
      max_cube_map_levels_(ComputeMipMapCount(max_cube_map_texture_size,
                                              max_cube_map_texture_size,
                                              max_cube_map_texture_size)) {
}

void TextureManager::CreateTextureInfo(GLuint texture) {
  TextureInfo* info = new TextureInfo(texture);
  std::pair<TextureInfoMap::iterator, bool> result =
      texture_infos_.insert(
          std::make_pair(texture, linked_ptr<TextureInfo>(info)));
  DCHECK(result.second);
}

TextureManager::TextureInfo* TextureManager::GetTextureInfo(
    GLuint texture) {
  TextureInfoMap::iterator it = texture_infos_.find(texture);
  return it != texture_infos_.end() ? &(*it->second) : NULL;
}

void TextureManager::RemoveTextureInfo(GLuint texture_id) {
  texture_infos_.erase(texture_id);
}

}  // namespace gles2
}  // namespace gpu

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/controls/tabbed_pane/native_tabbed_pane_win.h"

#include <vssym32.h>

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/l10n_util_win.h"
#include "app/resource_bundle.h"
#include "base/gfx/native_theme.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"

namespace views {

// A background object that paints the tab panel background which may be
// rendered by the system visual styles system.
class TabBackground : public Background {
 public:
  explicit TabBackground() {
    // TMT_FILLCOLORHINT returns a color value that supposedly
    // approximates the texture drawn by PaintTabPanelBackground.
    SkColor tab_page_color =
        gfx::NativeTheme::instance()->GetThemeColorWithDefault(
            gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT,
            COLOR_3DFACE);
    SetNativeControlColor(tab_page_color);
  }
  virtual ~TabBackground() {}

  virtual void Paint(gfx::Canvas* canvas, View* view) const {
    HDC dc = canvas->beginPlatformPaint();
    RECT r = {0, 0, view->width(), view->height()};
    gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r);
    canvas->endPlatformPaint();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TabBackground);
};

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, public:

NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane)
    : NativeControlWin(),
      tabbed_pane_(tabbed_pane),
      content_window_(NULL),
      selected_index_(-1) {
  // Associates the actual HWND with the tabbed-pane so the tabbed-pane is
  // the one considered as having the focus (not the wrapper) when the HWND is
  // focused directly (with a click for example).
  set_focus_view(tabbed_pane);
}

NativeTabbedPaneWin::~NativeTabbedPaneWin() {
  // We own the tab views, let's delete them.
  STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end());
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeTabbedPaneWrapper implementation:

void NativeTabbedPaneWin::AddTab(const std::wstring& title, View* contents) {
  AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true);
}

void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title,
                                        View* contents,
                                        bool select_if_first_tab) {
  DCHECK(index <= static_cast<int>(tab_views_.size()));
  contents->SetParentOwned(false);
  tab_views_.insert(tab_views_.begin() + index, contents);
  tab_titles_.insert(tab_titles_.begin() + index, title);

  if (!contents->background())
    contents->set_background(new TabBackground);

  if (tab_views_.size() == 1 && select_if_first_tab) {
    // If this is the only tab displayed, make sure the contents is set.
    selected_index_ = 0;
    if (content_window_)
      content_window_->GetRootView()->AddChildView(contents);
  }

  // Add native tab only if the native control is alreay created.
  if (content_window_) {
    AddNativeTab(index, title, contents);

    // The newly added tab may have made the contents window smaller.
    ResizeContents();
  }
}

void NativeTabbedPaneWin::AddNativeTab(int index,
                                       const std::wstring &title,
                                       views::View* contents) {
  TCITEM tcitem;
  tcitem.mask = TCIF_TEXT;

  // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is
  // rendered properly on the tabs.
  if (UILayoutIsRightToLeft()) {
    tcitem.mask |= TCIF_RTLREADING;
  }

  tcitem.pszText = const_cast<wchar_t*>(title.c_str());
  int result = TabCtrl_InsertItem(native_view(), index, &tcitem);
  DCHECK(result != -1);
}

View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) {
  int tab_count = static_cast<int>(tab_views_.size());
  DCHECK(index >= 0 && index < tab_count);

  if (index < (tab_count - 1)) {
    // Select the next tab.
    SelectTabAt(index + 1);
  } else {
    // We are the last tab, select the previous one.
    if (index > 0) {
      SelectTabAt(index - 1);
    } else if (content_window_) {
      // That was the last tab. Remove the contents.
      content_window_->GetRootView()->RemoveAllChildViews(false);
    }
  }
  TabCtrl_DeleteItem(native_view(), index);

  // The removed tab may have made the contents window bigger.
  ResizeContents();

  std::vector<View*>::iterator iter = tab_views_.begin() + index;
  View* removed_tab = *iter;
  tab_views_.erase(iter);
  tab_titles_.erase(tab_titles_.begin() + index);

  return removed_tab;
}

void NativeTabbedPaneWin::SelectTabAt(int index) {
  DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size())));
  if (native_view())
    TabCtrl_SetCurSel(native_view(), index);
  DoSelectTabAt(index, true);
}

int NativeTabbedPaneWin::GetTabCount() {
  return TabCtrl_GetItemCount(native_view());
}

int NativeTabbedPaneWin::GetSelectedTabIndex() {
  return TabCtrl_GetCurSel(native_view());
}

View* NativeTabbedPaneWin::GetSelectedTab() {
  if (selected_index_ < 0)
    return NULL;
  return tab_views_[selected_index_];
}

View* NativeTabbedPaneWin::GetView() {
  return this;
}

void NativeTabbedPaneWin::SetFocus() {
  // Focus the associated HWND.
  Focus();
}

gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const {
  return native_view();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeControlWin override:

void NativeTabbedPaneWin::CreateNativeControl() {
  // Create the tab control.
  //
  // Note that we don't follow the common convention for NativeControl
  // subclasses and we don't pass the value returned from
  // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is
  // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when
  // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If
  // we do that, then the HWND we create for |content_window_| below will
  // inherit the WS_EX_LAYOUTRTL property and this will result in the contents
  // being flipped, which is not what we want (because we handle mirroring in
  // views without the use of Windows' support for mirroring). Therefore,
  // we initially create our HWND without the aforementioned property and we
  // explicitly set this property our child is created. This way, on RTL
  // locales, our tabs will be nicely rendered from right to left (by virtue of
  // Windows doing the right thing with the TabbedPane HWND) and each tab
  // contents will use an RTL layout correctly (by virtue of the mirroring
  // infrastructure in views doing the right thing with each View we put
  // in the tab).
  HWND tab_control = ::CreateWindowEx(0,
                                      WC_TABCONTROL,
                                      L"",
                                      WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
                                      0, 0, width(), height(),
                                      GetWidget()->GetNativeView(), NULL, NULL,
                                      NULL);

  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(tab_control, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);

  // Create the view container which is a child of the TabControl.
  content_window_ = new WidgetWin();
  content_window_->Init(tab_control, gfx::Rect());

  // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above
  // for a thorough explanation regarding why we waited until |content_window_|
  // if created before we set this property for the tabbed pane's HWND).
  if (UILayoutIsRightToLeft())
    l10n_util::HWNDSetRTLLayout(tab_control);

  RootView* root_view = content_window_->GetRootView();
  root_view->SetLayoutManager(new FillLayout());
  DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
  SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
                                GetBValue(sys_color));
  root_view->set_background(Background::CreateSolidBackground(color));

  content_window_->SetFocusTraversableParentView(this);

  NativeControlCreated(tab_control);

  // Add tabs that are already added if any.
  if (tab_views_.size() > 0) {
    InitializeTabs();
    if (selected_index_ >= 0)
      DoSelectTabAt(selected_index_, false);
  }

  ResizeContents();
}

bool NativeTabbedPaneWin::ProcessMessage(UINT message,
                                         WPARAM w_param,
                                         LPARAM l_param,
                                         LRESULT* result) {
  if (message == WM_NOTIFY &&
      reinterpret_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) {
    int selected_tab = TabCtrl_GetCurSel(native_view());
    DCHECK(selected_tab != -1);
    DoSelectTabAt(selected_tab, true);
    return TRUE;
  }
  return NativeControlWin::ProcessMessage(message, w_param, l_param, result);
}

////////////////////////////////////////////////////////////////////////////////
// View override:

void NativeTabbedPaneWin::Layout() {
  NativeControlWin::Layout();
  ResizeContents();
}

FocusTraversable* NativeTabbedPaneWin::GetFocusTraversable() {
  return content_window_;
}

void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add,
                                               View *parent,
                                               View *child) {
  NativeControlWin::ViewHierarchyChanged(is_add, parent, child);

  if (is_add && (child == this) && content_window_) {
    // We have been added to a view hierarchy, update the FocusTraversable
    // parent.
    content_window_->SetFocusTraversableParent(GetRootView());
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, private:

void NativeTabbedPaneWin::InitializeTabs() {
  for (size_t i = 0; i < tab_views_.size(); ++i) {
    AddNativeTab(i, tab_titles_[i], tab_views_[i]);
  }
}

void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
  selected_index_ = index;
  if (content_window_) {
    RootView* content_root = content_window_->GetRootView();

    // Clear the focus if the focused view was on the tab.
    FocusManager* focus_manager = GetFocusManager();
    DCHECK(focus_manager);
    View* focused_view = focus_manager->GetFocusedView();
    if (focused_view && content_root->IsParentOf(focused_view))
      focus_manager->ClearFocus();

    content_root->RemoveAllChildViews(false);
    content_root->AddChildView(tab_views_[index]);
    content_root->Layout();
  }
  if (invoke_listener && tabbed_pane_->listener())
    tabbed_pane_->listener()->TabSelectedAt(index);
}

void NativeTabbedPaneWin::ResizeContents() {
  CRect content_bounds;
  if (!GetClientRect(native_view(), &content_bounds))
    return;
  TabCtrl_AdjustRect(native_view(), FALSE, &content_bounds);
  content_window_->MoveWindow(content_bounds.left, content_bounds.top,
                              content_bounds.Width(), content_bounds.Height(),
                              TRUE);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWrapper, public:

// static
NativeTabbedPaneWrapper* NativeTabbedPaneWrapper::CreateNativeWrapper(
    TabbedPane* tabbed_pane) {
  return new NativeTabbedPaneWin(tabbed_pane);
}

}  // namespace views
<commit_msg>Fix possible null pointer dereference.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/controls/tabbed_pane/native_tabbed_pane_win.h"

#include <vssym32.h>

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/l10n_util_win.h"
#include "app/resource_bundle.h"
#include "base/gfx/native_theme.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"

namespace views {

// A background object that paints the tab panel background which may be
// rendered by the system visual styles system.
class TabBackground : public Background {
 public:
  explicit TabBackground() {
    // TMT_FILLCOLORHINT returns a color value that supposedly
    // approximates the texture drawn by PaintTabPanelBackground.
    SkColor tab_page_color =
        gfx::NativeTheme::instance()->GetThemeColorWithDefault(
            gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT,
            COLOR_3DFACE);
    SetNativeControlColor(tab_page_color);
  }
  virtual ~TabBackground() {}

  virtual void Paint(gfx::Canvas* canvas, View* view) const {
    HDC dc = canvas->beginPlatformPaint();
    RECT r = {0, 0, view->width(), view->height()};
    gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r);
    canvas->endPlatformPaint();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TabBackground);
};

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, public:

NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane)
    : NativeControlWin(),
      tabbed_pane_(tabbed_pane),
      content_window_(NULL),
      selected_index_(-1) {
  // Associates the actual HWND with the tabbed-pane so the tabbed-pane is
  // the one considered as having the focus (not the wrapper) when the HWND is
  // focused directly (with a click for example).
  set_focus_view(tabbed_pane);
}

NativeTabbedPaneWin::~NativeTabbedPaneWin() {
  // We own the tab views, let's delete them.
  STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end());
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeTabbedPaneWrapper implementation:

void NativeTabbedPaneWin::AddTab(const std::wstring& title, View* contents) {
  AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true);
}

void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title,
                                        View* contents,
                                        bool select_if_first_tab) {
  DCHECK(index <= static_cast<int>(tab_views_.size()));
  contents->SetParentOwned(false);
  tab_views_.insert(tab_views_.begin() + index, contents);
  tab_titles_.insert(tab_titles_.begin() + index, title);

  if (!contents->background())
    contents->set_background(new TabBackground);

  if (tab_views_.size() == 1 && select_if_first_tab) {
    // If this is the only tab displayed, make sure the contents is set.
    selected_index_ = 0;
    if (content_window_)
      content_window_->GetRootView()->AddChildView(contents);
  }

  // Add native tab only if the native control is alreay created.
  if (content_window_) {
    AddNativeTab(index, title, contents);

    // The newly added tab may have made the contents window smaller.
    ResizeContents();
  }
}

void NativeTabbedPaneWin::AddNativeTab(int index,
                                       const std::wstring &title,
                                       views::View* contents) {
  TCITEM tcitem;
  tcitem.mask = TCIF_TEXT;

  // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is
  // rendered properly on the tabs.
  if (UILayoutIsRightToLeft()) {
    tcitem.mask |= TCIF_RTLREADING;
  }

  tcitem.pszText = const_cast<wchar_t*>(title.c_str());
  int result = TabCtrl_InsertItem(native_view(), index, &tcitem);
  DCHECK(result != -1);
}

View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) {
  int tab_count = static_cast<int>(tab_views_.size());
  DCHECK(index >= 0 && index < tab_count);

  if (index < (tab_count - 1)) {
    // Select the next tab.
    SelectTabAt(index + 1);
  } else {
    // We are the last tab, select the previous one.
    if (index > 0) {
      SelectTabAt(index - 1);
    } else if (content_window_) {
      // That was the last tab. Remove the contents.
      content_window_->GetRootView()->RemoveAllChildViews(false);
    }
  }
  TabCtrl_DeleteItem(native_view(), index);

  // The removed tab may have made the contents window bigger.
  if (content_window_)
    ResizeContents();

  std::vector<View*>::iterator iter = tab_views_.begin() + index;
  View* removed_tab = *iter;
  tab_views_.erase(iter);
  tab_titles_.erase(tab_titles_.begin() + index);

  return removed_tab;
}

void NativeTabbedPaneWin::SelectTabAt(int index) {
  DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size())));
  if (native_view())
    TabCtrl_SetCurSel(native_view(), index);
  DoSelectTabAt(index, true);
}

int NativeTabbedPaneWin::GetTabCount() {
  return TabCtrl_GetItemCount(native_view());
}

int NativeTabbedPaneWin::GetSelectedTabIndex() {
  return TabCtrl_GetCurSel(native_view());
}

View* NativeTabbedPaneWin::GetSelectedTab() {
  if (selected_index_ < 0)
    return NULL;
  return tab_views_[selected_index_];
}

View* NativeTabbedPaneWin::GetView() {
  return this;
}

void NativeTabbedPaneWin::SetFocus() {
  // Focus the associated HWND.
  Focus();
}

gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const {
  return native_view();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeControlWin override:

void NativeTabbedPaneWin::CreateNativeControl() {
  // Create the tab control.
  //
  // Note that we don't follow the common convention for NativeControl
  // subclasses and we don't pass the value returned from
  // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is
  // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when
  // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If
  // we do that, then the HWND we create for |content_window_| below will
  // inherit the WS_EX_LAYOUTRTL property and this will result in the contents
  // being flipped, which is not what we want (because we handle mirroring in
  // views without the use of Windows' support for mirroring). Therefore,
  // we initially create our HWND without the aforementioned property and we
  // explicitly set this property our child is created. This way, on RTL
  // locales, our tabs will be nicely rendered from right to left (by virtue of
  // Windows doing the right thing with the TabbedPane HWND) and each tab
  // contents will use an RTL layout correctly (by virtue of the mirroring
  // infrastructure in views doing the right thing with each View we put
  // in the tab).
  HWND tab_control = ::CreateWindowEx(0,
                                      WC_TABCONTROL,
                                      L"",
                                      WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
                                      0, 0, width(), height(),
                                      GetWidget()->GetNativeView(), NULL, NULL,
                                      NULL);

  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(tab_control, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);

  // Create the view container which is a child of the TabControl.
  content_window_ = new WidgetWin();
  content_window_->Init(tab_control, gfx::Rect());

  // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above
  // for a thorough explanation regarding why we waited until |content_window_|
  // if created before we set this property for the tabbed pane's HWND).
  if (UILayoutIsRightToLeft())
    l10n_util::HWNDSetRTLLayout(tab_control);

  RootView* root_view = content_window_->GetRootView();
  root_view->SetLayoutManager(new FillLayout());
  DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
  SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
                                GetBValue(sys_color));
  root_view->set_background(Background::CreateSolidBackground(color));

  content_window_->SetFocusTraversableParentView(this);

  NativeControlCreated(tab_control);

  // Add tabs that are already added if any.
  if (tab_views_.size() > 0) {
    InitializeTabs();
    if (selected_index_ >= 0)
      DoSelectTabAt(selected_index_, false);
  }

  ResizeContents();
}

bool NativeTabbedPaneWin::ProcessMessage(UINT message,
                                         WPARAM w_param,
                                         LPARAM l_param,
                                         LRESULT* result) {
  if (message == WM_NOTIFY &&
      reinterpret_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) {
    int selected_tab = TabCtrl_GetCurSel(native_view());
    DCHECK(selected_tab != -1);
    DoSelectTabAt(selected_tab, true);
    return TRUE;
  }
  return NativeControlWin::ProcessMessage(message, w_param, l_param, result);
}

////////////////////////////////////////////////////////////////////////////////
// View override:

void NativeTabbedPaneWin::Layout() {
  NativeControlWin::Layout();
  ResizeContents();
}

FocusTraversable* NativeTabbedPaneWin::GetFocusTraversable() {
  return content_window_;
}

void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add,
                                               View *parent,
                                               View *child) {
  NativeControlWin::ViewHierarchyChanged(is_add, parent, child);

  if (is_add && (child == this) && content_window_) {
    // We have been added to a view hierarchy, update the FocusTraversable
    // parent.
    content_window_->SetFocusTraversableParent(GetRootView());
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, private:

void NativeTabbedPaneWin::InitializeTabs() {
  for (size_t i = 0; i < tab_views_.size(); ++i) {
    AddNativeTab(i, tab_titles_[i], tab_views_[i]);
  }
}

void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
  selected_index_ = index;
  if (content_window_) {
    RootView* content_root = content_window_->GetRootView();

    // Clear the focus if the focused view was on the tab.
    FocusManager* focus_manager = GetFocusManager();
    DCHECK(focus_manager);
    View* focused_view = focus_manager->GetFocusedView();
    if (focused_view && content_root->IsParentOf(focused_view))
      focus_manager->ClearFocus();

    content_root->RemoveAllChildViews(false);
    content_root->AddChildView(tab_views_[index]);
    content_root->Layout();
  }
  if (invoke_listener && tabbed_pane_->listener())
    tabbed_pane_->listener()->TabSelectedAt(index);
}

void NativeTabbedPaneWin::ResizeContents() {
  CRect content_bounds;
  if (!GetClientRect(native_view(), &content_bounds))
    return;
  TabCtrl_AdjustRect(native_view(), FALSE, &content_bounds);
  content_window_->MoveWindow(content_bounds.left, content_bounds.top,
                              content_bounds.Width(), content_bounds.Height(),
                              TRUE);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWrapper, public:

// static
NativeTabbedPaneWrapper* NativeTabbedPaneWrapper::CreateNativeWrapper(
    TabbedPane* tabbed_pane) {
  return new NativeTabbedPaneWin(tabbed_pane);
}

}  // namespace views
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Arcanet.                                       *
 *                                                                       *
 *   Arcanet is free software: you can redistribute it and/or modify     *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Arcanet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Arcanet.                                         *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "core.h"

namespace arc
{

Core::Core(void)
{

}

Core::~Core(void)
{

}

void Core::add(Socket *sock)
{
	assert(sock != NULL);
	Handler *handler = new Handler(this,sock);
	handler->start();
	add(sock->getRemoteAddress(), handler);
}

void Core::add(const Address &addr, Core::Handler *handler)
{
	assert(handler != NULL);
	mHandlers.insert(addr, handler);
}

void Core::remove(const Address &addr)
{
	if(mHandlers.contains(addr))
	{
		delete mHandlers.get(addr);
		mHandlers.erase(addr);
	}
}

Core::Handler::Handler(Core *core, Stream *stream) :
	mCore(core),
	mStream(stream)
{

}

Core::Handler::~Handler(void)
{
	delete mStream;
	delete mHandler;
}

void Core::Handler::run(void)
{
	String line;
	if(!mStream->readLine(line))
		return;

	String proto;
	String version;
	line.readString(proto);
	line.readString(version);

	while(mStream->readLine(line))
	{
		unsigned channel, size;
		line.read(channel);
		line.read(size);

		Pipe *pipe;
		if(mChannel.get(channel,pipe))
		{
			// TODO: Limited read
			//mStream->read(*pipe);
		}
	}

	//mCore->remove(this);
}

}
<commit_msg>Need correct multiplexing algorithm<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Arcanet.                                       *
 *                                                                       *
 *   Arcanet is free software: you can redistribute it and/or modify     *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Arcanet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Arcanet.                                         *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "core.h"

namespace arc
{

Core::Core(void)
{

}

Core::~Core(void)
{

}

void Core::add(Socket *sock)
{
	assert(sock != NULL);
	Handler *handler = new Handler(this,sock);
	handler->start();
	add(sock->getRemoteAddress(), handler);
}

void Core::add(const Address &addr, Core::Handler *handler)
{
	assert(handler != NULL);
	mHandlers.insert(addr, handler);
}

void Core::remove(const Address &addr)
{
	if(mHandlers.contains(addr))
	{
		delete mHandlers.get(addr);
		mHandlers.erase(addr);
	}
}

Core::Handler::Handler(Core *core, Stream *stream) :
	mCore(core),
	mStream(stream)
{

}

Core::Handler::~Handler(void)
{
	delete mStream;
	delete mHandler;
}

void Core::Handler::run(void)
{
	String line;
	if(!mStream->readLine(line))
		return;

	String proto;
	String version;
	line.readString(proto);
	line.readString(version);

	while(mStream->readLine(line))
	{
		unsigned channel, size;
		line.read(channel);
		line.read(size);

		if(channel == 0)
		{

		}
		else {
			Pipe *pipe;
			if(mChannels.get(channel,pipe))
			{
				// TODO: Limited read
				//mStream->read(*pipe);
			}
		}
	}

	//mCore->remove(this);
}

}
<|endoftext|>


<commit_before>#include "declarativeviewtexture.h"

#include <QtGui/QPainter>
#include <QtGui/QImage>
#include <QtGui/QPaintEvent>
#include <QtCore/QDebug>

static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
{
    const int width = img.width();
    const int height = img.height();

    if (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)
    {
        for (int i = 0; i < height; ++i) {
            uint *p = (uint *) img.scanLine(i);
            for (int x = 0; x < width; ++x)
                p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
        }
    } else {
        for (int i = 0; i < height; ++i) {
            uint *p = (uint *) img.scanLine(i);
            for (int x = 0; x < width; ++x)
                p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
        }
    }
}

DeclarativeViewTexture::DeclarativeViewTexture(QWidget *parent) :
    QDeclarativeView(parent),
    m_bufferPainter(0)
{
    setAttribute(Qt::WA_DontShowOnScreen);
    setOptimizationFlag(QGraphicsView::IndirectPainting);
    setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);

    glGenTextures(1, &m_textureId);
}

DeclarativeViewTexture::~DeclarativeViewTexture()
{

}

void DeclarativeViewTexture::paintEvent(QPaintEvent *event)
{
    // Render the view in an offscreen image
    delete m_bufferPainter;
    m_bufferPainter = new QPainter;
    QRegion exposedRegion = event->region();
    QImage im(exposedRegion.boundingRect().size(), QImage::Format_ARGB32_Premultiplied);
    im.fill(Qt::transparent);
    m_bufferPainter->begin(&im);
    m_bufferPainter->translate(-exposedRegion.boundingRect().topLeft());
    m_bufferPainter->setClipRegion(exposedRegion);
    QDeclarativeView::paintEvent(event);
    m_bufferPainter->end();

    // Upload the image in graphics memory
    glBindTexture(GL_TEXTURE_2D, m_textureId);
    qgl_byteSwapImage(im, GL_UNSIGNED_BYTE);
    foreach (const QRect &rect, exposedRegion.rects()) {
        if (rect.size() == size()) {
            glTexImage2D(GL_TEXTURE_2D, 0, 4, rect.width(), rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
            break;
        } else {
            QRect adjustedRect = rect.translated(-exposedRegion.boundingRect().topLeft());
            QImage subIm = im.copy(adjustedRect);
            glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left(), rect.top(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, subIm.bits());
        }
    }
    glBindTexture(GL_TEXTURE_2D, 0);
}

void DeclarativeViewTexture::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[])
{
    QDeclarativeView::drawItems(m_bufferPainter, numItems, items, options);
}

void DeclarativeViewTexture::drawBackground(QPainter *painter, const QRectF &rect)
{
    QDeclarativeView::drawBackground(m_bufferPainter, rect);
}

void DeclarativeViewTexture::drawForeground(QPainter *painter, const QRectF &rect)
{
    QDeclarativeView::drawForeground(m_bufferPainter, rect);
}
<commit_msg>Activates anti-aliasing for QML rendering.<commit_after>#include "declarativeviewtexture.h"

#include <QtGui/QPainter>
#include <QtGui/QImage>
#include <QtGui/QPaintEvent>
#include <QtCore/QDebug>

static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
{
    const int width = img.width();
    const int height = img.height();

    if (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)
    {
        for (int i = 0; i < height; ++i) {
            uint *p = (uint *) img.scanLine(i);
            for (int x = 0; x < width; ++x)
                p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
        }
    } else {
        for (int i = 0; i < height; ++i) {
            uint *p = (uint *) img.scanLine(i);
            for (int x = 0; x < width; ++x)
                p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
        }
    }
}

DeclarativeViewTexture::DeclarativeViewTexture(QWidget *parent) :
    QDeclarativeView(parent),
    m_bufferPainter(0)
{
    setAttribute(Qt::WA_DontShowOnScreen);
    setOptimizationFlag(QGraphicsView::IndirectPainting);

    glGenTextures(1, &m_textureId);
}

DeclarativeViewTexture::~DeclarativeViewTexture()
{

}

void DeclarativeViewTexture::paintEvent(QPaintEvent *event)
{
    // Render the view in an offscreen image
    delete m_bufferPainter;
    m_bufferPainter = new QPainter;
    QRegion exposedRegion = event->region();
    QImage im(exposedRegion.boundingRect().size(), QImage::Format_ARGB32_Premultiplied);
    im.fill(Qt::transparent);
    m_bufferPainter->begin(&im);
    m_bufferPainter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
    m_bufferPainter->translate(-exposedRegion.boundingRect().topLeft());
    m_bufferPainter->setClipRegion(exposedRegion);
    QDeclarativeView::paintEvent(event);
    m_bufferPainter->end();

    // Upload the image in graphics memory
    glBindTexture(GL_TEXTURE_2D, m_textureId);
    qgl_byteSwapImage(im, GL_UNSIGNED_BYTE);
    foreach (const QRect &rect, exposedRegion.rects()) {
        if (rect.size() == size()) {
            glTexImage2D(GL_TEXTURE_2D, 0, 4, rect.width(), rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
            glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
            break;
        } else {
            QRect adjustedRect = rect.translated(-exposedRegion.boundingRect().topLeft());
            QImage subIm = im.copy(adjustedRect);
            glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left(), rect.top(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, subIm.bits());
        }
    }
    glBindTexture(GL_TEXTURE_2D, 0);
}

void DeclarativeViewTexture::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[])
{
    QDeclarativeView::drawItems(m_bufferPainter, numItems, items, options);
}

void DeclarativeViewTexture::drawBackground(QPainter *painter, const QRectF &rect)
{
    QDeclarativeView::drawBackground(m_bufferPainter, rect);
}

void DeclarativeViewTexture::drawForeground(QPainter *painter, const QRectF &rect)
{
    QDeclarativeView::drawForeground(m_bufferPainter, rect);
}
<|endoftext|>