<commit_before>#include "udpping.h"

UdpPing::UdpPing(QObject *parent)
    : Measurement(parent),
      currentStatus(Unknown)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);
    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();
    return true;
}

bool UdpPing::start()
{
    return false;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    return 0;
}

bool UdpPing::sendData(PingProbe *probe)
{
    return false;
}

void UdpPing::receiveData(PingProbe *probe)
{
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

int UdpPing::getAddress(const QString &address, sockaddr_any *addr) const
{
    return 0;
}

// vim: set sts=4 sw=4 et:
<commit_msg>fix method signature of getAddress<commit_after>#include "udpping.h"

UdpPing::UdpPing(QObject *parent)
    : Measurement(parent),
      currentStatus(Unknown)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager* networkManager, const MeasurementDefinitionPtr& measurementDefinition)
{
    Q_UNUSED(networkManager);
    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();
    return true;
}

bool UdpPing::start()
{
    return false;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    return 0;
}

bool UdpPing::sendData(PingProbe *probe)
{
    return false;
}

void UdpPing::receiveData(PingProbe *probe)
{
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

bool UdpPing::getAddress(const QString &address, sockaddr_any *addr) const
{
    return true;
}

// vim: set sts=4 sw=4 et:
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2013 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/convenience.hpp>
#include <votca/tools/getline.h>

#ifndef HAVE_NO_CONFIG
#include <votca_config.h>
#endif

#include "dlpolytopologyreader.h"
#ifdef DLPOLY_FORTRAN
#include "dlpoly/dlp_io_layer.h"
#include "fortan_mangling.h"
#endif

namespace votca { namespace csg {

bool DLPOLYTopologyReader::ReadTopology(string file, Topology &top)
{
    std::ifstream fl;
    boost::filesystem::path filepath(file.c_str());
    string filename;
#ifdef DLPOLY_FORTRAN
    if (file != ".dlpoly")
      throw std::runtime_error("Reading from different filename/directories not implemented yet. (use --top '.dlpoly')");

    struct FieldSpecsT  FieldBase;
    struct FrameSpecsT  FrameBase;
    struct MolecSpecsT *MolecBase;
    struct FieldSiteT  *FieldSite;
    struct FrameSiteT  *FrameSite;

    int idnode,matms,natms,nmols,nmolt;
    int istateF;

    int inode=matms=natms=nmols=nmolt=0;

    // TODO: istateF must be an enum!
    istateF=1;

    // TODO: we need to fix the file naming!
    FortranCInterface_GLOBAL(field_scan,FIELD_SCAN)(&istateF,&matms,&natms,&nmolt);

    MolecBase = new MolecSpecsT[nmolt];
    FieldSite = new FieldSiteT[natms];

    FieldBase.nmols = nmolt;
    FieldBase.natms = natms;

    FortranCInterface_GLOBAL(field_read,FIELD_READ)(&istateF,&FieldBase,MolecBase,FieldSite);

    // AB: if on return istateF < 0  => in the next F-call the relevant F-arrays will be deallocated (at the end)
    // AB: NOT TO RE-/DE-ALLOCATE F-arrays in the next F-call, reset istateF = 0
    istateF = 0;

    // TODO: fix residue naming / assignment
    Residue *res = top.CreateResidue("no");

    // read the atoms
    int mol_offset=0;
    for(int im=0; im<nmolt; im++){
        for(int imr=0; imr<MolecBase[im].nrept; ++imr) {
            Molecule *mi = top.CreateMolecule(MolecBase[im].name);
            for(int ims=0; ims<MolecBase[im].nsites; ims++) {
	        int is=mol_offset+ims;
                BeadType *type = top.GetOrCreateBeadType(FieldSite[is].type); // what is
	        string beadname = boost::lexical_cast<string>(FieldSite[is].name) + "#" + boost::lexical_cast<string>(ims+1);
                Bead *bead = top.CreateBead(1, beadname, type, res->getId(), FieldSite[is].m, FieldSite[is].q);

                stringstream nm;
                nm << bead->getResnr() + 1 << ":" <<  top.getResidue(bead->getResnr())->getName() << ":" << bead->getName();
                mi->AddBead(bead, nm.str());
            }
        }
	mol_offset+=MolecBase[im].nsites;
    }

    delete [] MolecBase;
    delete [] FieldSite;
#else
    // TODO: fix residue naming / assignment
    Residue *res = top.CreateResidue("no");

    if ( boost::filesystem::basename(filepath).size() == 0 ) {
      if (filepath.parent_path().string().size() == 0) {
        filename="FIELD";
      } else {
	filename=filepath.parent_path().string() + "/FIELD";
      }
    } else {
      filename=file;
    }
    fl.open(filename.c_str());
    if (!fl.is_open()){
      throw std::runtime_error("could open dlpoly file " + filename);
    } else {
      string line;
      getline(fl, line); //title
      getline(fl, line); //unit line
      fl >> line;
      if (line != "MOLECULES")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'MOLECULES' got" + line);
      int nmol_types;
      fl >> nmol_types;
      getline(fl, line); //rest of MOLECULES line
      int id=0;
      for (int nmol_type=0;nmol_type<nmol_types; nmol_type++){
	string mol_name;
        getline(fl, mol_name); //molecule name might incl. spaces
	boost::erase_all(mol_name, " ");
        Molecule *mi = top.CreateMolecule(mol_name);
        fl >> line;
        if (line != "NUMMOLS")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'NUMMOLS' got" + line);
	int nreplica;
	fl >> nreplica;
	fl >> line;
        if (line != "ATOMS")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'ATOMS' got" + line);
	int natoms;
	fl >> natoms;
	//read molecule
	int id_map[natoms];
	for (int i=0;i<natoms;){//i is altered in reapeater loop
	  string beadtype;
	  fl >> beadtype;
	  BeadType *type = top.GetOrCreateBeadType(beadtype);
	  double mass;
	  fl >> mass;
	  double charge;
	  fl >> charge;
          getline(fl,line); //rest of the atom line
          Tokenizer tok(line, " ");
          vector<int> fields;
          tok.ConvertToVector<int>(fields);
	  int repeater=1;
	  if (fields.size() > 1)
	    repeater=fields[0];
	  for(int j=0;j<repeater;j++){
	    string beadname = beadtype + "#" + boost::lexical_cast<string>(j+1);
	    Bead *bead = top.CreateBead(1, beadname , type, res->getId(), mass, charge);
            stringstream nm;
            nm << bead->getResnr() + 1 << ":" <<  top.getResidue(bead->getResnr())->getName() << ":" << bead->getName();
            mi->AddBead(bead, nm.str());
	    id_map[i]=bead->getId();
	    i++;
	  }
	}
	while (line != "FINISH"){
	  if ((line == "BONDS")||(line == "ANGLES")||(line == "DIHEDRALS")) {
	    string type = line;
	    int count;
	    fl >> count;
	    for (int i=0;i<count;i++){
	      fl >> line; //bond/angle/dih type not used
	      int ids[4];
              Interaction *ic;
	      fl >> ids[0]; fl>>ids[1];
	      if (type == "BONDS"){
	        ic = new IBond(id_map[ids[0]-1],id_map[ids[1]-1]); // -1 due to fortran vs c
	      } else if (type == "ANGLES"){
		fl >> ids[2];
	        ic = new IAngle(id_map[ids[0]-1],id_map[ids[1]-1],id_map[ids[2]-1]); // -1 due to fortran vs c
	      } else if (type == "DIHEDRALS"){
		fl >> ids[2]; fl >> ids[3];
	        ic = new IDihedral(id_map[ids[0]-1],id_map[ids[1]-1],id_map[ids[2]-1],id_map[ids[3]-1]); // -1 due to fortran vs c
	      }
              ic->setGroup(type);
              ic->setIndex(i);
              ic->setMolecule(mi->getId());
              top.AddBondedInteraction(ic);
              mi->AddInteraction(ic);
	      getline(fl,line);
	    }
	  }
	  fl >> line;
	  if (fl.eof())
            throw std::runtime_error("unexpected end of dlpoly file " + filename + " while scanning for 'FINISH'");
	}
	getline(fl, line); //rest of the FINISH line
	//replicate molecule
	for (int replica=1;replica<nreplica;replica++){
          Molecule *mi_replica = top.CreateMolecule(mol_name);
	  for(int i=0;i<mi->BeadCount();i++){
	    Bead *bead=mi->getBead(i);
	    BeadType *type = top.GetOrCreateBeadType(bead->Type()->getName());
	    string beadname=mi->getBeadName(i);
	    Bead *bead_replica = top.CreateBead(1, bead->getName(), type, res->getId(), bead->getM(), bead->getQ());
	    mi_replica->AddBead(bead_replica,beadname);
	    //TODO copy interactions
	  }
	}
      }
    }
    //we don't need the rest.
    fl.close();
#endif
    if ( boost::filesystem::basename(filepath).size() == 0 ) {
      if (filepath.parent_path().string().size() == 0) {
        filename="CONFIG";
      } else {
	filename=filepath.parent_path().string() + "/CONFIG";
      }
    } else {
      cout << "NOTE: Explicit dlploy topology filename given, so no config will be openend and no boundary conditions will set in the topology." << endl;
      return true;
    }
    fl.open(filename.c_str());
    if(fl.is_open()) {
      string line;
      getline(fl, line); //title
      getline(fl, line); // 2nd header line
      vec box_vectors[3];
      for (int i=0;i<3;i++){ // read 3 box lines
        getline(fl, line);
        if(fl.eof())
          throw std::runtime_error("unexpected end of file in dlpoly file " + filename +", when reading box vector"  +
              boost::lexical_cast<string>(i));
        Tokenizer tok(line, " ");
        vector<double> fields;
        tok.ConvertToVector<double>(fields);
        box_vectors[i]=vec(fields[0],fields[1],fields[2]);
      }
      matrix box(box_vectors[0],box_vectors[1],box_vectors[2]);
      top.setBox(box);
      fl.close();
    }
    else {
      cout << "NOTE: Could not open dlploy file " << filename << "so no boundary conditions, where set in the topology." << endl;
    }
    return true;
}

}}

<commit_msg>dlpolytopologyreader: generate exclusion lists<commit_after>/*
 * Copyright 2009-2013 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/convenience.hpp>
#include <votca/tools/getline.h>

#ifndef HAVE_NO_CONFIG
#include <votca_config.h>
#endif

#include "dlpolytopologyreader.h"
#ifdef DLPOLY_FORTRAN
#include "dlpoly/dlp_io_layer.h"
#include "fortan_mangling.h"
#endif

namespace votca { namespace csg {

bool DLPOLYTopologyReader::ReadTopology(string file, Topology &top)
{
    std::ifstream fl;
    boost::filesystem::path filepath(file.c_str());
    string filename;
#ifdef DLPOLY_FORTRAN
    if (file != ".dlpoly")
      throw std::runtime_error("Reading from different filename/directories not implemented yet. (use --top '.dlpoly')");

    struct FieldSpecsT  FieldBase;
    struct FrameSpecsT  FrameBase;
    struct MolecSpecsT *MolecBase;
    struct FieldSiteT  *FieldSite;
    struct FrameSiteT  *FrameSite;

    int idnode,matms,natms,nmols,nmolt;
    int istateF;

    int inode=matms=natms=nmols=nmolt=0;

    // TODO: istateF must be an enum!
    istateF=1;

    // TODO: we need to fix the file naming!
    FortranCInterface_GLOBAL(field_scan,FIELD_SCAN)(&istateF,&matms,&natms,&nmolt);

    MolecBase = new MolecSpecsT[nmolt];
    FieldSite = new FieldSiteT[natms];

    FieldBase.nmols = nmolt;
    FieldBase.natms = natms;

    FortranCInterface_GLOBAL(field_read,FIELD_READ)(&istateF,&FieldBase,MolecBase,FieldSite);

    // AB: if on return istateF < 0  => in the next F-call the relevant F-arrays will be deallocated (at the end)
    // AB: NOT TO RE-/DE-ALLOCATE F-arrays in the next F-call, reset istateF = 0
    istateF = 0;

    // TODO: fix residue naming / assignment
    Residue *res = top.CreateResidue("no");

    // read the atoms
    int mol_offset=0;
    for(int im=0; im<nmolt; im++){
        for(int imr=0; imr<MolecBase[im].nrept; ++imr) {
            Molecule *mi = top.CreateMolecule(MolecBase[im].name);
            for(int ims=0; ims<MolecBase[im].nsites; ims++) {
	        int is=mol_offset+ims;
                BeadType *type = top.GetOrCreateBeadType(FieldSite[is].type); // what is
	        string beadname = boost::lexical_cast<string>(FieldSite[is].name) + "#" + boost::lexical_cast<string>(ims+1);
                Bead *bead = top.CreateBead(1, beadname, type, res->getId(), FieldSite[is].m, FieldSite[is].q);

                stringstream nm;
                nm << bead->getResnr() + 1 << ":" <<  top.getResidue(bead->getResnr())->getName() << ":" << bead->getName();
                mi->AddBead(bead, nm.str());
            }
        }
	mol_offset+=MolecBase[im].nsites;
    }

    delete [] MolecBase;
    delete [] FieldSite;
#else
    // TODO: fix residue naming / assignment
    Residue *res = top.CreateResidue("no");

    if ( boost::filesystem::basename(filepath).size() == 0 ) {
      if (filepath.parent_path().string().size() == 0) {
        filename="FIELD";
      } else {
	filename=filepath.parent_path().string() + "/FIELD";
      }
    } else {
      filename=file;
    }
    fl.open(filename.c_str());
    if (!fl.is_open()){
      throw std::runtime_error("could open dlpoly file " + filename);
    } else {
      string line;
      getline(fl, line); //title
      getline(fl, line); //unit line
      fl >> line;
      if (line != "MOLECULES")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'MOLECULES' got" + line);
      int nmol_types;
      fl >> nmol_types;
      getline(fl, line); //rest of MOLECULES line
      int id=0;
      for (int nmol_type=0;nmol_type<nmol_types; nmol_type++){
	string mol_name;
        getline(fl, mol_name); //molecule name might incl. spaces
	boost::erase_all(mol_name, " ");
        Molecule *mi = top.CreateMolecule(mol_name);
        fl >> line;
        if (line != "NUMMOLS")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'NUMMOLS' got" + line);
	int nreplica;
	fl >> nreplica;
	fl >> line;
        if (line != "ATOMS")
          throw std::runtime_error("unexpected line in dlpoly file " + filename + ", expected 'ATOMS' got" + line);
	int natoms;
	fl >> natoms;
	//read molecule
	int id_map[natoms];
	for (int i=0;i<natoms;){//i is altered in reapeater loop
	  string beadtype;
	  fl >> beadtype;
	  BeadType *type = top.GetOrCreateBeadType(beadtype);
	  double mass;
	  fl >> mass;
	  double charge;
	  fl >> charge;
          getline(fl,line); //rest of the atom line
          Tokenizer tok(line, " ");
          vector<int> fields;
          tok.ConvertToVector<int>(fields);
	  int repeater=1;
	  if (fields.size() > 1)
	    repeater=fields[0];
	  for(int j=0;j<repeater;j++){
	    string beadname = beadtype + "#" + boost::lexical_cast<string>(j+1);
	    Bead *bead = top.CreateBead(1, beadname , type, res->getId(), mass, charge);
            stringstream nm;
            nm << bead->getResnr() + 1 << ":" <<  top.getResidue(bead->getResnr())->getName() << ":" << bead->getName();
            mi->AddBead(bead, nm.str());
	    id_map[i]=bead->getId();
	    i++;
	  }
	}
	while (line != "FINISH"){
	  if ((line == "BONDS")||(line == "ANGLES")||(line == "DIHEDRALS")) {
	    string type = line;
	    int count;
	    fl >> count;
	    for (int i=0;i<count;i++){
	      fl >> line; //bond/angle/dih type not used
	      int ids[4];
              Interaction *ic;
	      fl >> ids[0]; fl>>ids[1];
	      if (type == "BONDS"){
	        ic = new IBond(id_map[ids[0]-1],id_map[ids[1]-1]); // -1 due to fortran vs c
	      } else if (type == "ANGLES"){
		fl >> ids[2];
	        ic = new IAngle(id_map[ids[0]-1],id_map[ids[1]-1],id_map[ids[2]-1]); // -1 due to fortran vs c
	      } else if (type == "DIHEDRALS"){
		fl >> ids[2]; fl >> ids[3];
	        ic = new IDihedral(id_map[ids[0]-1],id_map[ids[1]-1],id_map[ids[2]-1],id_map[ids[3]-1]); // -1 due to fortran vs c
	      }
              ic->setGroup(type);
              ic->setIndex(i);
              ic->setMolecule(mi->getId());
              top.AddBondedInteraction(ic);
              mi->AddInteraction(ic);
	      getline(fl,line);
	    }
	  }
	  fl >> line;
	  if (fl.eof())
            throw std::runtime_error("unexpected end of dlpoly file " + filename + " while scanning for 'FINISH'");
	}
	getline(fl, line); //rest of the FINISH line
	//replicate molecule
	for (int replica=1;replica<nreplica;replica++){
          Molecule *mi_replica = top.CreateMolecule(mol_name);
	  for(int i=0;i<mi->BeadCount();i++){
	    Bead *bead=mi->getBead(i);
	    BeadType *type = top.GetOrCreateBeadType(bead->Type()->getName());
	    string beadname=mi->getBeadName(i);
	    Bead *bead_replica = top.CreateBead(1, bead->getName(), type, res->getId(), bead->getM(), bead->getQ());
	    mi_replica->AddBead(bead_replica,beadname);
	  }
	  InteractionContainer ics=mi->Interactions();
          for(vector<Interaction *>::iterator ic=ics.begin(); ic!=ics.end(); ++ic) {
            Interaction *ic_replica;
	    //TODO: change if beads are not continous anymore
	    int offset = mi_replica->getBead(0)->getId() - mi->getBead(0)->getId();
	    if ((*ic)->BeadCount() == 2) {
	      ic_replica = new IBond((*ic)->getBeadId(0)+offset,(*ic)->getBeadId(1)+offset);
	    } else if ((*ic)->BeadCount() == 3) {
	      ic_replica = new IAngle((*ic)->getBeadId(0)+offset,(*ic)->getBeadId(1)+offset,(*ic)->getBeadId(2)+offset);
	    } else if ((*ic)->BeadCount() == 4) {
	      ic_replica = new IDihedral((*ic)->getBeadId(0)+offset,(*ic)->getBeadId(1)+offset,(*ic)->getBeadId(2)+offset,(*ic)->getBeadId(3)+offset);
	    }
            ic_replica->setGroup((*ic)->getGroup());
            ic_replica->setIndex((*ic)->getIndex());
            ic_replica->setMolecule(mi_replica->getId());
            top.AddBondedInteraction(ic_replica);
            mi_replica->AddInteraction(ic_replica);
	  }
	}
      }
      top.RebuildExclusions();
    }
    //we don't need the rest.
    fl.close();
#endif
    if ( boost::filesystem::basename(filepath).size() == 0 ) {
      if (filepath.parent_path().string().size() == 0) {
        filename="CONFIG";
      } else {
	filename=filepath.parent_path().string() + "/CONFIG";
      }
    } else {
      cout << "NOTE: Explicit dlploy topology filename given, so no config will be openend and no boundary conditions will set in the topology." << endl;
      return true;
    }
    fl.open(filename.c_str());
    if(fl.is_open()) {
      string line;
      getline(fl, line); //title
      getline(fl, line); // 2nd header line
      vec box_vectors[3];
      for (int i=0;i<3;i++){ // read 3 box lines
        getline(fl, line);
        if(fl.eof())
          throw std::runtime_error("unexpected end of file in dlpoly file " + filename +", when reading box vector"  +
              boost::lexical_cast<string>(i));
        Tokenizer tok(line, " ");
        vector<double> fields;
        tok.ConvertToVector<double>(fields);
        box_vectors[i]=vec(fields[0],fields[1],fields[2]);
      }
      matrix box(box_vectors[0],box_vectors[1],box_vectors[2]);
      top.setBox(box);
      fl.close();
    }
    else {
      cout << "NOTE: Could not open dlploy file " << filename << "so no boundary conditions, where set in the topology." << endl;
    }
    return true;
}

}}

<|endoftext|>


<commit_before>#ifndef GENERICS_H
#define GENERICS_H

#include"objects.hpp"

class Semispace;
class ToPointerUser;

/*-----------------------------------------------------------------------------
GenericTraverser
-----------------------------------------------------------------------------*/
/*An abstract base class which provides a
"traverse" method.  This method is invoked
on each reference of an object.
*/
class GenericTraverser {
public:
	virtual void traverse(Object::ref&) =0;
	virtual ~GenericTraverser() {}
};

/*-----------------------------------------------------------------------------
HashingClass
-----------------------------------------------------------------------------*/
/*A class which provides a "enhash" method, which
perturbs its internal state.
*/
class HashingClass {
private:
	uint32_t a, b;
public:
	uint32_t c;
	void enhash(size_t);
	HashingClass(void);
};

/*-----------------------------------------------------------------------------
Generic
-----------------------------------------------------------------------------*/

class Generic {
private:
	Object::ref to_pointer;

public:

	virtual void traverse_references(GenericTraverser* gt) {
		/*default to having no references to traverse*/
		/*example for Cons:
		gt->traverse(a);
		gt->traverse(d);
		*/
	}

	/*some objects have extra allocated space at their ends
	(e.g. Closure).
 	This virtual function returns the total size of the class
	plus extra allocated space.
	*/
	virtual size_t real_size(void) const =0;

	/*Copies an object, used for message passing and
	copying garbage collection
	*/
	virtual Generic* clone(Semispace*) const =0;

	/*broken hearts for GC*/
	virtual void break_heart(Generic*) =0;

	/*------These two functions must be redefined together------*/
	virtual bool is(Object::ref) const {
		/*return true if the given Object::ref is-equal to
		this object, even if they have different addresses
		*/
		return false;
	}
	virtual void enhash(HashingClass* hc) const {
		/*Should provide hc with all the values
		it uses to determine equality, as in is()
		above.
		Should *not* provide Generic* pointers,
		because those *will* change in a GC, and
		we want hash tables to work even across
		a GC.
		*/
		return;
	}
	/*------The above two functions must be redefined together------*/

	virtual Object::ref type(void) const =0;

	/*dtor*/
	virtual ~Generic() { }

	friend class ToPointerUser;
};

/*-----------------------------------------------------------------------------
Broken Heart tags
-----------------------------------------------------------------------------*/

void throw_OverBrokenHeart(Generic*);

class BrokenHeart : public Generic {
private:
	// disallowed
	BrokenHeart();
	BrokenHeart(BrokenHeart const&);
public:
	Generic* to;
	virtual void break_heart(Generic* to) {
		/*already broken - don't break too much!*/
		throw_OverBrokenHeart(to);
	}
	virtual Generic* clone(Semispace*) const {
		/*broken - why are we cloning this?*/
		throw_OverBrokenHeart(to);
                return NULL;
	}
	Object::ref type(void) const {
		return Object::to_ref(symbol_unspecified);
	}
	BrokenHeart(Generic* nto) : to(nto) { }
};

class BrokenHeartVariadic : public BrokenHeart {
private:
	// disallowed
	BrokenHeartVariadic();
	BrokenHeartVariadic(BrokenHeart const&);
protected:
	size_t sz;
public:
	BrokenHeartVariadic(Generic* x, size_t nsz)
		: BrokenHeart(x), sz(nsz) { }
};

/*-----------------------------------------------------------------------------
Size computations
-----------------------------------------------------------------------------*/

template<class T>
static inline size_t compute_size(void) {
	size_t sizeofBrokenHeart = Object::round_up_to_alignment(
			sizeof(BrokenHeart)
	);
	size_t sizeofT = Object::round_up_to_alignment(sizeof(T));
	return
	(sizeofT < sizeofBrokenHeart) ?		sizeofBrokenHeart :
	/*otherwise*/				sizeofT ;
}

template<class T>
static inline size_t compute_size_variadic(size_t sz) {
	/*remember that this is variadic*/
	size_t sizeofBrokenHeart = Object::round_up_to_alignment(
			sizeof(BrokenHeartVariadic)
	);
	size_t sizeofT = Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
		);
	return
	(sizeofT < sizeofBrokenHeart) ?		sizeofBrokenHeart :
	/*otherwise*/				sizeofT ;
}

/*-----------------------------------------------------------------------------
ToPointerUser
-----------------------------------------------------------------------------*/
/*A class intended for being derived, which can access the
to_pointer of Generic's
*/

class ToPointerUser {
protected:
	inline Object::ref& to_pointer(Generic& g) F_INLINE {
		return g.to_pointer;
	}
	/*Only for deriving!*/
	ToPointerUser(void) { }
}

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

static inline bool is(Object::ref a, Object::ref b) {
	if(a == b) return true;
	if(!is_a<Generic*>(a)) return false;
	return as_a<Generic*>(a)->is(b);
}

#endif // GENERICS_H

<commit_msg>inc/generics.hpp: missing ;<commit_after>#ifndef GENERICS_H
#define GENERICS_H

#include"objects.hpp"

class Semispace;
class ToPointerUser;

/*-----------------------------------------------------------------------------
GenericTraverser
-----------------------------------------------------------------------------*/
/*An abstract base class which provides a
"traverse" method.  This method is invoked
on each reference of an object.
*/
class GenericTraverser {
public:
	virtual void traverse(Object::ref&) =0;
	virtual ~GenericTraverser() {}
};

/*-----------------------------------------------------------------------------
HashingClass
-----------------------------------------------------------------------------*/
/*A class which provides a "enhash" method, which
perturbs its internal state.
*/
class HashingClass {
private:
	uint32_t a, b;
public:
	uint32_t c;
	void enhash(size_t);
	HashingClass(void);
};

/*-----------------------------------------------------------------------------
Generic
-----------------------------------------------------------------------------*/

class Generic {
private:
	Object::ref to_pointer;

public:

	virtual void traverse_references(GenericTraverser* gt) {
		/*default to having no references to traverse*/
		/*example for Cons:
		gt->traverse(a);
		gt->traverse(d);
		*/
	}

	/*some objects have extra allocated space at their ends
	(e.g. Closure).
 	This virtual function returns the total size of the class
	plus extra allocated space.
	*/
	virtual size_t real_size(void) const =0;

	/*Copies an object, used for message passing and
	copying garbage collection
	*/
	virtual Generic* clone(Semispace*) const =0;

	/*broken hearts for GC*/
	virtual void break_heart(Generic*) =0;

	/*------These two functions must be redefined together------*/
	virtual bool is(Object::ref) const {
		/*return true if the given Object::ref is-equal to
		this object, even if they have different addresses
		*/
		return false;
	}
	virtual void enhash(HashingClass* hc) const {
		/*Should provide hc with all the values
		it uses to determine equality, as in is()
		above.
		Should *not* provide Generic* pointers,
		because those *will* change in a GC, and
		we want hash tables to work even across
		a GC.
		*/
		return;
	}
	/*------The above two functions must be redefined together------*/

	virtual Object::ref type(void) const =0;

	/*dtor*/
	virtual ~Generic() { }

	friend class ToPointerUser;
};

/*-----------------------------------------------------------------------------
Broken Heart tags
-----------------------------------------------------------------------------*/

void throw_OverBrokenHeart(Generic*);

class BrokenHeart : public Generic {
private:
	// disallowed
	BrokenHeart();
	BrokenHeart(BrokenHeart const&);
public:
	Generic* to;
	virtual void break_heart(Generic* to) {
		/*already broken - don't break too much!*/
		throw_OverBrokenHeart(to);
	}
	virtual Generic* clone(Semispace*) const {
		/*broken - why are we cloning this?*/
		throw_OverBrokenHeart(to);
                return NULL;
	}
	Object::ref type(void) const {
		return Object::to_ref(symbol_unspecified);
	}
	BrokenHeart(Generic* nto) : to(nto) { }
};

class BrokenHeartVariadic : public BrokenHeart {
private:
	// disallowed
	BrokenHeartVariadic();
	BrokenHeartVariadic(BrokenHeart const&);
protected:
	size_t sz;
public:
	BrokenHeartVariadic(Generic* x, size_t nsz)
		: BrokenHeart(x), sz(nsz) { }
};

/*-----------------------------------------------------------------------------
Size computations
-----------------------------------------------------------------------------*/

template<class T>
static inline size_t compute_size(void) {
	size_t sizeofBrokenHeart = Object::round_up_to_alignment(
			sizeof(BrokenHeart)
	);
	size_t sizeofT = Object::round_up_to_alignment(sizeof(T));
	return
	(sizeofT < sizeofBrokenHeart) ?		sizeofBrokenHeart :
	/*otherwise*/				sizeofT ;
}

template<class T>
static inline size_t compute_size_variadic(size_t sz) {
	/*remember that this is variadic*/
	size_t sizeofBrokenHeart = Object::round_up_to_alignment(
			sizeof(BrokenHeartVariadic)
	);
	size_t sizeofT = Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
		);
	return
	(sizeofT < sizeofBrokenHeart) ?		sizeofBrokenHeart :
	/*otherwise*/				sizeofT ;
}

/*-----------------------------------------------------------------------------
ToPointerUser
-----------------------------------------------------------------------------*/
/*A class intended for being derived, which can access the
to_pointer of Generic's
*/

class ToPointerUser {
protected:
	inline Object::ref& to_pointer(Generic& g) F_INLINE {
		return g.to_pointer;
	}
	/*Only for deriving!*/
	ToPointerUser(void) { }
};

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

static inline bool is(Object::ref a, Object::ref b) {
	if(a == b) return true;
	if(!is_a<Generic*>(a)) return false;
	return as_a<Generic*>(a)->is(b);
}

#endif // GENERICS_H

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * 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 Google Inc. 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 "config.h"
#include "bindings/v8/ScriptProfiler.h"

#include "V8ArrayBufferView.h"
#include "V8Node.h"
#include "V8Window.h"
#include "bindings/v8/RetainedDOMInfo.h"
#include "bindings/v8/ScriptObject.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/WrapperTypeInfo.h"
#include "core/dom/Document.h"
#include "core/dom/WebCoreMemoryInstrumentation.h"
#include "core/inspector/BindingVisitors.h"

#include <v8-profiler.h>
#include <v8.h>

#include "wtf/ThreadSpecific.h"

namespace WebCore {

typedef HashMap<String, double> ProfileNameIdleTimeMap;

void ScriptProfiler::start(const String& title)
{
    ProfileNameIdleTimeMap* profileNameIdleTimeMap = ScriptProfiler::currentProfileNameIdleTimeMap();
    if (profileNameIdleTimeMap->contains(title))
        return;
    profileNameIdleTimeMap->add(title, 0);

    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
    if (!profiler)
        return;
    v8::HandleScope handleScope(isolate);
    profiler->StartCpuProfiling(v8String(title, isolate), true);
}

PassRefPtr<ScriptProfile> ScriptProfiler::stop(const String& title)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
    if (!profiler)
        return 0;
    v8::HandleScope handleScope(isolate);
    const v8::CpuProfile* profile = profiler->StopCpuProfiling(v8String(title, isolate));
    if (!profile)
        return 0;

    String profileTitle = toWebCoreString(profile->GetTitle());
    double idleTime = 0.0;
    ProfileNameIdleTimeMap* profileNameIdleTimeMap = ScriptProfiler::currentProfileNameIdleTimeMap();
    ProfileNameIdleTimeMap::iterator profileIdleTime = profileNameIdleTimeMap->find(profileTitle);
    if (profileIdleTime != profileNameIdleTimeMap->end()) {
        idleTime = profileIdleTime->value * 1000.0;
        profileNameIdleTimeMap->remove(profileIdleTime);
    }

    return ScriptProfile::create(profile, idleTime);
}

void ScriptProfiler::collectGarbage()
{
    v8::V8::LowMemoryNotification();
}

ScriptObject ScriptProfiler::objectByHeapObjectId(unsigned id)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return ScriptObject();
    // As ids are unique, it doesn't matter which HeapSnapshot owns HeapGraphNode.
    // We need to find first HeapSnapshot containing a node with the specified id.
    const v8::HeapGraphNode* node = 0;
    for (int i = 0, l = profiler->GetSnapshotCount(); i < l; ++i) {
        const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
        node = snapshot->GetNodeById(id);
        if (node)
            break;
    }
    if (!node)
        return ScriptObject();

    v8::HandleScope handleScope(isolate);
    v8::Handle<v8::Value> value = node->GetHeapValue();
    if (!value->IsObject())
        return ScriptObject();

    v8::Handle<v8::Object> object = value.As<v8::Object>();

    if (object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount) {
        v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex);
        // Skip wrapper boilerplates which are like regular wrappers but don't have
        // native object.
        if (!wrapper.IsEmpty() && wrapper->IsUndefined())
            return ScriptObject();
    }

    ScriptState* scriptState = ScriptState::forContext(object->CreationContext());
    return ScriptObject(scriptState, object);
}

unsigned ScriptProfiler::getHeapObjectId(const ScriptValue& value)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    v8::SnapshotObjectId id = profiler->GetObjectId(value.v8Value());
    return id;
}

namespace {

class ActivityControlAdapter : public v8::ActivityControl {
public:
    ActivityControlAdapter(ScriptProfiler::HeapSnapshotProgress* progress)
            : m_progress(progress), m_firstReport(true) { }
    ControlOption ReportProgressValue(int done, int total)
    {
        ControlOption result = m_progress->isCanceled() ? kAbort : kContinue;
        if (m_firstReport) {
            m_firstReport = false;
            m_progress->Start(total);
        } else
            m_progress->Worked(done);
        if (done >= total)
            m_progress->Done();
        return result;
    }
private:
    ScriptProfiler::HeapSnapshotProgress* m_progress;
    bool m_firstReport;
};

class GlobalObjectNameResolver : public v8::HeapProfiler::ObjectNameResolver {
public:
    virtual const char* GetName(v8::Handle<v8::Object> object)
    {
        if (V8DOMWrapper::isWrapperOfType(object, &V8Window::info)) {
            DOMWindow* window = V8Window::toNative(object);
            if (window) {
                CString url = window->document()->url().string().utf8();
                m_strings.append(url);
                return url.data();
            }
        }
        return 0;
    }

private:
    Vector<CString> m_strings;
};

} // namespace

void ScriptProfiler::startTrackingHeapObjects()
{
    v8::Isolate::GetCurrent()->GetHeapProfiler()->StartTrackingHeapObjects();
}

namespace {

class HeapStatsStream : public v8::OutputStream {
public:
    HeapStatsStream(ScriptProfiler::OutputStream* stream) : m_stream(stream) { }
    virtual void EndOfStream() OVERRIDE { }

    virtual WriteResult WriteAsciiChunk(char* data, int size) OVERRIDE
    {
        ASSERT(false);
        return kAbort;
    }

    virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* updateData, int count) OVERRIDE
    {
        Vector<uint32_t> rawData(count * 3);
        for (int i = 0; i < count; ++i) {
            int offset = i * 3;
            rawData[offset] = updateData[i].index;
            rawData[offset + 1] = updateData[i].count;
            rawData[offset + 2] = updateData[i].size;
        }
        m_stream->write(rawData.data(), rawData.size());
        return kContinue;
    }

private:
    ScriptProfiler::OutputStream* m_stream;
};

}

unsigned ScriptProfiler::requestHeapStatsUpdate(ScriptProfiler::OutputStream* stream)
{
    HeapStatsStream heapStatsStream(stream);
    return v8::Isolate::GetCurrent()->GetHeapProfiler()->GetHeapStats(&heapStatsStream);
}

void ScriptProfiler::stopTrackingHeapObjects()
{
    v8::Isolate::GetCurrent()->GetHeapProfiler()->StopTrackingHeapObjects();
}

// FIXME: This method should receive a ScriptState, from which we should retrieve an Isolate.
PassRefPtr<ScriptHeapSnapshot> ScriptProfiler::takeHeapSnapshot(const String& title, HeapSnapshotProgress* control)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return 0;
    v8::HandleScope handleScope(isolate);
    ASSERT(control);
    ActivityControlAdapter adapter(control);
    GlobalObjectNameResolver resolver;
    const v8::HeapSnapshot* snapshot = profiler->TakeHeapSnapshot(v8String(title, isolate), &adapter, &resolver);
    return snapshot ? ScriptHeapSnapshot::create(snapshot) : 0;
}

static v8::RetainedObjectInfo* retainedDOMInfo(uint16_t classId, v8::Handle<v8::Value> wrapper)
{
    ASSERT(classId == v8DOMNodeClassId);
    if (!wrapper->IsObject())
        return 0;
    Node* node = V8Node::toNative(wrapper.As<v8::Object>());
    return node ? new RetainedDOMInfo(node) : 0;
}

void ScriptProfiler::initialize()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (profiler)
        profiler->SetWrapperClassInfoProvider(v8DOMNodeClassId, &retainedDOMInfo);
}

void ScriptProfiler::visitNodeWrappers(WrappedNodeVisitor* visitor)
{
    // visitNodeWrappers() should receive a ScriptState and retrieve an Isolate
    // from the ScriptState.
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HandleScope handleScope(isolate);

    class DOMNodeWrapperVisitor : public v8::PersistentHandleVisitor {
    public:
        DOMNodeWrapperVisitor(WrappedNodeVisitor* visitor, v8::Isolate* isolate)
            : m_visitor(visitor)
            , m_isolate(isolate)
        {
        }

        virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
        {
            if (classId != v8DOMNodeClassId)
                return;
            // Casting to Handle is safe here, since the Persistent cannot get
            // GCd during visiting.
            v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
            ASSERT(V8Node::HasInstance(*wrapper, m_isolate, worldType(m_isolate)));
            ASSERT((*wrapper)->IsObject());
            m_visitor->visitNode(V8Node::toNative(*wrapper));
        }

    private:
        WrappedNodeVisitor* m_visitor;
        v8::Isolate* m_isolate;
    } wrapperVisitor(visitor, isolate);

    v8::V8::VisitHandlesWithClassIds(&wrapperVisitor);
}

void ScriptProfiler::visitExternalStrings(ExternalStringVisitor* visitor)
{
    V8PerIsolateData::current()->visitExternalStrings(visitor);
}

void ScriptProfiler::visitExternalArrays(ExternalArrayVisitor* visitor)
{
    class DOMObjectWrapperVisitor : public v8::PersistentHandleVisitor {
    public:
        explicit DOMObjectWrapperVisitor(ExternalArrayVisitor* visitor)
            : m_visitor(visitor)
        {
        }

        virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
        {
            if (classId != v8DOMObjectClassId)
                return;
            // Casting to Handle is safe here, since the Persistent cannot get
            // GCd during visiting.
            ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject());
            v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
            if (!toWrapperTypeInfo(*wrapper)->isSubclass(&V8ArrayBufferView::info))
                return;
            m_visitor->visitJSExternalArray(V8ArrayBufferView::toNative(*wrapper));
        }

    private:
        ExternalArrayVisitor* m_visitor;
    } wrapperVisitor(visitor);

    v8::V8::VisitHandlesWithClassIds(&wrapperVisitor);
}

void ScriptProfiler::collectBindingMemoryInfo(MemoryInstrumentation* instrumentation)
{
    V8PerIsolateData* data = V8PerIsolateData::current();
    instrumentation->addRootObject(data);
}

size_t ScriptProfiler::profilerSnapshotsSize()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return 0;
    return profiler->GetProfilerMemorySize();
}

ProfileNameIdleTimeMap* ScriptProfiler::currentProfileNameIdleTimeMap()
{
    AtomicallyInitializedStatic(WTF::ThreadSpecific<ProfileNameIdleTimeMap>*, map = new WTF::ThreadSpecific<ProfileNameIdleTimeMap>);
    return *map;
}

} // namespace WebCore
<commit_msg>Fix: ScriptProfiler::visitNodeWrappers shouldn't try to check for wrappers in a specific world.<commit_after>/*
 * Copyright (c) 2011, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * 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 Google Inc. 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 "config.h"
#include "bindings/v8/ScriptProfiler.h"

#include "V8ArrayBufferView.h"
#include "V8Node.h"
#include "V8Window.h"
#include "bindings/v8/RetainedDOMInfo.h"
#include "bindings/v8/ScriptObject.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/WrapperTypeInfo.h"
#include "core/dom/Document.h"
#include "core/dom/WebCoreMemoryInstrumentation.h"
#include "core/inspector/BindingVisitors.h"

#include <v8-profiler.h>
#include <v8.h>

#include "wtf/ThreadSpecific.h"

namespace WebCore {

typedef HashMap<String, double> ProfileNameIdleTimeMap;

void ScriptProfiler::start(const String& title)
{
    ProfileNameIdleTimeMap* profileNameIdleTimeMap = ScriptProfiler::currentProfileNameIdleTimeMap();
    if (profileNameIdleTimeMap->contains(title))
        return;
    profileNameIdleTimeMap->add(title, 0);

    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
    if (!profiler)
        return;
    v8::HandleScope handleScope(isolate);
    profiler->StartCpuProfiling(v8String(title, isolate), true);
}

PassRefPtr<ScriptProfile> ScriptProfiler::stop(const String& title)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
    if (!profiler)
        return 0;
    v8::HandleScope handleScope(isolate);
    const v8::CpuProfile* profile = profiler->StopCpuProfiling(v8String(title, isolate));
    if (!profile)
        return 0;

    String profileTitle = toWebCoreString(profile->GetTitle());
    double idleTime = 0.0;
    ProfileNameIdleTimeMap* profileNameIdleTimeMap = ScriptProfiler::currentProfileNameIdleTimeMap();
    ProfileNameIdleTimeMap::iterator profileIdleTime = profileNameIdleTimeMap->find(profileTitle);
    if (profileIdleTime != profileNameIdleTimeMap->end()) {
        idleTime = profileIdleTime->value * 1000.0;
        profileNameIdleTimeMap->remove(profileIdleTime);
    }

    return ScriptProfile::create(profile, idleTime);
}

void ScriptProfiler::collectGarbage()
{
    v8::V8::LowMemoryNotification();
}

ScriptObject ScriptProfiler::objectByHeapObjectId(unsigned id)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return ScriptObject();
    // As ids are unique, it doesn't matter which HeapSnapshot owns HeapGraphNode.
    // We need to find first HeapSnapshot containing a node with the specified id.
    const v8::HeapGraphNode* node = 0;
    for (int i = 0, l = profiler->GetSnapshotCount(); i < l; ++i) {
        const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
        node = snapshot->GetNodeById(id);
        if (node)
            break;
    }
    if (!node)
        return ScriptObject();

    v8::HandleScope handleScope(isolate);
    v8::Handle<v8::Value> value = node->GetHeapValue();
    if (!value->IsObject())
        return ScriptObject();

    v8::Handle<v8::Object> object = value.As<v8::Object>();

    if (object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount) {
        v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex);
        // Skip wrapper boilerplates which are like regular wrappers but don't have
        // native object.
        if (!wrapper.IsEmpty() && wrapper->IsUndefined())
            return ScriptObject();
    }

    ScriptState* scriptState = ScriptState::forContext(object->CreationContext());
    return ScriptObject(scriptState, object);
}

unsigned ScriptProfiler::getHeapObjectId(const ScriptValue& value)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    v8::SnapshotObjectId id = profiler->GetObjectId(value.v8Value());
    return id;
}

namespace {

class ActivityControlAdapter : public v8::ActivityControl {
public:
    ActivityControlAdapter(ScriptProfiler::HeapSnapshotProgress* progress)
            : m_progress(progress), m_firstReport(true) { }
    ControlOption ReportProgressValue(int done, int total)
    {
        ControlOption result = m_progress->isCanceled() ? kAbort : kContinue;
        if (m_firstReport) {
            m_firstReport = false;
            m_progress->Start(total);
        } else
            m_progress->Worked(done);
        if (done >= total)
            m_progress->Done();
        return result;
    }
private:
    ScriptProfiler::HeapSnapshotProgress* m_progress;
    bool m_firstReport;
};

class GlobalObjectNameResolver : public v8::HeapProfiler::ObjectNameResolver {
public:
    virtual const char* GetName(v8::Handle<v8::Object> object)
    {
        if (V8DOMWrapper::isWrapperOfType(object, &V8Window::info)) {
            DOMWindow* window = V8Window::toNative(object);
            if (window) {
                CString url = window->document()->url().string().utf8();
                m_strings.append(url);
                return url.data();
            }
        }
        return 0;
    }

private:
    Vector<CString> m_strings;
};

} // namespace

void ScriptProfiler::startTrackingHeapObjects()
{
    v8::Isolate::GetCurrent()->GetHeapProfiler()->StartTrackingHeapObjects();
}

namespace {

class HeapStatsStream : public v8::OutputStream {
public:
    HeapStatsStream(ScriptProfiler::OutputStream* stream) : m_stream(stream) { }
    virtual void EndOfStream() OVERRIDE { }

    virtual WriteResult WriteAsciiChunk(char* data, int size) OVERRIDE
    {
        ASSERT(false);
        return kAbort;
    }

    virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* updateData, int count) OVERRIDE
    {
        Vector<uint32_t> rawData(count * 3);
        for (int i = 0; i < count; ++i) {
            int offset = i * 3;
            rawData[offset] = updateData[i].index;
            rawData[offset + 1] = updateData[i].count;
            rawData[offset + 2] = updateData[i].size;
        }
        m_stream->write(rawData.data(), rawData.size());
        return kContinue;
    }

private:
    ScriptProfiler::OutputStream* m_stream;
};

}

unsigned ScriptProfiler::requestHeapStatsUpdate(ScriptProfiler::OutputStream* stream)
{
    HeapStatsStream heapStatsStream(stream);
    return v8::Isolate::GetCurrent()->GetHeapProfiler()->GetHeapStats(&heapStatsStream);
}

void ScriptProfiler::stopTrackingHeapObjects()
{
    v8::Isolate::GetCurrent()->GetHeapProfiler()->StopTrackingHeapObjects();
}

// FIXME: This method should receive a ScriptState, from which we should retrieve an Isolate.
PassRefPtr<ScriptHeapSnapshot> ScriptProfiler::takeHeapSnapshot(const String& title, HeapSnapshotProgress* control)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return 0;
    v8::HandleScope handleScope(isolate);
    ASSERT(control);
    ActivityControlAdapter adapter(control);
    GlobalObjectNameResolver resolver;
    const v8::HeapSnapshot* snapshot = profiler->TakeHeapSnapshot(v8String(title, isolate), &adapter, &resolver);
    return snapshot ? ScriptHeapSnapshot::create(snapshot) : 0;
}

static v8::RetainedObjectInfo* retainedDOMInfo(uint16_t classId, v8::Handle<v8::Value> wrapper)
{
    ASSERT(classId == v8DOMNodeClassId);
    if (!wrapper->IsObject())
        return 0;
    Node* node = V8Node::toNative(wrapper.As<v8::Object>());
    return node ? new RetainedDOMInfo(node) : 0;
}

void ScriptProfiler::initialize()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (profiler)
        profiler->SetWrapperClassInfoProvider(v8DOMNodeClassId, &retainedDOMInfo);
}

void ScriptProfiler::visitNodeWrappers(WrappedNodeVisitor* visitor)
{
    // visitNodeWrappers() should receive a ScriptState and retrieve an Isolate
    // from the ScriptState.
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HandleScope handleScope(isolate);

    class DOMNodeWrapperVisitor : public v8::PersistentHandleVisitor {
    public:
        DOMNodeWrapperVisitor(WrappedNodeVisitor* visitor, v8::Isolate* isolate)
            : m_visitor(visitor)
            , m_isolate(isolate)
        {
        }

        virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
        {
            if (classId != v8DOMNodeClassId)
                return;
            // Casting to Handle is safe here, since the Persistent cannot get
            // GCd during visiting.
            v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
            ASSERT(V8Node::HasInstanceInAnyWorld(*wrapper, m_isolate));
            ASSERT((*wrapper)->IsObject());
            m_visitor->visitNode(V8Node::toNative(*wrapper));
        }

    private:
        WrappedNodeVisitor* m_visitor;
        v8::Isolate* m_isolate;
    } wrapperVisitor(visitor, isolate);

    v8::V8::VisitHandlesWithClassIds(&wrapperVisitor);
}

void ScriptProfiler::visitExternalStrings(ExternalStringVisitor* visitor)
{
    V8PerIsolateData::current()->visitExternalStrings(visitor);
}

void ScriptProfiler::visitExternalArrays(ExternalArrayVisitor* visitor)
{
    class DOMObjectWrapperVisitor : public v8::PersistentHandleVisitor {
    public:
        explicit DOMObjectWrapperVisitor(ExternalArrayVisitor* visitor)
            : m_visitor(visitor)
        {
        }

        virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
        {
            if (classId != v8DOMObjectClassId)
                return;
            // Casting to Handle is safe here, since the Persistent cannot get
            // GCd during visiting.
            ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject());
            v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
            if (!toWrapperTypeInfo(*wrapper)->isSubclass(&V8ArrayBufferView::info))
                return;
            m_visitor->visitJSExternalArray(V8ArrayBufferView::toNative(*wrapper));
        }

    private:
        ExternalArrayVisitor* m_visitor;
    } wrapperVisitor(visitor);

    v8::V8::VisitHandlesWithClassIds(&wrapperVisitor);
}

void ScriptProfiler::collectBindingMemoryInfo(MemoryInstrumentation* instrumentation)
{
    V8PerIsolateData* data = V8PerIsolateData::current();
    instrumentation->addRootObject(data);
}

size_t ScriptProfiler::profilerSnapshotsSize()
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
    if (!profiler)
        return 0;
    return profiler->GetProfilerMemorySize();
}

ProfileNameIdleTimeMap* ScriptProfiler::currentProfileNameIdleTimeMap()
{
    AtomicallyInitializedStatic(WTF::ThreadSpecific<ProfileNameIdleTimeMap>*, map = new WTF::ThreadSpecific<ProfileNameIdleTimeMap>);
    return *map;
}

} // namespace WebCore
<|endoftext|>


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

#include "config.h"
#include "core/css/CSSFontFaceSource.h"

#include "RuntimeEnabledFeatures.h"
#include "core/css/CSSCustomFontData.h"
#include "core/css/CSSFontFace.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "wtf/CurrentTime.h"

#if ENABLE(SVG_FONTS)
#include "SVGNames.h"
#include "core/svg/SVGFontData.h"
#include "core/svg/SVGFontElement.h"
#include "core/svg/SVGFontFaceElement.h"
#endif

namespace WebCore {

CSSFontFaceSource::CSSFontFaceSource(const String& str, FontResource* font)
    : m_string(str)
    , m_font(font)
    , m_face(0)
#if ENABLE(SVG_FONTS)
    , m_hasExternalSVGFont(false)
#endif
{
    if (m_font)
        m_font->addClient(this);
}

CSSFontFaceSource::~CSSFontFaceSource()
{
    if (m_font)
        m_font->removeClient(this);
    pruneTable();
}

void CSSFontFaceSource::pruneTable()
{
    if (m_fontDataTable.isEmpty())
        return;

    for (FontDataTable::iterator it = m_fontDataTable.begin(); it != m_fontDataTable.end(); ++it) {
        SimpleFontData* fontData = it->value.get();
        if (fontData && fontData->customFontData())
            fontData->customFontData()->clearCSSFontFaceSource();
    }
    m_fontDataTable.clear();
}

bool CSSFontFaceSource::isLocal() const
{
    if (m_font)
        return false;
#if ENABLE(SVG_FONTS)
    if (m_svgFontFaceElement)
        return false;
#endif
    return true;
}

bool CSSFontFaceSource::isLoading() const
{
    if (m_font)
        return !m_font->stillNeedsLoad() && !m_font->isLoaded();
    return false;
}

bool CSSFontFaceSource::isLoaded() const
{
    if (m_font)
        return m_font->isLoaded();
    return true;
}

bool CSSFontFaceSource::isValid() const
{
    if (m_font)
        return !m_font->errorOccurred();
    return true;
}

void CSSFontFaceSource::didStartFontLoad(FontResource*)
{
    // Avoid duplicated reports when multiple CSSFontFaceSource are registered
    // at this FontResource.
    if (!m_fontDataTable.isEmpty())
        m_histograms.loadStarted();
}

void CSSFontFaceSource::fontLoaded(FontResource*)
{
    if (!m_fontDataTable.isEmpty())
        m_histograms.recordRemoteFont(m_font.get());

    pruneTable();
    if (m_face)
        m_face->fontLoaded(this);
}

PassRefPtr<SimpleFontData> CSSFontFaceSource::getFontData(const FontDescription& fontDescription)
{
    // If the font hasn't loaded or an error occurred, then we've got nothing.
    if (!isValid())
        return 0;

    if (isLocal()) {
        // We're local. Just return a SimpleFontData from the normal cache.
        // We don't want to check alternate font family names here, so pass true as the checkingAlternateName parameter.
        RefPtr<SimpleFontData> fontData = FontCache::fontCache()->getFontData(fontDescription, m_string, true);
        m_histograms.recordLocalFont(fontData);
        return fontData;
    }

    // See if we have a mapping in our FontData cache.
    AtomicString emptyFontFamily = "";
    FontCacheKey key = fontDescription.cacheKey(emptyFontFamily);

    RefPtr<SimpleFontData>& fontData = m_fontDataTable.add(key.hash(), 0).iterator->value;
    if (fontData)
        return fontData; // No release, because fontData is a reference to a RefPtr that is held in the m_fontDataTable.

    // If we are still loading, then we let the system pick a font.
    if (isLoaded()) {
        if (m_font) {
#if ENABLE(SVG_FONTS)
            if (m_hasExternalSVGFont) {
                // For SVG fonts parse the external SVG document, and extract the <font> element.
                if (!m_font->ensureSVGFontData())
                    return 0;

                if (!m_externalSVGFontElement) {
                    String fragmentIdentifier;
                    size_t start = m_string.find('#');
                    if (start != kNotFound)
                        fragmentIdentifier = m_string.string().substring(start + 1);
                    m_externalSVGFontElement = m_font->getSVGFontById(fragmentIdentifier);
                }

                if (!m_externalSVGFontElement)
                    return 0;

                SVGFontFaceElement* fontFaceElement = 0;

                // Select first <font-face> child
                for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) {
                    if (fontChild->hasTagName(SVGNames::font_faceTag)) {
                        fontFaceElement = toSVGFontFaceElement(fontChild);
                        break;
                    }
                }

                if (fontFaceElement) {
                    if (!m_svgFontFaceElement) {
                        // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement.
                        // Use the imported <font-face> tag as referencing font-face element for these cases.
                        m_svgFontFaceElement = fontFaceElement;
                    }

                    fontData = SimpleFontData::create(
                        SVGFontData::create(fontFaceElement),
                        fontDescription.effectiveFontSize(),
                        fontDescription.isSyntheticBold(),
                        fontDescription.isSyntheticItalic());
                }
            } else
#endif
            {
                // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef.
                if (!m_font->ensureCustomFontData())
                    return 0;

                fontData = SimpleFontData::create(
                    m_font->platformDataFromCustomData(fontDescription.effectiveFontSize(),
                        fontDescription.isSyntheticBold(), fontDescription.isSyntheticItalic(),
                        fontDescription.orientation(), fontDescription.widthVariant()), CustomFontData::create(false));
            }
        } else {
#if ENABLE(SVG_FONTS)
            // In-Document SVG Fonts
            if (m_svgFontFaceElement) {
                fontData = SimpleFontData::create(
                    SVGFontData::create(m_svgFontFaceElement.get()),
                    fontDescription.effectiveFontSize(),
                    fontDescription.isSyntheticBold(),
                    fontDescription.isSyntheticItalic());
            }
#endif
        }
    } else {
        // This temporary font is not retained and should not be returned.
        FontCachePurgePreventer fontCachePurgePreventer;
        SimpleFontData* temporaryFont = FontCache::fontCache()->getNonRetainedLastResortFallbackFont(fontDescription);
        if (!temporaryFont) {
            ASSERT_NOT_REACHED();
            return 0;
        }
        RefPtr<CSSCustomFontData> cssFontData = CSSCustomFontData::create(true);
        cssFontData->setCSSFontFaceSource(this);
        fontData = SimpleFontData::create(temporaryFont->platformData(), cssFontData);
    }

    return fontData; // No release, because fontData is a reference to a RefPtr that is held in the m_fontDataTable.
}

#if ENABLE(SVG_FONTS)
SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const
{
    return m_svgFontFaceElement.get();
}

void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element)
{
    m_svgFontFaceElement = element;
}

bool CSSFontFaceSource::isSVGFontFaceSource() const
{
    return m_svgFontFaceElement || m_hasExternalSVGFont;
}
#endif

bool CSSFontFaceSource::ensureFontData()
{
    if (!m_font)
        return false;
#if ENABLE(SVG_FONTS)
    if (m_hasExternalSVGFont)
        return m_font->ensureSVGFontData();
#endif
    return m_font->ensureCustomFontData();
}

bool CSSFontFaceSource::isLocalFontAvailable(const FontDescription& fontDescription)
{
    if (!isLocal())
        return false;
    return FontCache::fontCache()->isPlatformFontAvailable(fontDescription, m_string);
}

void CSSFontFaceSource::beginLoadIfNeeded()
{
    if (m_face && m_font)
        m_face->beginLoadIfNeeded(this);
}

void CSSFontFaceSource::FontLoadHistograms::loadStarted()
{
    if (!m_loadStartTime)
        m_loadStartTime = currentTimeMS();
}

void CSSFontFaceSource::FontLoadHistograms::recordLocalFont(bool loadSuccess)
{
    if (!m_loadStartTime) {
        blink::Platform::current()->histogramEnumeration("WebFont.LocalFontUsed", loadSuccess ? 1 : 0, 2);
        m_loadStartTime = -1; // Do not count this font again.
    }
}

void CSSFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResource* font)
{
    if (m_loadStartTime > 0 && font && !font->isLoading()) {
        int duration = static_cast<int>(currentTimeMS() - m_loadStartTime);
        blink::Platform::current()->histogramCustomCounts(histogramName(font), duration, 0, 10000, 50);
        m_loadStartTime = -1;

        enum { Miss, Hit, DataUrl, CacheHitEnumMax };
        int histogramValue = font->url().protocolIsData() ? DataUrl
            : font->response().wasCached() ? Hit
            : Miss;
        blink::Platform::current()->histogramEnumeration("WebFont.CacheHit", histogramValue, CacheHitEnumMax);
    }
}

const char* CSSFontFaceSource::FontLoadHistograms::histogramName(const FontResource* font)
{
    if (font->errorOccurred())
        return "WebFont.DownloadTime.LoadError";

    unsigned size = font->encodedSize();
    if (size < 10 * 1024)
        return "WebFont.DownloadTime.0.Under10KB";
    if (size < 50 * 1024)
        return "WebFont.DownloadTime.1.10KBTo50KB";
    if (size < 100 * 1024)
        return "WebFont.DownloadTime.2.50KBTo100KB";
    if (size < 1024 * 1024)
        return "WebFont.DownloadTime.3.100KBTo1MB";
    return "WebFont.DownloadTime.4.Over1MB";
}

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

#include "config.h"
#include "core/css/CSSFontFaceSource.h"

#include "RuntimeEnabledFeatures.h"
#include "core/css/CSSCustomFontData.h"
#include "core/css/CSSFontFace.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "wtf/CurrentTime.h"

#if ENABLE(SVG_FONTS)
#include "SVGNames.h"
#include "core/svg/SVGFontData.h"
#include "core/svg/SVGFontElement.h"
#include "core/svg/SVGFontFaceElement.h"
#endif

namespace WebCore {

CSSFontFaceSource::CSSFontFaceSource(const String& str, FontResource* font)
    : m_string(str)
    , m_font(font)
    , m_face(0)
#if ENABLE(SVG_FONTS)
    , m_hasExternalSVGFont(false)
#endif
{
    if (m_font)
        m_font->addClient(this);
}

CSSFontFaceSource::~CSSFontFaceSource()
{
    if (m_font)
        m_font->removeClient(this);
    pruneTable();
}

void CSSFontFaceSource::pruneTable()
{
    if (m_fontDataTable.isEmpty())
        return;

    for (FontDataTable::iterator it = m_fontDataTable.begin(); it != m_fontDataTable.end(); ++it) {
        SimpleFontData* fontData = it->value.get();
        if (fontData && fontData->customFontData())
            fontData->customFontData()->clearCSSFontFaceSource();
    }
    m_fontDataTable.clear();
}

bool CSSFontFaceSource::isLocal() const
{
    if (m_font)
        return false;
#if ENABLE(SVG_FONTS)
    if (m_svgFontFaceElement)
        return false;
#endif
    return true;
}

bool CSSFontFaceSource::isLoading() const
{
    if (m_font)
        return !m_font->stillNeedsLoad() && !m_font->isLoaded();
    return false;
}

bool CSSFontFaceSource::isLoaded() const
{
    if (m_font)
        return m_font->isLoaded();
    return true;
}

bool CSSFontFaceSource::isValid() const
{
    if (m_font)
        return !m_font->errorOccurred();
    return true;
}

void CSSFontFaceSource::didStartFontLoad(FontResource*)
{
    // Avoid duplicated reports when multiple CSSFontFaceSource are registered
    // at this FontResource.
    if (!m_fontDataTable.isEmpty())
        m_histograms.loadStarted();
}

void CSSFontFaceSource::fontLoaded(FontResource*)
{
    if (!m_fontDataTable.isEmpty())
        m_histograms.recordRemoteFont(m_font.get());

    pruneTable();
    if (m_face)
        m_face->fontLoaded(this);
}

PassRefPtr<SimpleFontData> CSSFontFaceSource::getFontData(const FontDescription& fontDescription)
{
    // If the font hasn't loaded or an error occurred, then we've got nothing.
    if (!isValid())
        return 0;

    if (isLocal()) {
        // We're local. Just return a SimpleFontData from the normal cache.
        // We don't want to check alternate font family names here, so pass true as the checkingAlternateName parameter.
        RefPtr<SimpleFontData> fontData = FontCache::fontCache()->getFontData(fontDescription, m_string, true);
        m_histograms.recordLocalFont(fontData);
        return fontData;
    }

    // See if we have a mapping in our FontData cache.
    AtomicString emptyFontFamily = "";
    FontCacheKey key = fontDescription.cacheKey(emptyFontFamily);

    RefPtr<SimpleFontData>& fontData = m_fontDataTable.add(key.hash(), 0).iterator->value;
    if (fontData)
        return fontData; // No release, because fontData is a reference to a RefPtr that is held in the m_fontDataTable.

    // If we are still loading, then we let the system pick a font.
    if (isLoaded()) {
        if (m_font) {
#if ENABLE(SVG_FONTS)
            if (m_hasExternalSVGFont) {
                // For SVG fonts parse the external SVG document, and extract the <font> element.
                if (!m_font->ensureSVGFontData())
                    return 0;

                if (!m_externalSVGFontElement) {
                    String fragmentIdentifier;
                    size_t start = m_string.find('#');
                    if (start != kNotFound)
                        fragmentIdentifier = m_string.string().substring(start + 1);
                    m_externalSVGFontElement = m_font->getSVGFontById(fragmentIdentifier);
                }

                if (!m_externalSVGFontElement)
                    return 0;

                SVGFontFaceElement* fontFaceElement = 0;

                // Select first <font-face> child
                for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) {
                    if (fontChild->hasTagName(SVGNames::font_faceTag)) {
                        fontFaceElement = toSVGFontFaceElement(fontChild);
                        break;
                    }
                }

                if (fontFaceElement) {
                    if (!m_svgFontFaceElement) {
                        // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement.
                        // Use the imported <font-face> tag as referencing font-face element for these cases.
                        m_svgFontFaceElement = fontFaceElement;
                    }

                    fontData = SimpleFontData::create(
                        SVGFontData::create(fontFaceElement),
                        fontDescription.effectiveFontSize(),
                        fontDescription.isSyntheticBold(),
                        fontDescription.isSyntheticItalic());
                }
            } else
#endif
            {
                // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef.
                if (!m_font->ensureCustomFontData())
                    return 0;

                fontData = SimpleFontData::create(
                    m_font->platformDataFromCustomData(fontDescription.effectiveFontSize(),
                        fontDescription.isSyntheticBold(), fontDescription.isSyntheticItalic(),
                        fontDescription.orientation(), fontDescription.widthVariant()), CustomFontData::create(false));
            }
        } else {
#if ENABLE(SVG_FONTS)
            // In-Document SVG Fonts
            if (m_svgFontFaceElement) {
                fontData = SimpleFontData::create(
                    SVGFontData::create(m_svgFontFaceElement.get()),
                    fontDescription.effectiveFontSize(),
                    fontDescription.isSyntheticBold(),
                    fontDescription.isSyntheticItalic());
            }
#endif
        }
    } else {
        // This temporary font is not retained and should not be returned.
        FontCachePurgePreventer fontCachePurgePreventer;
        SimpleFontData* temporaryFont = FontCache::fontCache()->getNonRetainedLastResortFallbackFont(fontDescription);
        RefPtr<CSSCustomFontData> cssFontData = CSSCustomFontData::create(true);
        cssFontData->setCSSFontFaceSource(this);
        fontData = SimpleFontData::create(temporaryFont->platformData(), cssFontData);
    }

    return fontData; // No release, because fontData is a reference to a RefPtr that is held in the m_fontDataTable.
}

#if ENABLE(SVG_FONTS)
SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const
{
    return m_svgFontFaceElement.get();
}

void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element)
{
    m_svgFontFaceElement = element;
}

bool CSSFontFaceSource::isSVGFontFaceSource() const
{
    return m_svgFontFaceElement || m_hasExternalSVGFont;
}
#endif

bool CSSFontFaceSource::ensureFontData()
{
    if (!m_font)
        return false;
#if ENABLE(SVG_FONTS)
    if (m_hasExternalSVGFont)
        return m_font->ensureSVGFontData();
#endif
    return m_font->ensureCustomFontData();
}

bool CSSFontFaceSource::isLocalFontAvailable(const FontDescription& fontDescription)
{
    if (!isLocal())
        return false;
    return FontCache::fontCache()->isPlatformFontAvailable(fontDescription, m_string);
}

void CSSFontFaceSource::beginLoadIfNeeded()
{
    if (m_face && m_font)
        m_face->beginLoadIfNeeded(this);
}

void CSSFontFaceSource::FontLoadHistograms::loadStarted()
{
    if (!m_loadStartTime)
        m_loadStartTime = currentTimeMS();
}

void CSSFontFaceSource::FontLoadHistograms::recordLocalFont(bool loadSuccess)
{
    if (!m_loadStartTime) {
        blink::Platform::current()->histogramEnumeration("WebFont.LocalFontUsed", loadSuccess ? 1 : 0, 2);
        m_loadStartTime = -1; // Do not count this font again.
    }
}

void CSSFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResource* font)
{
    if (m_loadStartTime > 0 && font && !font->isLoading()) {
        int duration = static_cast<int>(currentTimeMS() - m_loadStartTime);
        blink::Platform::current()->histogramCustomCounts(histogramName(font), duration, 0, 10000, 50);
        m_loadStartTime = -1;

        enum { Miss, Hit, DataUrl, CacheHitEnumMax };
        int histogramValue = font->url().protocolIsData() ? DataUrl
            : font->response().wasCached() ? Hit
            : Miss;
        blink::Platform::current()->histogramEnumeration("WebFont.CacheHit", histogramValue, CacheHitEnumMax);
    }
}

const char* CSSFontFaceSource::FontLoadHistograms::histogramName(const FontResource* font)
{
    if (font->errorOccurred())
        return "WebFont.DownloadTime.LoadError";

    unsigned size = font->encodedSize();
    if (size < 10 * 1024)
        return "WebFont.DownloadTime.0.Under10KB";
    if (size < 50 * 1024)
        return "WebFont.DownloadTime.1.10KBTo50KB";
    if (size < 100 * 1024)
        return "WebFont.DownloadTime.2.50KBTo100KB";
    if (size < 1024 * 1024)
        return "WebFont.DownloadTime.3.100KBTo1MB";
    return "WebFont.DownloadTime.4.Over1MB";
}

}
<|endoftext|>