<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Markus Berndt

   Interface for the Volumetric Deformation PK.

   <ParameterList name="volumetric deformation">
   <Parameter name="PK model" type="string" value="Prescibed Mesh Deformation"/>
   <Parameter name="Deformation method" type="string" value="method name"/>
   </ParameterList>

   ------------------------------------------------------------------------- */
#include "Teuchos_XMLParameterListHelpers.hpp"

#include "NKAOperator.hh"
#include "composite_vector_function_factory.hh"

#include "volumetric_deformation.hh"
#include "porosity_evaluator.hh"

namespace Amanzi {
namespace Deform {

using namespace Amanzi::AmanziMesh;

RegisteredPKFactory<VolumetricDeformation> VolumetricDeformation::reg_("volumetric deformation");

VolumetricDeformation::VolumetricDeformation(Teuchos::ParameterList& plist,
        const Teuchos::RCP<TreeVector>& solution):
    PKDefaultBase(plist,solution),
    PKPhysicalBase(plist,solution) {
  poro_key_ = plist_.get<std::string>("porosity key","porosity");
}

// -- Setup data
void VolumetricDeformation::setup(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::setup(S);

  // save the meshes
  mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(mesh_);

  if (S->HasMesh("surface")) {
    surf_mesh_ = S->GetMesh("surface");
    surf3d_mesh_ = S->GetMesh("surface_3d");
    surf_mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(surf_mesh_);
    surf3d_mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(surf3d_mesh_);
  }

  // create storage for primary variable, rock volume
  Teuchos::RCP<CompositeVectorFactory> rv_fac =
      S->RequireField(key_, name_);
  rv_fac->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("cell", AmanziMesh::CELL, 1);

  // Create storage and a function for cell volume change
  Teuchos::RCP<CompositeVectorFactory> cv_fac =
      S->RequireField("dcell_volume_dtime", name_);
  cv_fac->Update(*rv_fac);
  Teuchos::ParameterList func_plist = plist_.sublist("deformation function");
  deform_func_ = Functions::CreateCompositeVectorFunction(func_plist, *cv_fac);

  // create storage for the vertex coordinates
  // we need to checkpoint those to be able to create
  // the deformed mesh after restart
  int dim = mesh_->space_dimension();
  S->RequireField("vertex coordinate", name_)->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("node", AmanziMesh::NODE, dim);

  S->RequireFieldEvaluator("cell_volume");
  S->RequireFieldEvaluator("porosity");
  S->RequireField("porosity")->SetMesh(mesh_)->SetGhosted()
      ->AddComponent("cell",AmanziMesh::CELL,1);

  // solve method
  Teuchos::ParameterList op_plist = plist_.sublist("global solve operator");

  // collect a set of the fixed nodes
  std::vector<std::string> bottom_regions;
  if (op_plist.isParameter("bottom region")) {
    bottom_regions.push_back(op_plist.get<std::string>("bottom region"));
  } else {
    bottom_regions =
        op_plist.get<Teuchos::Array<std::string> >("bottom regions").toVector();
  }
  std::string bottom_region_type = op_plist.get<std::string>("bottom region type","node");
  std::set<AmanziMesh::Entity_ID> bottom_node_set;
  for (std::vector<std::string>::const_iterator region=bottom_regions.begin();
       region!=bottom_regions.end(); ++region) {
    if (bottom_region_type == "node") {
      AmanziMesh::Entity_ID_List region_nodes;
      mesh_->get_set_entities(*region, AmanziMesh::NODE, AmanziMesh::OWNED,&region_nodes);
      bottom_node_set.insert(region_nodes.begin(), region_nodes.end());
    } else if (bottom_region_type == "face") {
      AmanziMesh::Entity_ID_List region_faces;
      mesh_->get_set_entities(*region, AmanziMesh::FACE, AmanziMesh::OWNED,&region_faces);
      for (AmanziMesh::Entity_ID_List::const_iterator f=region_faces.begin();
           f!=region_faces.end(); ++f) {
        AmanziMesh::Entity_ID_List face_nodes;
        mesh_->face_get_nodes(*f, &face_nodes);
        bottom_node_set.insert(face_nodes.begin(), face_nodes.end());
      }
    } else {
      Errors::Message mesg("Invalid bottom region type (must be node or face)");
      Exceptions::amanzi_throw(mesg);
    }
  }

  // create the unique list of owned bottom nodes
  unsigned int nnodes_owned = mesh_->num_entities(AmanziMesh::NODE, AmanziMesh::OWNED);
  Teuchos::RCP<AmanziMesh::Entity_ID_List> bottom_node_list =
      Teuchos::rcp(new AmanziMesh::Entity_ID_List());
  for (std::set<AmanziMesh::Entity_ID>::const_iterator n=bottom_node_set.begin();
       n!=bottom_node_set.end(); ++n) {
    if (*n < nnodes_owned) bottom_node_list->push_back(*n);
  }

  // create the operator
  def_matrix_ = Teuchos::rcp(new Operators::MatrixVolumetricDeformation(op_plist,
          mesh_, bottom_node_list));

  if (op_plist.isSublist("NKA Solver")) {
    Teuchos::ParameterList solver_plist = op_plist.sublist("NKA Solver");
    operator_ = Teuchos::rcp(
        new NKAOperator<CompositeMatrix,CompositeVector,
                        CompositeVectorFactory>(solver_plist,def_matrix_));
  } else {
    operator_ = def_matrix_;
  }

  // create storage for the nodal deformation
  S->RequireField("nodal_dz", name_)->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("node", AmanziMesh::NODE, 1);
}

// -- Initialize owned (dependent) variables.
void VolumetricDeformation::initialize(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::initialize(S);

  // the PK's initial condition sets the initial porosity.  From this, we
  // calculate the actual initial condition, which is the rock volume.
  Epetra_MultiVector& rock_vol = *S->GetFieldData(key_,name_)
      ->ViewComponent("cell",false);
  int ncells = rock_vol.MyLength();
  for (int c=0; c!=ncells; ++c) {
    rock_vol[0][c] = (1.0 - rock_vol[0][c]) * mesh_->cell_volume(c);
  }

  // initialize the deformation rate to 0
  S->GetFieldData("dcell_volume_dtime",name_)->PutScalar(0.);
  S->GetField("dcell_volume_dtime",name_)->set_initialized();

  // initialize the plane displacement to be zero
  S->GetFieldData("nodal_dz",name_)->PutScalar(0.);
  S->GetField("nodal_dz",name_)->set_initialized();

  { // initialize the vertex coordinate to the current mesh
    int dim = mesh_->space_dimension();
    AmanziGeometry::Point coords;
    coords.init(dim);
    int nnodes = mesh_->num_entities(Amanzi::AmanziMesh::NODE,
            Amanzi::AmanziMesh::OWNED);

    Epetra_MultiVector& vc = *S->GetFieldData("vertex coordinate",name_)
        ->ViewComponent("node",false);

    // search the id of the mid point on the top
    for (int iV=0; iV!=nnodes; ++iV) {
      // get the coords of the node
      mesh_->node_get_coordinates(iV,&coords);
      for (int s=0; s!=dim; ++s) vc[s][iV] = coords[s];
    }
  }
  S->GetField("vertex coordinate",name_)->set_initialized();
}

bool VolumetricDeformation::advance(double dt) {
  Teuchos::OSTab tab = getOSTab();
  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_MEDIUM, true)) {
    *out_ << "Advancing deformation PK from time " << S_->time() << " to "
          << S_next_->time() << " with step size " << dt << std::endl;
    *out_ << "----------------------------------------------------------------" << std::endl;
  }

  double ss = S_next_->time();
  double ss0 = S_->time();
  double dT = ss - ss0;
  double T_mid = (ss + ss0) / 2.;

  const Epetra_MultiVector& cv = *S_->GetFieldData("cell_volume")
      ->ViewComponent("cell",false);
  const Epetra_MultiVector& poro = *S_->GetFieldData(poro_key_)
      ->ViewComponent("cell",false);

  // Evaluate the function at the mean time to get d(cv)/dT
  Teuchos::RCP<CompositeVector> dcell_vol_vec =
      S_next_->GetFieldData("dcell_volume_dtime", name_);
  dcell_vol_vec->PutScalar(0.);
  deform_func_->Compute(T_mid, dcell_vol_vec.ptr());

  { // scale by cell volume, this is fractional loss
    Epetra_MultiVector& dcell_vol_c = *dcell_vol_vec->ViewComponent("cell",false);
    for (int c=0; c!=dcell_vol_c.MyLength(); ++c) {
      dcell_vol_c[0][c] *= cv[0][c] * dT;
    }
  }

  // calculate the nodal deformation
  Teuchos::RCP<CompositeVector> nodal_dz_vec =
      S_next_->GetFieldData("nodal_dz",name_);
  Teuchos::RCP<CompositeVector> rhs = Teuchos::rcp(new CompositeVector(*nodal_dz_vec));
  def_matrix_->ApplyRHS(*dcell_vol_vec, rhs.ptr());
  operator_->ApplyInverse(*rhs, nodal_dz_vec.ptr());

  // form list of deformed nodes
  Entity_ID_List nodeids;
  AmanziGeometry::Point_List newpos;
  Amanzi::AmanziGeometry::Point coords, new_coords;
  int dim = mesh_->space_dimension();
  new_coords.init(dim);

  nodal_dz_vec->ScatterMasterToGhosted("node",true);

  // WORKAROUND for non-communication in deform() by Mesh
  //  const Epetra_MultiVector& nodal_dz_l =
  //      *nodal_dz_vec->ViewComponent("node",false);
  const Epetra_MultiVector& nodal_dz_l =
      *nodal_dz_vec->ViewComponent("node",true);

  int nnodes = nodal_dz_l.MyLength();
  for (int i=0; i!=nnodes; ++i) {
    nodeids.push_back(i);
    mesh_->node_get_coordinates(i,&coords);
    new_coords = coords;
    new_coords[2] += nodal_dz_l[0][i];
    newpos.push_back(new_coords);
  }

  // deform the mesh
  AmanziGeometry::Point_List finpos;
  mesh_nc_->deform(nodeids, newpos, false, &finpos);

  if (surf_mesh_ != Teuchos::null) {
    // now we have to adapt the surface mesh to the new volume mesh
    // extract the correct new coordinates for the surface from the domain
    // mesh and update the surface mesh accordingly

    // WORKAROUND for non-communication in deform() by Mesh
    //    int nsurfnodes = surf_mesh_->num_entities(Amanzi::AmanziMesh::NODE,
    //            Amanzi::AmanziMesh::OWNED);
    int nsurfnodes = surf_mesh_->num_entities(Amanzi::AmanziMesh::NODE,
            Amanzi::AmanziMesh::USED);
    AmanziGeometry::Point coord_domain(dim);
    AmanziGeometry::Point coord_surface(dim-1);

    Entity_ID_List surface_nodeids, surface3d_nodeids;
    AmanziGeometry::Point_List surface_newpos, surface3d_newpos;

    for (int i=0; i!=nsurfnodes; ++i) {
      // get the coords of the node
      AmanziGeometry::Point coord(3);
      AmanziMesh::Entity_ID pnode =
          surf_mesh_->entity_get_parent(AmanziMesh::NODE, i);
      mesh_->node_get_coordinates(i, &coord_domain);

      // surface points are two dimensional
      for (int s=0; s!=dim-1; ++s) coord_surface[s] = coord_domain[s];
      surface_nodeids.push_back(i);
      surface_newpos.push_back(coord_surface);

      surface3d_nodeids.push_back(i);
      surface3d_newpos.push_back(coord_domain);
    }

    // now deform the surface meshes, note that we set the keep_valid
    // flag to false, since we want the surface mesh to exactly mirror
    // the domain mesh
    AmanziGeometry::Point_List surface_finpos;
    surf_mesh_nc_->deform(surface_nodeids, surface_newpos, false, &surface_finpos);
    surf3d_mesh_nc_->deform(surface3d_nodeids, surface3d_newpos, false, &surface_finpos);
  }

  {  // update vertex coordinates in state (for checkpointing)
    Epetra_MultiVector& vc = *S_next_->GetFieldData("vertex coordinate",name_)
        ->ViewComponent("node",false);
    int nnodes = vc.MyLength();
    for (int i=0; i!=nnodes; ++i) {
      mesh_->node_get_coordinates(i,&coords);
      for (int s=0; s!=dim; ++s) vc[s][i] = coords[s];
    }
  }

  // setting deformation to be rock_volume at old time, (1-poro_old)*CV_old
  {
    Epetra_MultiVector& def = *S_next_->GetFieldData(key_,name_)
        ->ViewComponent("cell",false);

    int ncells = def.MyLength();
    for (int c=0; c!=ncells; ++c) {
      def[0][c] = (1. - poro[0][c]) * cv[0][c];
    }
  }

  // mark the placeholder evaluator as changed
  solution_evaluator_->SetFieldAsChanged(S_next_.ptr());

  // REMOVE ME --etc
  // update porosity and cell volumes
  S_next_->GetFieldEvaluator("cell_volume")
      ->HasFieldChanged(S_next_.ptr(), name_);
  S_next_->GetFieldEvaluator("porosity")
      ->HasFieldChanged(S_next_.ptr(), name_);

  return false;
}

} // namespace
} // namespace
<commit_msg>bug fix in volumetric deformation as applied to surface meshes, get correct node id<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Markus Berndt

   Interface for the Volumetric Deformation PK.

   <ParameterList name="volumetric deformation">
   <Parameter name="PK model" type="string" value="Prescibed Mesh Deformation"/>
   <Parameter name="Deformation method" type="string" value="method name"/>
   </ParameterList>

   ------------------------------------------------------------------------- */
#include "Teuchos_XMLParameterListHelpers.hpp"

#include "NKAOperator.hh"
#include "composite_vector_function_factory.hh"

#include "volumetric_deformation.hh"
#include "porosity_evaluator.hh"

namespace Amanzi {
namespace Deform {

using namespace Amanzi::AmanziMesh;

RegisteredPKFactory<VolumetricDeformation> VolumetricDeformation::reg_("volumetric deformation");

VolumetricDeformation::VolumetricDeformation(Teuchos::ParameterList& plist,
        const Teuchos::RCP<TreeVector>& solution):
    PKDefaultBase(plist,solution),
    PKPhysicalBase(plist,solution) {
  poro_key_ = plist_.get<std::string>("porosity key","porosity");
}

// -- Setup data
void VolumetricDeformation::setup(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::setup(S);

  // save the meshes
  mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(mesh_);

  if (S->HasMesh("surface")) {
    surf_mesh_ = S->GetMesh("surface");
    surf3d_mesh_ = S->GetMesh("surface_3d");
    surf_mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(surf_mesh_);
    surf3d_mesh_nc_ = Teuchos::rcp_const_cast<AmanziMesh::Mesh>(surf3d_mesh_);
  }

  // create storage for primary variable, rock volume
  Teuchos::RCP<CompositeVectorFactory> rv_fac =
      S->RequireField(key_, name_);
  rv_fac->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("cell", AmanziMesh::CELL, 1);

  // Create storage and a function for cell volume change
  Teuchos::RCP<CompositeVectorFactory> cv_fac =
      S->RequireField("dcell_volume_dtime", name_);
  cv_fac->Update(*rv_fac);
  Teuchos::ParameterList func_plist = plist_.sublist("deformation function");
  deform_func_ = Functions::CreateCompositeVectorFunction(func_plist, *cv_fac);

  // create storage for the vertex coordinates
  // we need to checkpoint those to be able to create
  // the deformed mesh after restart
  int dim = mesh_->space_dimension();
  S->RequireField("vertex coordinate", name_)->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("node", AmanziMesh::NODE, dim);

  S->RequireFieldEvaluator("cell_volume");
  S->RequireFieldEvaluator("porosity");
  S->RequireField("porosity")->SetMesh(mesh_)->SetGhosted()
      ->AddComponent("cell",AmanziMesh::CELL,1);

  // solve method
  Teuchos::ParameterList op_plist = plist_.sublist("global solve operator");

  // collect a set of the fixed nodes
  std::vector<std::string> bottom_regions;
  if (op_plist.isParameter("bottom region")) {
    bottom_regions.push_back(op_plist.get<std::string>("bottom region"));
  } else {
    bottom_regions =
        op_plist.get<Teuchos::Array<std::string> >("bottom regions").toVector();
  }
  std::string bottom_region_type = op_plist.get<std::string>("bottom region type","node");
  std::set<AmanziMesh::Entity_ID> bottom_node_set;
  for (std::vector<std::string>::const_iterator region=bottom_regions.begin();
       region!=bottom_regions.end(); ++region) {
    if (bottom_region_type == "node") {
      AmanziMesh::Entity_ID_List region_nodes;
      mesh_->get_set_entities(*region, AmanziMesh::NODE, AmanziMesh::OWNED,&region_nodes);
      bottom_node_set.insert(region_nodes.begin(), region_nodes.end());
    } else if (bottom_region_type == "face") {
      AmanziMesh::Entity_ID_List region_faces;
      mesh_->get_set_entities(*region, AmanziMesh::FACE, AmanziMesh::OWNED,&region_faces);
      for (AmanziMesh::Entity_ID_List::const_iterator f=region_faces.begin();
           f!=region_faces.end(); ++f) {
        AmanziMesh::Entity_ID_List face_nodes;
        mesh_->face_get_nodes(*f, &face_nodes);
        bottom_node_set.insert(face_nodes.begin(), face_nodes.end());
      }
    } else {
      Errors::Message mesg("Invalid bottom region type (must be node or face)");
      Exceptions::amanzi_throw(mesg);
    }
  }

  // create the unique list of owned bottom nodes
  unsigned int nnodes_owned = mesh_->num_entities(AmanziMesh::NODE, AmanziMesh::OWNED);
  Teuchos::RCP<AmanziMesh::Entity_ID_List> bottom_node_list =
      Teuchos::rcp(new AmanziMesh::Entity_ID_List());
  for (std::set<AmanziMesh::Entity_ID>::const_iterator n=bottom_node_set.begin();
       n!=bottom_node_set.end(); ++n) {
    if (*n < nnodes_owned) bottom_node_list->push_back(*n);
  }

  // create the operator
  def_matrix_ = Teuchos::rcp(new Operators::MatrixVolumetricDeformation(op_plist,
          mesh_, bottom_node_list));

  if (op_plist.isSublist("NKA Solver")) {
    Teuchos::ParameterList solver_plist = op_plist.sublist("NKA Solver");
    operator_ = Teuchos::rcp(
        new NKAOperator<CompositeMatrix,CompositeVector,
                        CompositeVectorFactory>(solver_plist,def_matrix_));
  } else {
    operator_ = def_matrix_;
  }

  // create storage for the nodal deformation
  S->RequireField("nodal_dz", name_)->SetMesh(mesh_)->SetGhosted()
      ->SetComponent("node", AmanziMesh::NODE, 1);
}

// -- Initialize owned (dependent) variables.
void VolumetricDeformation::initialize(const Teuchos::Ptr<State>& S) {
  PKPhysicalBase::initialize(S);

  // the PK's initial condition sets the initial porosity.  From this, we
  // calculate the actual initial condition, which is the rock volume.
  Epetra_MultiVector& rock_vol = *S->GetFieldData(key_,name_)
      ->ViewComponent("cell",false);
  int ncells = rock_vol.MyLength();
  for (int c=0; c!=ncells; ++c) {
    rock_vol[0][c] = (1.0 - rock_vol[0][c]) * mesh_->cell_volume(c);
  }

  // initialize the deformation rate to 0
  S->GetFieldData("dcell_volume_dtime",name_)->PutScalar(0.);
  S->GetField("dcell_volume_dtime",name_)->set_initialized();

  // initialize the plane displacement to be zero
  S->GetFieldData("nodal_dz",name_)->PutScalar(0.);
  S->GetField("nodal_dz",name_)->set_initialized();

  { // initialize the vertex coordinate to the current mesh
    int dim = mesh_->space_dimension();
    AmanziGeometry::Point coords;
    coords.init(dim);
    int nnodes = mesh_->num_entities(Amanzi::AmanziMesh::NODE,
            Amanzi::AmanziMesh::OWNED);

    Epetra_MultiVector& vc = *S->GetFieldData("vertex coordinate",name_)
        ->ViewComponent("node",false);

    // search the id of the mid point on the top
    for (int iV=0; iV!=nnodes; ++iV) {
      // get the coords of the node
      mesh_->node_get_coordinates(iV,&coords);
      for (int s=0; s!=dim; ++s) vc[s][iV] = coords[s];
    }
  }
  S->GetField("vertex coordinate",name_)->set_initialized();
}

bool VolumetricDeformation::advance(double dt) {
  Teuchos::OSTab tab = getOSTab();
  if (out_.get() && includesVerbLevel(verbosity_, Teuchos::VERB_MEDIUM, true)) {
    *out_ << "Advancing deformation PK from time " << S_->time() << " to "
          << S_next_->time() << " with step size " << dt << std::endl;
    *out_ << "----------------------------------------------------------------" << std::endl;
  }

  double ss = S_next_->time();
  double ss0 = S_->time();
  double dT = ss - ss0;
  double T_mid = (ss + ss0) / 2.;

  const Epetra_MultiVector& cv = *S_->GetFieldData("cell_volume")
      ->ViewComponent("cell",false);
  const Epetra_MultiVector& poro = *S_->GetFieldData(poro_key_)
      ->ViewComponent("cell",false);

  // Evaluate the function at the mean time to get d(cv)/dT
  Teuchos::RCP<CompositeVector> dcell_vol_vec =
      S_next_->GetFieldData("dcell_volume_dtime", name_);
  dcell_vol_vec->PutScalar(0.);
  deform_func_->Compute(T_mid, dcell_vol_vec.ptr());

  { // scale by cell volume, this is fractional loss
    Epetra_MultiVector& dcell_vol_c = *dcell_vol_vec->ViewComponent("cell",false);
    for (int c=0; c!=dcell_vol_c.MyLength(); ++c) {
      dcell_vol_c[0][c] *= cv[0][c] * dT;
    }
  }

  // calculate the nodal deformation
  Teuchos::RCP<CompositeVector> nodal_dz_vec =
      S_next_->GetFieldData("nodal_dz",name_);
  Teuchos::RCP<CompositeVector> rhs = Teuchos::rcp(new CompositeVector(*nodal_dz_vec));
  def_matrix_->ApplyRHS(*dcell_vol_vec, rhs.ptr());
  operator_->ApplyInverse(*rhs, nodal_dz_vec.ptr());

  // form list of deformed nodes
  Entity_ID_List nodeids;
  AmanziGeometry::Point_List newpos;
  Amanzi::AmanziGeometry::Point coords, new_coords;
  int dim = mesh_->space_dimension();
  new_coords.init(dim);

  nodal_dz_vec->ScatterMasterToGhosted("node",true);

  // WORKAROUND for non-communication in deform() by Mesh
  //  const Epetra_MultiVector& nodal_dz_l =
  //      *nodal_dz_vec->ViewComponent("node",false);
  const Epetra_MultiVector& nodal_dz_l =
      *nodal_dz_vec->ViewComponent("node",true);

  int nnodes = nodal_dz_l.MyLength();
  for (int i=0; i!=nnodes; ++i) {
    nodeids.push_back(i);
    mesh_->node_get_coordinates(i,&coords);
    new_coords = coords;
    new_coords[2] += nodal_dz_l[0][i];
    newpos.push_back(new_coords);
  }

  // deform the mesh
  AmanziGeometry::Point_List finpos;
  mesh_nc_->deform(nodeids, newpos, false, &finpos);

  if (surf_mesh_ != Teuchos::null) {
    // now we have to adapt the surface mesh to the new volume mesh
    // extract the correct new coordinates for the surface from the domain
    // mesh and update the surface mesh accordingly

    // WORKAROUND for non-communication in deform() by Mesh
    //    int nsurfnodes = surf_mesh_->num_entities(Amanzi::AmanziMesh::NODE,
    //            Amanzi::AmanziMesh::OWNED);
    int nsurfnodes = surf_mesh_->num_entities(AmanziMesh::NODE,
            AmanziMesh::USED);

    Entity_ID_List surface_nodeids, surface3d_nodeids;
    AmanziGeometry::Point_List surface_newpos, surface3d_newpos;

    for (int i=0; i!=nsurfnodes; ++i) {
      // get the coords of the node
      AmanziMesh::Entity_ID pnode =
          surf_mesh_->entity_get_parent(AmanziMesh::NODE, i);
      AmanziGeometry::Point coord_domain(dim);
      mesh_->node_get_coordinates(pnode, &coord_domain);

      surface3d_nodeids.push_back(i);
      surface3d_newpos.push_back(coord_domain);

      // surface points are two dimensional
      AmanziGeometry::Point coord_surface(dim-1);
      for (int s=0; s!=dim-1; ++s) coord_surface[s] = coord_domain[s];
      surface_nodeids.push_back(i);
      surface_newpos.push_back(coord_surface);
    }
    AmanziGeometry::Point_List surface_finpos;
    surf_mesh_nc_->deform(surface_nodeids, surface_newpos, false, &surface_finpos);
    surf3d_mesh_nc_->deform(surface3d_nodeids, surface3d_newpos, false, &surface_finpos);
  }

  {  // update vertex coordinates in state (for checkpointing)
    Epetra_MultiVector& vc = *S_next_->GetFieldData("vertex coordinate",name_)
        ->ViewComponent("node",false);
    int nnodes = vc.MyLength();
    for (int i=0; i!=nnodes; ++i) {
      mesh_->node_get_coordinates(i,&coords);
      for (int s=0; s!=dim; ++s) vc[s][i] = coords[s];
    }
  }

  // setting deformation to be rock_volume at old time, (1-poro_old)*CV_old
  {
    Epetra_MultiVector& def = *S_next_->GetFieldData(key_,name_)
        ->ViewComponent("cell",false);

    int ncells = def.MyLength();
    for (int c=0; c!=ncells; ++c) {
      def[0][c] = (1. - poro[0][c]) * cv[0][c];
    }
  }

  // mark the placeholder evaluator as changed
  solution_evaluator_->SetFieldAsChanged(S_next_.ptr());

  // REMOVE ME --etc
  // update porosity and cell volumes
  S_next_->GetFieldEvaluator("cell_volume")
      ->HasFieldChanged(S_next_.ptr(), name_);
  S_next_->GetFieldEvaluator("porosity")
      ->HasFieldChanged(S_next_.ptr(), name_);

  return false;
}

} // namespace
} // namespace
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmltextgenerator.h"

#include <QVariant>
#include <QColor>

#include "bindingproperty.h"
#include "signalhandlerproperty.h"
#include "nodeproperty.h"
#include "nodelistproperty.h"
#include "variantproperty.h"
#include <nodemetainfo.h>
#include "model.h"

using namespace QmlDesigner;
using namespace QmlDesigner::Internal;

inline static QString properColorName(const QColor &color)
{
    QString s;
    if (color.alpha() == 255)
        s.sprintf("#%02x%02x%02x", color.red(), color.green(), color.blue());
    else
        s.sprintf("#%02x%02x%02x%02x", color.alpha(), color.red(), color.green(), color.blue());
    return s;
}

inline static QString doubleToString(double d)
{
    QString string = QString::number(d, 'f', 3);
    if (string.contains(QLatin1Char('.'))) {
        while (string.at(string.length()- 1) == QLatin1Char('0'))
            string.chop(1);
        if (string.at(string.length()- 1) == QLatin1Char('.'))
            string.chop(1);
    }
    return string;
}

QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth):
        m_propertyOrder(propertyOrder),
        m_indentDepth(indentDepth)
{
}

QString QmlTextGenerator::toQml(const AbstractProperty &property, int indentDepth) const
{
    if (property.isBindingProperty()) {
        return property.toBindingProperty().expression();
    } else if (property.isSignalHandlerProperty()) {
        return property.toSignalHandlerProperty().source();
    } else if (property.isNodeProperty()) {
        return toQml(property.toNodeProperty().modelNode(), indentDepth);
    } else if (property.isNodeListProperty()) {
        const QList<ModelNode> nodes = property.toNodeListProperty().toModelNodeList();
        if (property.isDefaultProperty()) {
            QString result;
            for (int i = 0; i < nodes.length(); ++i) {
                if (i > 0)
                    result += QLatin1String("\n\n");
                result += QString(indentDepth, QLatin1Char(' '));
                result += toQml(nodes.at(i), indentDepth);
            }
            return result;
        } else {
            QString result = QLatin1String("[");
            const int arrayContentDepth = indentDepth + 4;
            const QString arrayContentIndentation(arrayContentDepth, QLatin1Char(' '));
            for (int i = 0; i < nodes.length(); ++i) {
                if (i > 0)
                    result += QLatin1Char(',');
                result += QLatin1Char('\n');
                result += arrayContentIndentation;
                result += toQml(nodes.at(i), arrayContentDepth);
            }
            return result + QLatin1Char(']');
        }
    } else if (property.isVariantProperty()) {
        const VariantProperty variantProperty = property.toVariantProperty();
        const QVariant value = variantProperty.value();
        const QString stringValue = value.toString();

        if (property.name() == "id")
            return stringValue;

          if (false) {
          }
        if (variantProperty.holdsEnumeration()) {
            return variantProperty.enumeration().toString();
        } else {

            switch (value.type()) {
            case QVariant::Bool:
                if (value.value<bool>())
                    return QLatin1String("true");
                else
                    return QLatin1String("false");

            case QVariant::Color:
                return QString(QLatin1String("\"%1\"")).arg(properColorName(value.value<QColor>()));

            case QVariant::Double:
                return doubleToString(value.toDouble());
            case QVariant::Int:
            case QVariant::LongLong:
            case QVariant::UInt:
            case QVariant::ULongLong:
                return stringValue;

            default:
                return QString(QLatin1String("\"%1\"")).arg(escape(stringValue));
            }
        }
    } else {
        Q_ASSERT("Unknown property type");
        return QString();
    }
}

QString QmlTextGenerator::toQml(const ModelNode &node, int indentDepth) const
{
    QString type = node.type();
    QString url;
    if (type.contains('.')) {
        QStringList nameComponents = type.split('.');
        url = nameComponents.first();
        type = nameComponents.last();
    }

    QString alias;
    if (!url.isEmpty()) {
        foreach (const Import &import, node.model()->imports()) {
            if (import.url() == url) {
                alias = import.alias();
                break;
            }
            if (import.file() == url) {
                alias = import.alias();
                break;
            }
        }
    }

    QString result;

    if (!alias.isEmpty())
        result = alias + '.';

    result += type;
    result += QLatin1String(" {\n");

    const int propertyIndentDepth = indentDepth + 4;

    const QString properties = propertiesToQml(node, propertyIndentDepth);

    return result + properties + QString(indentDepth, QLatin1Char(' ')) + QLatin1Char('}');
}

QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth) const
{
    QString topPart;
    QString bottomPart;

    PropertyNameList nodePropertyNames = node.propertyNames();
    bool addToTop = true;

    foreach (const PropertyName &propertyName, m_propertyOrder) {
        if (propertyName == "id") {
            // the model handles the id property special, so:
            if (!node.id().isEmpty()) {
                QString idLine(indentDepth, QLatin1Char(' '));
                idLine += QLatin1String("id: ");
                idLine += node.id();
                idLine += QLatin1Char('\n');

                if (addToTop)
                    topPart.append(idLine);
                else
                    bottomPart.append(idLine);
            }
        } else if (propertyName.isEmpty()) {
            addToTop = false;
        } else if (nodePropertyNames.removeAll(propertyName)) {
            const QString newContent = propertyToQml(node.property(propertyName), indentDepth);

            if (addToTop)
                topPart.append(newContent);
            else
                bottomPart.append(newContent);
        }
    }

    foreach (const PropertyName &propertyName, nodePropertyNames) {
        bottomPart.prepend(propertyToQml(node.property(propertyName), indentDepth));
    }

    return topPart + bottomPart;
}

QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int indentDepth) const
{
    QString result;

    if (property.isDefaultProperty()) {
        result = toQml(property, indentDepth);
    } else {
        if (property.isDynamic()) {
            result = QString(indentDepth, QLatin1Char(' '))
                    + QLatin1String("property ")
                    + property.dynamicTypeName()
                    + QLatin1String(" ")
                    + property.name()
                    + QLatin1String(": ")
                    + toQml(property, indentDepth);
        } else {
            result = QString(indentDepth, QLatin1Char(' ')) + property.name() + QLatin1String(": ") + toQml(property, indentDepth);
        }
    }

    result += QLatin1Char('\n');

    return result;
}

QString QmlTextGenerator::escape(const QString &value)
{
    QString result = value;

    result.replace(QLatin1String("\\"), QLatin1String("\\\\"));

    result.replace(QLatin1String("\""), QLatin1String("\\\""));
    result.replace(QLatin1String("\t"), QLatin1String("\\t"));
    result.replace(QLatin1String("\r"), QLatin1String("\\r"));
    result.replace(QLatin1String("\n"), QLatin1String("\\n"));

    return result;
}
<commit_msg>QmlDesigner.Rewriter: Support for float type in QVariant<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmltextgenerator.h"

#include <QVariant>
#include <QColor>

#include "bindingproperty.h"
#include "signalhandlerproperty.h"
#include "nodeproperty.h"
#include "nodelistproperty.h"
#include "variantproperty.h"
#include <nodemetainfo.h>
#include "model.h"

using namespace QmlDesigner;
using namespace QmlDesigner::Internal;

inline static QString properColorName(const QColor &color)
{
    QString s;
    if (color.alpha() == 255)
        s.sprintf("#%02x%02x%02x", color.red(), color.green(), color.blue());
    else
        s.sprintf("#%02x%02x%02x%02x", color.alpha(), color.red(), color.green(), color.blue());
    return s;
}

inline static QString doubleToString(double d)
{
    QString string = QString::number(d, 'f', 3);
    if (string.contains(QLatin1Char('.'))) {
        while (string.at(string.length()- 1) == QLatin1Char('0'))
            string.chop(1);
        if (string.at(string.length()- 1) == QLatin1Char('.'))
            string.chop(1);
    }
    return string;
}

QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, int indentDepth):
        m_propertyOrder(propertyOrder),
        m_indentDepth(indentDepth)
{
}

QString QmlTextGenerator::toQml(const AbstractProperty &property, int indentDepth) const
{
    if (property.isBindingProperty()) {
        return property.toBindingProperty().expression();
    } else if (property.isSignalHandlerProperty()) {
        return property.toSignalHandlerProperty().source();
    } else if (property.isNodeProperty()) {
        return toQml(property.toNodeProperty().modelNode(), indentDepth);
    } else if (property.isNodeListProperty()) {
        const QList<ModelNode> nodes = property.toNodeListProperty().toModelNodeList();
        if (property.isDefaultProperty()) {
            QString result;
            for (int i = 0; i < nodes.length(); ++i) {
                if (i > 0)
                    result += QLatin1String("\n\n");
                result += QString(indentDepth, QLatin1Char(' '));
                result += toQml(nodes.at(i), indentDepth);
            }
            return result;
        } else {
            QString result = QLatin1String("[");
            const int arrayContentDepth = indentDepth + 4;
            const QString arrayContentIndentation(arrayContentDepth, QLatin1Char(' '));
            for (int i = 0; i < nodes.length(); ++i) {
                if (i > 0)
                    result += QLatin1Char(',');
                result += QLatin1Char('\n');
                result += arrayContentIndentation;
                result += toQml(nodes.at(i), arrayContentDepth);
            }
            return result + QLatin1Char(']');
        }
    } else if (property.isVariantProperty()) {
        const VariantProperty variantProperty = property.toVariantProperty();
        const QVariant value = variantProperty.value();
        const QString stringValue = value.toString();

        if (property.name() == "id")
            return stringValue;

          if (false) {
          }
        if (variantProperty.holdsEnumeration()) {
            return variantProperty.enumeration().toString();
        } else {

            switch (value.type()) {
            case QVariant::Bool:
                if (value.value<bool>())
                    return QLatin1String("true");
                else
                    return QLatin1String("false");

            case QVariant::Color:
                return QString(QLatin1String("\"%1\"")).arg(properColorName(value.value<QColor>()));

            case QMetaType::Float:
            case QVariant::Double:
                return doubleToString(value.toDouble());
            case QVariant::Int:
            case QVariant::LongLong:
            case QVariant::UInt:
            case QVariant::ULongLong:
                return stringValue;

            default:
                return QString(QLatin1String("\"%1\"")).arg(escape(stringValue));
            }
        }
    } else {
        Q_ASSERT("Unknown property type");
        return QString();
    }
}

QString QmlTextGenerator::toQml(const ModelNode &node, int indentDepth) const
{
    QString type = node.type();
    QString url;
    if (type.contains('.')) {
        QStringList nameComponents = type.split('.');
        url = nameComponents.first();
        type = nameComponents.last();
    }

    QString alias;
    if (!url.isEmpty()) {
        foreach (const Import &import, node.model()->imports()) {
            if (import.url() == url) {
                alias = import.alias();
                break;
            }
            if (import.file() == url) {
                alias = import.alias();
                break;
            }
        }
    }

    QString result;

    if (!alias.isEmpty())
        result = alias + '.';

    result += type;
    result += QLatin1String(" {\n");

    const int propertyIndentDepth = indentDepth + 4;

    const QString properties = propertiesToQml(node, propertyIndentDepth);

    return result + properties + QString(indentDepth, QLatin1Char(' ')) + QLatin1Char('}');
}

QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth) const
{
    QString topPart;
    QString bottomPart;

    PropertyNameList nodePropertyNames = node.propertyNames();
    bool addToTop = true;

    foreach (const PropertyName &propertyName, m_propertyOrder) {
        if (propertyName == "id") {
            // the model handles the id property special, so:
            if (!node.id().isEmpty()) {
                QString idLine(indentDepth, QLatin1Char(' '));
                idLine += QLatin1String("id: ");
                idLine += node.id();
                idLine += QLatin1Char('\n');

                if (addToTop)
                    topPart.append(idLine);
                else
                    bottomPart.append(idLine);
            }
        } else if (propertyName.isEmpty()) {
            addToTop = false;
        } else if (nodePropertyNames.removeAll(propertyName)) {
            const QString newContent = propertyToQml(node.property(propertyName), indentDepth);

            if (addToTop)
                topPart.append(newContent);
            else
                bottomPart.append(newContent);
        }
    }

    foreach (const PropertyName &propertyName, nodePropertyNames) {
        bottomPart.prepend(propertyToQml(node.property(propertyName), indentDepth));
    }

    return topPart + bottomPart;
}

QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int indentDepth) const
{
    QString result;

    if (property.isDefaultProperty()) {
        result = toQml(property, indentDepth);
    } else {
        if (property.isDynamic()) {
            result = QString(indentDepth, QLatin1Char(' '))
                    + QLatin1String("property ")
                    + property.dynamicTypeName()
                    + QLatin1String(" ")
                    + property.name()
                    + QLatin1String(": ")
                    + toQml(property, indentDepth);
        } else {
            result = QString(indentDepth, QLatin1Char(' ')) + property.name() + QLatin1String(": ") + toQml(property, indentDepth);
        }
    }

    result += QLatin1Char('\n');

    return result;
}

QString QmlTextGenerator::escape(const QString &value)
{
    QString result = value;

    result.replace(QLatin1String("\\"), QLatin1String("\\\\"));

    result.replace(QLatin1String("\""), QLatin1String("\\\""));
    result.replace(QLatin1String("\t"), QLatin1String("\\t"));
    result.replace(QLatin1String("\r"), QLatin1String("\\r"));
    result.replace(QLatin1String("\n"), QLatin1String("\\n"));

    return result;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006, 2007 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 <windows.h>

#include "Font.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
#include "SimpleFontData.h"
#include "UniscribeStateTextRun.h"

#include "base/gfx/platform_canvas_win.h"
#include "base/gfx/skia_utils.h"
#include "graphics/SkiaUtils.h"
#include "webkit/glue/webkit_glue.h"

namespace WebCore {

void Font::drawGlyphs(GraphicsContext* graphicsContext,
                      const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,
                      int from,
                      int numGlyphs,
                      const FloatPoint& point) const
{
    PlatformGraphicsContext* context = graphicsContext->platformContext();

    // Max buffer length passed to the underlying windows API.
    const int kMaxBufferLength = 1024;
    // Default size for the buffer. It should be enough for most of cases.
    const int kDefaultBufferLength = 256;

    SkColor color = context->fillColor();
    unsigned char alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha)
        return;

    // Set up our graphics context.
    HDC hdc = context->canvas()->beginPlatformPaint();
    HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());

    // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
    // Enforce non-transparent color.
    color = SkColorSetRGB(SkColorGetR(color),
                          SkColorGetG(color),
                          SkColorGetB(color));
    SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
    SetBkMode(hdc, TRANSPARENT);

    // Windows needs the characters and the advances in nice contiguous
    // buffers, which we build here.
    Vector<WORD, kDefaultBufferLength> glyphs;
    Vector<int, kDefaultBufferLength> advances;

    // We draw the glyphs in chunks to avoid having to do a heap allocation for
    // the arrays of characters and advances. Since ExtTextOut is the
    // lowest-level text output function on Windows, there should be little
    // penalty for splitting up the text. On the other hand, the buffer cannot
    // be bigger than 4094 or the function will fail.
    int glyphIndex = 0;
    int chunkX = 0;  // x offset of this span from the point
    while (glyphIndex < numGlyphs) {
        // how many chars will be in this chunk?
        int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);

        glyphs.resize(curLen);
        advances.resize(curLen);

        int curWidth = 0;
        for (int i = 0; i < curLen; ++i, ++glyphIndex) {
            glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
            advances[i] =
                static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
            curWidth += advances[i];
        }

        SkPoint origin2 = point;
        origin2.fX += chunkX;

        bool success = false;
        for (int executions = 0; executions < 2; ++executions) {
            // The 'origin' represents the baseline, so we need to move it up
            // to the top of the bounding square by subtracting the ascent
            success = !!ExtTextOut(hdc, static_cast<int>(origin2.fX),
                                   static_cast<int>(origin2.fY) - ascent(),
                                   ETO_GLYPH_INDEX, NULL,
                                   reinterpret_cast<const wchar_t*>(&glyphs[0]),
                                   curLen,
                                   &advances[0]);

            if (!success && executions == 0) {
                // Ask the browser to load the font for us and retry.
                webkit_glue::EnsureFontLoaded(font->platformData().hfont());
                continue;
            }
            break;
        }

        ASSERT(success);

        chunkX += curWidth;
    }

    SelectObject(hdc, oldFont);
    context->canvas()->endPlatformPaint();
}

FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const IntPoint& point,
                                            int h,
                                            int from,
                                            int to) const
{
    UniscribeStateTextRun state(run, *this);
    float left = static_cast<float>(point.x() + state.CharacterToX(from));
    float right = static_cast<float>(point.x() + state.CharacterToX(to));

    // If the text is RTL, left will actually be after right.
    if (left < right) {
      return FloatRect(left, static_cast<float>(point.y()),
                       right - left, static_cast<float>(h));
    }
    return FloatRect(right, static_cast<float>(point.y()),
                     left - right, static_cast<float>(h));
}

void Font::drawComplexText(GraphicsContext* graphicsContext,
                           const TextRun& run,
                           const FloatPoint& point,
                           int from,
                           int to) const
{
    PlatformGraphicsContext* context = graphicsContext->platformContext();
    UniscribeStateTextRun state(run, *this);

    SkColor color = context->fillColor();
    uint8 alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha)
        return;

    HDC hdc = context->canvas()->beginPlatformPaint();

    // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
    // Enforce non-transparent color.
    color = SkColorSetRGB(SkColorGetR(color),
                          SkColorGetG(color),
                          SkColorGetB(color));
    SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
    SetBkMode(hdc, TRANSPARENT);

    // Uniscribe counts the coordinates from the upper left, while WebKit uses
    // the baseline, so we have to subtract off the ascent.
    state.Draw(hdc,
               static_cast<int>(point.x()),
               static_cast<int>(point.y() - ascent()),
               from,
               to);
    context->canvas()->endPlatformPaint();
}

float Font::floatWidthForComplexText(const TextRun& run) const
{
    UniscribeStateTextRun state(run, *this);
    return static_cast<float>(state.Width());
}

int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
{
    // Mac code ignores includePartialGlyphs, and they don't know what it's
    // supposed to do, so we just ignore it as well.
    UniscribeStateTextRun state(run, *this);
    int char_index = state.XToCharacter(x);

    // XToCharacter will return -1 if the position is before the first
    // character (we get called like this sometimes).
    if (char_index < 0)
      char_index = 0;
    return char_index;
}

} // namespace WebCore
<commit_msg>Fix font regression. I was using ascent() instead of font->ascent(), which I think doesn't take into account fallback fonts and small caps, so those characters would be incorrectly vertically aligned. This also fixes an old bug I noticed where if the run is more than 1024 pixels, it will start being drawn over itself since we never used the updated x coordinate. Review URL: http://codereview.chromium.org/9206<commit_after>/*
 * Copyright (C) 2006, 2007 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 <windows.h>

#include "Font.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
#include "SimpleFontData.h"
#include "UniscribeStateTextRun.h"

#include "base/gfx/platform_canvas_win.h"
#include "base/gfx/skia_utils.h"
#include "graphics/SkiaUtils.h"
#include "webkit/glue/webkit_glue.h"

namespace WebCore {

void Font::drawGlyphs(GraphicsContext* graphicsContext,
                      const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,
                      int from,
                      int numGlyphs,
                      const FloatPoint& point) const
{
    PlatformGraphicsContext* context = graphicsContext->platformContext();

    // Max buffer length passed to the underlying windows API.
    const int kMaxBufferLength = 1024;
    // Default size for the buffer. It should be enough for most of cases.
    const int kDefaultBufferLength = 256;

    SkColor color = context->fillColor();
    unsigned char alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha)
        return;

    // Set up our graphics context.
    HDC hdc = context->canvas()->beginPlatformPaint();
    HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());

    // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
    // Enforce non-transparent color.
    color = SkColorSetRGB(SkColorGetR(color),
                          SkColorGetG(color),
                          SkColorGetB(color));
    SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
    SetBkMode(hdc, TRANSPARENT);

    // Windows needs the characters and the advances in nice contiguous
    // buffers, which we build here.
    Vector<WORD, kDefaultBufferLength> glyphs;
    Vector<int, kDefaultBufferLength> advances;

    // Compute the coordinate. The 'origin' represents the baseline, so we need
    // to move it up to the top of the bounding square.
    int x = static_cast<int>(point.x());
    int lineTop = static_cast<int>(point.y()) - font->ascent();

    // We draw the glyphs in chunks to avoid having to do a heap allocation for
    // the arrays of characters and advances. Since ExtTextOut is the
    // lowest-level text output function on Windows, there should be little
    // penalty for splitting up the text. On the other hand, the buffer cannot
    // be bigger than 4094 or the function will fail.
    int glyphIndex = 0;
    while (glyphIndex < numGlyphs) {
        // how many chars will be in this chunk?
        int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);

        glyphs.resize(curLen);
        advances.resize(curLen);

        int curWidth = 0;
        for (int i = 0; i < curLen; ++i, ++glyphIndex) {
            glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
            advances[i] =
                static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
            curWidth += advances[i];
        }

        bool success = false;
        for (int executions = 0; executions < 2; ++executions) {
            success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, NULL,
                                   reinterpret_cast<const wchar_t*>(&glyphs[0]),
                                   curLen,
                                   &advances[0]);

            if (!success && executions == 0) {
                // Ask the browser to load the font for us and retry.
                webkit_glue::EnsureFontLoaded(font->platformData().hfont());
                continue;
            }
            break;
        }

        ASSERT(success);

        x += curWidth;
    }

    SelectObject(hdc, oldFont);
    context->canvas()->endPlatformPaint();
}

FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const IntPoint& point,
                                            int h,
                                            int from,
                                            int to) const
{
    UniscribeStateTextRun state(run, *this);
    float left = static_cast<float>(point.x() + state.CharacterToX(from));
    float right = static_cast<float>(point.x() + state.CharacterToX(to));

    // If the text is RTL, left will actually be after right.
    if (left < right) {
      return FloatRect(left, static_cast<float>(point.y()),
                       right - left, static_cast<float>(h));
    }
    return FloatRect(right, static_cast<float>(point.y()),
                     left - right, static_cast<float>(h));
}

void Font::drawComplexText(GraphicsContext* graphicsContext,
                           const TextRun& run,
                           const FloatPoint& point,
                           int from,
                           int to) const
{
    PlatformGraphicsContext* context = graphicsContext->platformContext();
    UniscribeStateTextRun state(run, *this);

    SkColor color = context->fillColor();
    uint8 alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha)
        return;

    HDC hdc = context->canvas()->beginPlatformPaint();

    // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
    // Enforce non-transparent color.
    color = SkColorSetRGB(SkColorGetR(color),
                          SkColorGetG(color),
                          SkColorGetB(color));
    SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
    SetBkMode(hdc, TRANSPARENT);

    // Uniscribe counts the coordinates from the upper left, while WebKit uses
    // the baseline, so we have to subtract off the ascent.
    state.Draw(hdc,
               static_cast<int>(point.x()),
               static_cast<int>(point.y() - ascent()),
               from,
               to);
    context->canvas()->endPlatformPaint();
}

float Font::floatWidthForComplexText(const TextRun& run) const
{
    UniscribeStateTextRun state(run, *this);
    return static_cast<float>(state.Width());
}

int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
{
    // Mac code ignores includePartialGlyphs, and they don't know what it's
    // supposed to do, so we just ignore it as well.
    UniscribeStateTextRun state(run, *this);
    int char_index = state.XToCharacter(x);

    // XToCharacter will return -1 if the position is before the first
    // character (we get called like this sometimes).
    if (char_index < 0)
      char_index = 0;
    return char_index;
}

} // namespace WebCore
<|endoftext|>


<commit_before><commit_msg>GTK test shell valgrind, try 3. Null out the main window before initiating shutdown.<commit_after><|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of QMime
**
** Based on Qt Creator source code
**
** Qt Creator Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
**************************************************************************/

#include "qmimemagicrule.h"

#include <QtCore/QList>
#include <qendian.h>

QT_BEGIN_NAMESPACE

// in the same order as Type!
static const char magicRuleTypes_string[] =
    "invalid\0"
    "string\0"
    "host16\0"
    "host32\0"
    "big16\0"
    "big32\0"
    "little16\0"
    "little32\0"
    "byte\0"
    "\0";

static const int magicRuleTypes_indices[] = {
    0, 8, 15, 22, 29, 35, 41, 50, 59, 65, 0
};

QMimeMagicRule::Type QMimeMagicRule::type(const QByteArray &type)
{
    for (int i = String; i <= Byte; ++i) {
        if (type == magicRuleTypes_string + magicRuleTypes_indices[i])
            return static_cast<Type>(i);
    }
    return Invalid;
}

QByteArray QMimeMagicRule::typeName(QMimeMagicRule::Type type)
{
    return magicRuleTypes_string + magicRuleTypes_indices[type];
}

struct QMimeMagicRulePrivate
{
    QMimeMagicRule::Type type;
    QByteArray value;
    int startPos;
    int endPos;
    QByteArray mask;

    QByteArray pattern;
    quint32 number;
    quint32 numberMask;

    typedef bool (*MatchFunction)(QMimeMagicRulePrivate *d, const QByteArray &data);
    MatchFunction matchFunction;
};

static bool matchString(QMimeMagicRulePrivate *d, const QByteArray &data)
{
    const char *p = data.constData() + d->startPos;
    const char *e = p + qMin(data.size() - d->pattern.size(), d->endPos);
    for ( ; p <= e; ++p) {
        int i = 0;
        while (i < d->pattern.size() && (p[i] & d->mask.at(i)) == d->pattern.at(i))
            ++i;
        if (i == d->pattern.size())
            return true;
    }

    return false;
}

template <typename T>
static bool matchNumber(QMimeMagicRulePrivate *d, const QByteArray &data)
{
    const T value(d->number);
    const T mask(d->numberMask);

    const char *p = data.constData() + d->startPos;
    const char *e = p + qMin(data.size() - int(sizeof(T)), d->endPos);
    for ( ; p <= e; ++p) {
        if ((*reinterpret_cast<const T*>(p) & mask) == value)
            return true;
    }

    return false;
}

static inline QByteArray makePattern(const QByteArray &value)
{
    QByteArray pattern(value.size(), Qt::Uninitialized);
    char *data = pattern.data();

    const char *p = value.constData();
    const char *e = p + value.size();
    for ( ; p < e; ++p) {
        if (*p == '\\' && ++p < e) {
            if (*p == 'x') { // hex (\\xff)
                char c = 0;
                for (int i = 0; i < 2 && p + 1 < e; ++i) {
                    ++p;
                    if (*p >= '0' && *p <= '9')
                        c = (c << 4) + *p - '0';
                    else if (*p >= 'a' && *p <= 'f')
                        c = (c << 4) + *p - 'a' + 10;
                    else if (*p >= 'A' && *p <= 'F')
                        c = (c << 4) + *p - 'A' + 10;
                    else
                        continue;
                }
                *data++ = c;
            } else if (*p >= '0' && *p <= '7') { // oct (\\7, or \\77, or \\377)
                char c = *p - '0';
                if (p + 1 < e && p[1] >= '0' && p[1] <= '7') {
                    c = (c << 3) + *(++p) - '0';
                    if (p + 1 < e && p[1] >= '0' && p[1] <= '7' && p[-1] <= '3')
                        c = (c << 3) + *(++p) - '0';
                }
                *data++ = c;
            } else { // escaped
                *data++ = *p;
            }
        } else {
            *data++ = *p;
        }
    }
    pattern.truncate(data - pattern.data());

    return pattern;
}

QMimeMagicRule::QMimeMagicRule(QMimeMagicRule::Type type, const QByteArray &value, int startPos, int endPos, const QByteArray &mask)
    : d(new QMimeMagicRulePrivate)
{
    Q_ASSERT(!value.isEmpty());

    d->type = type;
    d->value = value;
    d->startPos = startPos;
    d->endPos = endPos;
    d->mask = mask;
    d->matchFunction = 0;

    if (d->type >= Host16 && d->type <= Byte) {
        bool ok;
        d->number = d->value.toUInt(&ok, 0); // autodetect
        Q_ASSERT(ok);
        d->numberMask = !d->mask.isEmpty() ? d->mask.toUInt(&ok, 0) : 0; // autodetect
    }

    switch (d->type) {
    case String:
        d->pattern = makePattern(d->value);
        d->pattern.squeeze();
        if (!d->mask.isEmpty()) {
            Q_ASSERT(d->mask.size() >= 4 && d->mask.startsWith("0x"));
            d->mask = QByteArray::fromHex(QByteArray::fromRawData(d->mask.constData() + 2, d->mask.size() - 2));
            Q_ASSERT(d->mask.size() == d->pattern.size());

            // apply mask to pattern
            const char *m = d->mask.constData();
            char *p = d->pattern.data();
            const char *e = p + d->pattern.size();
            while (p < e)
                *p++ &= *m++;
        } else {
            d->mask.fill(0xff, d->pattern.size());
        }
        d->mask.squeeze();
        d->matchFunction = matchString;
        break;
    case Byte:
        if (d->number <= quint8(-1)) {
            if (d->numberMask == 0)
                d->numberMask = quint8(-1);
            d->matchFunction = matchNumber<quint8>;
        }
        break;
    case Big16:
    case Host16:
    case Little16:
        if (d->number <= quint16(-1)) {
            d->number = d->type == Little16 ? qFromLittleEndian<quint16>(d->number) : qFromBigEndian<quint16>(d->number);
            if (d->numberMask == 0)
                d->numberMask = quint16(-1);
            d->matchFunction = matchNumber<quint16>;
        }
        break;
    case Big32:
    case Host32:
    case Little32:
        if (d->number <= quint32(-1)) {
            d->number = d->type == Little32 ? qFromLittleEndian<quint32>(d->number) : qFromBigEndian<quint32>(d->number);
            if (d->numberMask == 0)
                d->numberMask = quint32(-1);
            d->matchFunction = matchNumber<quint32>;
        }
        break;
    default:
        break;
    }
}

QMimeMagicRule::QMimeMagicRule(const QMimeMagicRule &other)
    : d(new QMimeMagicRulePrivate(*other.d))
{
}

QMimeMagicRule::~QMimeMagicRule()
{
}

QMimeMagicRule& QMimeMagicRule::operator=(const QMimeMagicRule &other)
{
    *d = *other.d;
    return *this;
}

QMimeMagicRule::Type QMimeMagicRule::type() const
{
    return d->type;
}

QByteArray QMimeMagicRule::value() const
{
    return d->value;
}

int QMimeMagicRule::startPos() const
{
    return d->startPos;
}

int QMimeMagicRule::endPos() const
{
    return d->endPos;
}

QByteArray QMimeMagicRule::mask() const
{
    QByteArray mask = d->mask;
    if (d->type == String) {
        // restore '0x'
        mask = "0x" + mask.toHex();
    }
    return mask;
}

bool QMimeMagicRule::isValid() const
{
    return d->matchFunction;
}

bool QMimeMagicRule::matches(const QByteArray &data) const
{
    return d->matchFunction && d->matchFunction(d.data(), data);
}

QT_END_NAMESPACE
<commit_msg>fix stupid bug<commit_after>/**************************************************************************
**
** This file is part of QMime
**
** Based on Qt Creator source code
**
** Qt Creator Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
**************************************************************************/

#include "qmimemagicrule.h"

#include <QtCore/QList>
#include <qendian.h>

QT_BEGIN_NAMESPACE

// in the same order as Type!
static const char magicRuleTypes_string[] =
    "invalid\0"
    "string\0"
    "host16\0"
    "host32\0"
    "big16\0"
    "big32\0"
    "little16\0"
    "little32\0"
    "byte\0"
    "\0";

static const int magicRuleTypes_indices[] = {
    0, 8, 15, 22, 29, 35, 41, 50, 59, 65, 0
};

QMimeMagicRule::Type QMimeMagicRule::type(const QByteArray &type)
{
    for (int i = String; i <= Byte; ++i) {
        if (type == magicRuleTypes_string + magicRuleTypes_indices[i])
            return static_cast<Type>(i);
    }
    return Invalid;
}

QByteArray QMimeMagicRule::typeName(QMimeMagicRule::Type type)
{
    return magicRuleTypes_string + magicRuleTypes_indices[type];
}

struct QMimeMagicRulePrivate
{
    QMimeMagicRule::Type type;
    QByteArray value;
    int startPos;
    int endPos;
    QByteArray mask;

    QByteArray pattern;
    quint32 number;
    quint32 numberMask;

    typedef bool (*MatchFunction)(QMimeMagicRulePrivate *d, const QByteArray &data);
    MatchFunction matchFunction;
};

static bool matchString(QMimeMagicRulePrivate *d, const QByteArray &data)
{
    const char *p = data.constData() + d->startPos;
    const char *e = data.constData() + qMin(data.size() - d->pattern.size(), d->endPos + 1);
    for ( ; p < e; ++p) {
        int i = 0;
        while (i < d->pattern.size() && (p[i] & d->mask.at(i)) == d->pattern.at(i))
            ++i;
        if (i == d->pattern.size())
            return true;
    }

    return false;
}

template <typename T>
static bool matchNumber(QMimeMagicRulePrivate *d, const QByteArray &data)
{
    const T value(d->number);
    const T mask(d->numberMask);

    const char *p = data.constData() + d->startPos;
    const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), d->endPos + 1);
    for ( ; p < e; ++p) {
        if ((*reinterpret_cast<const T*>(p) & mask) == value)
            return true;
    }

    return false;
}

static inline QByteArray makePattern(const QByteArray &value)
{
    QByteArray pattern(value.size(), Qt::Uninitialized);
    char *data = pattern.data();

    const char *p = value.constData();
    const char *e = p + value.size();
    for ( ; p < e; ++p) {
        if (*p == '\\' && ++p < e) {
            if (*p == 'x') { // hex (\\xff)
                char c = 0;
                for (int i = 0; i < 2 && p + 1 < e; ++i) {
                    ++p;
                    if (*p >= '0' && *p <= '9')
                        c = (c << 4) + *p - '0';
                    else if (*p >= 'a' && *p <= 'f')
                        c = (c << 4) + *p - 'a' + 10;
                    else if (*p >= 'A' && *p <= 'F')
                        c = (c << 4) + *p - 'A' + 10;
                    else
                        continue;
                }
                *data++ = c;
            } else if (*p >= '0' && *p <= '7') { // oct (\\7, or \\77, or \\377)
                char c = *p - '0';
                if (p + 1 < e && p[1] >= '0' && p[1] <= '7') {
                    c = (c << 3) + *(++p) - '0';
                    if (p + 1 < e && p[1] >= '0' && p[1] <= '7' && p[-1] <= '3')
                        c = (c << 3) + *(++p) - '0';
                }
                *data++ = c;
            } else { // escaped
                *data++ = *p;
            }
        } else {
            *data++ = *p;
        }
    }
    pattern.truncate(data - pattern.data());

    return pattern;
}

QMimeMagicRule::QMimeMagicRule(QMimeMagicRule::Type type, const QByteArray &value, int startPos, int endPos, const QByteArray &mask)
    : d(new QMimeMagicRulePrivate)
{
    Q_ASSERT(!value.isEmpty());

    d->type = type;
    d->value = value;
    d->startPos = startPos;
    d->endPos = endPos;
    d->mask = mask;
    d->matchFunction = 0;

    if (d->type >= Host16 && d->type <= Byte) {
        bool ok;
        d->number = d->value.toUInt(&ok, 0); // autodetect
        Q_ASSERT(ok);
        d->numberMask = !d->mask.isEmpty() ? d->mask.toUInt(&ok, 0) : 0; // autodetect
    }

    switch (d->type) {
    case String:
        d->pattern = makePattern(d->value);
        d->pattern.squeeze();
        if (!d->mask.isEmpty()) {
            Q_ASSERT(d->mask.size() >= 4 && d->mask.startsWith("0x"));
            d->mask = QByteArray::fromHex(QByteArray::fromRawData(d->mask.constData() + 2, d->mask.size() - 2));
            Q_ASSERT(d->mask.size() == d->pattern.size());

            // apply mask to pattern
            const char *m = d->mask.constData();
            char *p = d->pattern.data();
            const char *e = p + d->pattern.size();
            while (p < e)
                *p++ &= *m++;
        } else {
            d->mask.fill(0xff, d->pattern.size());
        }
        d->mask.squeeze();
        d->matchFunction = matchString;
        break;
    case Byte:
        if (d->number <= quint8(-1)) {
            if (d->numberMask == 0)
                d->numberMask = quint8(-1);
            d->matchFunction = matchNumber<quint8>;
        }
        break;
    case Big16:
    case Host16:
    case Little16:
        if (d->number <= quint16(-1)) {
            d->number = d->type == Little16 ? qFromLittleEndian<quint16>(d->number) : qFromBigEndian<quint16>(d->number);
            if (d->numberMask == 0)
                d->numberMask = quint16(-1);
            d->matchFunction = matchNumber<quint16>;
        }
        break;
    case Big32:
    case Host32:
    case Little32:
        if (d->number <= quint32(-1)) {
            d->number = d->type == Little32 ? qFromLittleEndian<quint32>(d->number) : qFromBigEndian<quint32>(d->number);
            if (d->numberMask == 0)
                d->numberMask = quint32(-1);
            d->matchFunction = matchNumber<quint32>;
        }
        break;
    default:
        break;
    }
}

QMimeMagicRule::QMimeMagicRule(const QMimeMagicRule &other)
    : d(new QMimeMagicRulePrivate(*other.d))
{
}

QMimeMagicRule::~QMimeMagicRule()
{
}

QMimeMagicRule& QMimeMagicRule::operator=(const QMimeMagicRule &other)
{
    *d = *other.d;
    return *this;
}

QMimeMagicRule::Type QMimeMagicRule::type() const
{
    return d->type;
}

QByteArray QMimeMagicRule::value() const
{
    return d->value;
}

int QMimeMagicRule::startPos() const
{
    return d->startPos;
}

int QMimeMagicRule::endPos() const
{
    return d->endPos;
}

QByteArray QMimeMagicRule::mask() const
{
    QByteArray mask = d->mask;
    if (d->type == String) {
        // restore '0x'
        mask = "0x" + mask.toHex();
    }
    return mask;
}

bool QMimeMagicRule::isValid() const
{
    return d->matchFunction;
}

bool QMimeMagicRule::matches(const QByteArray &data) const
{
    return d->matchFunction && d->matchFunction(d.data(), data);
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © ") + tr("2009-%1 The Bitcoin developers").arg(COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<commit_msg>aboutdialog: use just "The Bitcoin developers" as tr()-string<commit_after>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers"));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<|endoftext|>