<commit_before>#include "base/all.h"
#include "rpc/client.h"
#include "rpc/server.h"
#include "benchmark_service.h"

using namespace base;
using namespace std;
using namespace rpc;
using namespace benchmark;

TEST(future, wait_timeout) {
    PollMgr* poll = new PollMgr;
    ThreadPool* thrpool = new ThreadPool;

    // start the server
    int svc_port = find_open_port();
    EXPECT_NEQ(svc_port, -1);
    Server* svr = new Server(poll, thrpool);
    BenchmarkService bench_svc;
    svr->reg(&bench_svc);
    char svc_addr[100];
    sprintf(svc_addr, "127.0.0.1:%d", svc_port);
    svr->start(svc_addr);

    // start the client
    ClientPool* clnt_pool = new ClientPool(poll);
    BenchmarkProxy* clnt = new BenchmarkProxy(clnt_pool->get_client(svc_addr));

    Log::debug("do wait");
    Timer t;
    t.start();
    FutureAttr fu_attr;
    fu_attr.callback = [] (Future* fu) {
        Log::debug("fu->get_error_code() = %d", fu->get_error_code());
    };
    Future* fu = clnt->async_sleep(2.3, fu_attr);
    double wait_sec = 1.0;
    fu->timed_wait(wait_sec);
    t.stop();
    Log::debug("done wait: %lf seconds", t.elapsed());
    EXPECT_LT(fabs(wait_sec - t.elapsed()), 0.1);

    delete clnt;
    delete clnt_pool;
    delete svr;

    thrpool->release();
    poll->release();
}
<commit_msg>work around unittest failure<commit_after>#include "base/all.h"
#include "rpc/client.h"
#include "rpc/server.h"
#include "benchmark_service.h"

using namespace base;
using namespace std;
using namespace rpc;
using namespace benchmark;

TEST(future, wait_timeout) {
    PollMgr* poll = new PollMgr;
    ThreadPool* thrpool = new ThreadPool;

    // start the server
    int svc_port = find_open_port();
    EXPECT_NEQ(svc_port, -1);
    Server* svr = new Server(poll, thrpool);
    BenchmarkService bench_svc;
    svr->reg(&bench_svc);
    char svc_addr[100];
    sprintf(svc_addr, "127.0.0.1:%d", svc_port);
    svr->start(svc_addr);

    // start the client
    ClientPool* clnt_pool = new ClientPool(poll);
    BenchmarkProxy* clnt = new BenchmarkProxy(clnt_pool->get_client(svc_addr));

    Log::debug("do wait");
    Timer t;
    t.start();
    FutureAttr fu_attr;
    fu_attr.callback = [] (Future* fu) {
        Log::debug("fu->get_error_code() = %d", fu->get_error_code());
    };
    Future* fu = clnt->async_sleep(2.3, fu_attr);
    double wait_sec = 1.0;
    fu->timed_wait(wait_sec);
    t.stop();
    Log::debug("done wait: %lf seconds", t.elapsed());
    EXPECT_LT(fabs(wait_sec - t.elapsed()), 0.1);

    delete clnt;
    delete clnt_pool;

    thrpool->release();
    poll->release();

    delete svr;
}
<|endoftext|>


<commit_before>#include "av500.hpp"

Plugin *plugin;

void init(rack::Plugin *p) {
	plugin = p;
	p->slug = "av500";
#ifdef VERSION
	p->version = TOSTRING(VERSION);
#endif
	p->addModel(createModel<MultipleWidget>    ("av500", "av500", "Multiple", "Multiple"));
	p->addModel(createModel<Blank8hpWidget>    ("av500", "av500", "Blank", "8hp Blank"));
	p->addModel(createModel<p0wrWidget>        ("av500", "av500", "Power", "p0wr"));
	p->addModel(createModel<TR808CowbellWidget>("av500", "av500", "Drum", "808Cowbell"));
}

//plugin->homepageUrl = "https://github.com/av500/vcvrackplugins_av500";
<commit_msg>make it work with 0.5.0<commit_after>#include "av500.hpp"

Plugin *plugin;

void init(rack::Plugin *p) {
	plugin = p;
	p->slug = "av500";
#ifdef VERSION
	p->version = TOSTRING(VERSION);
#endif
	p->addModel(createModel<MultipleWidget>    ("av500", "Multiple", "Multiple", MULTIPLE_TAG));
	p->addModel(createModel<Blank8hpWidget>    ("av500", "Blank", "8hp Blank", BLANK_TAG));
	p->addModel(createModel<p0wrWidget>        ("av500", "Power", "p0wr", VISUAL_TAG));
	p->addModel(createModel<TR808CowbellWidget>("av500", "Drum", "808Cowbell", DRUM_TAG));
}

//plugin->homepageUrl = "https://github.com/av500/vcvrackplugins_av500";
<|endoftext|>


<commit_before>#include <vtkSmartPointer.h>
#include <vtkCellIterator.h>
#include <vtkGenericDataSet.h>
#include <vtkGenericCell.h>
#include <vtkXMLGenericDataObjectReader.h>
#include <vtkPointSet.h>
#include <vtkCellTypes.h>

#include <map>

int main (int argc, char *argv[])
{
  std::map<std::string, int> cellMap;

  for (int arg = 1; arg < argc; ++arg)
  {
    vtkSmartPointer<vtkXMLGenericDataObjectReader> reader =
      vtkSmartPointer<vtkXMLGenericDataObjectReader>::New();
    reader->SetFileName(argv[arg]);
    reader->Update();

    vtkPointSet *pointSet = vtkPointSet::SafeDownCast(reader->GetOutput());
    vtkCellIterator *it = pointSet->NewCellIterator();
    for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell())
    {
      vtkSmartPointer<vtkGenericCell> cell =
        vtkSmartPointer<vtkGenericCell>::New();
      it->GetCell(cell);
      std::string cellName = vtkCellTypes::GetClassNameFromTypeId(cell->GetCellType());
      if (cellMap.count(cellName) == 0)
      {
        int numFaces = cell->GetNumberOfFaces();
        std::cout << "Type: " << cellName
                  << " has " << cell->GetNumberOfFaces() << " faces" << std::endl;
      }
      cellMap[cellName]++;
    }
}
  std::map <std::string, int>::iterator itm = cellMap.begin();

  for (itm = cellMap.begin(); itm != cellMap.end(); ++itm)
  {
    std::cout << itm->first << " occurs " << itm->second << " times" << std::endl;
  }

  return EXIT_SUCCESS;
}
<commit_msg>BUG: Fixed memory leak<commit_after>#include <vtkSmartPointer.h>
#include <vtkCellIterator.h>
#include <vtkGenericDataSet.h>
#include <vtkGenericCell.h>
#include <vtkXMLGenericDataObjectReader.h>
#include <vtkPointSet.h>
#include <vtkCellTypes.h>

#include <map>

int main (int argc, char *argv[])
{
  std::map<std::string, int> cellMap;

  for (int arg = 1; arg < argc; ++arg)
  {
    vtkSmartPointer<vtkXMLGenericDataObjectReader> reader =
      vtkSmartPointer<vtkXMLGenericDataObjectReader>::New();
    reader->SetFileName(argv[arg]);
    reader->Update();

    vtkPointSet *pointSet = vtkPointSet::SafeDownCast(reader->GetOutput());
    vtkCellIterator *it = pointSet->NewCellIterator();
    for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell())
    {
      vtkSmartPointer<vtkGenericCell> cell =
        vtkSmartPointer<vtkGenericCell>::New();
      it->GetCell(cell);
      std::string cellName = vtkCellTypes::GetClassNameFromTypeId(cell->GetCellType());
      if (cellMap.count(cellName) == 0)
      {
        std::cout << "Type: " << cellName
                  << " has " << cell->GetNumberOfFaces() << " faces" << std::endl;
      }
      cellMap[cellName]++;
    }
    it->Delete();
  }

  std::map <std::string, int>::iterator itm = cellMap.begin();
  for (itm = cellMap.begin(); itm != cellMap.end(); ++itm)
  {
    std::cout << itm->first << " occurs " << itm->second << " times" << std::endl;
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


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

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/util/trim.hpp>

// stl
#include <stdexcept>

// boost
// fusion
#include <boost/fusion/include/adapt_adt.hpp>
// spirit
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>

// agg
#include "agg_trans_affine.h"

BOOST_FUSION_ADAPT_TPL_ADT(
    (T),
    (mapnik::box2d)(T),
    (T, T, obj.minx(), obj.set_minx(val))
    (T, T, obj.miny(), obj.set_miny(val))
    (T, T, obj.maxx(), obj.set_maxx(val))
    (T, T, obj.maxy(), obj.set_maxy(val)))

namespace mapnik
{
template <typename T>
box2d<T>::box2d()
    :minx_(0),miny_(0),maxx_(-1),maxy_(-1) {}

template <typename T>
box2d<T>::box2d(T minx,T miny,T maxx,T maxy)
{
    init(minx,miny,maxx,maxy);
}

template <typename T>
box2d<T>::box2d(const coord<T,2> &c0,const coord<T,2> &c1)
{
    init(c0.x,c0.y,c1.x,c1.y);
}

template <typename T>
box2d<T>::box2d(const box2d &rhs)
    : minx_(rhs.minx_),
      miny_(rhs.miny_),
      maxx_(rhs.maxx_),
      maxy_(rhs.maxy_) {}

template <typename T>
box2d<T>::box2d(box2d_type const& rhs, const agg::trans_affine& tr)
{
    double x0 = rhs.minx_, y0 = rhs.miny_;
    double x1 = rhs.maxx_, y1 = rhs.miny_;
    double x2 = rhs.maxx_, y2 = rhs.maxy_;
    double x3 = rhs.minx_, y3 = rhs.maxy_;
    tr.transform(&x0, &y0);
    tr.transform(&x1, &y1);
    tr.transform(&x2, &y2);
    tr.transform(&x3, &y3);
    init(static_cast<T>(x0), static_cast<T>(y0),
         static_cast<T>(x2), static_cast<T>(y2));
    expand_to_include(static_cast<T>(x1), static_cast<T>(y1));
    expand_to_include(static_cast<T>(x3), static_cast<T>(y3));
}

template <typename T>
bool box2d<T>::operator==(const box2d<T>& other) const
{
    return minx_==other.minx_ &&
        miny_==other.miny_ &&
        maxx_==other.maxx_ &&
        maxy_==other.maxy_;
}

template <typename T>
T box2d<T>::minx() const
{
    return minx_;
}

template <typename T>
T box2d<T>::maxx() const
{
    return maxx_;
}

template <typename T>
T box2d<T>::miny() const
{
    return miny_;
}

template <typename T>
T box2d<T>::maxy() const
{
    return maxy_;
}

template<typename T>
void box2d<T>::set_minx(T v)
{
    minx_ = v;
}

template<typename T>
void box2d<T>::set_miny(T v)
{
    miny_ = v;
}

template<typename T>
void box2d<T>::set_maxx(T v)
{
    maxx_ = v;
}

template<typename T>
void box2d<T>::set_maxy(T v)
{
    maxy_ = v;
}

template <typename T>
T box2d<T>::width() const
{
    return maxx_-minx_;
}

template <typename T>
T box2d<T>::height() const
{
    return maxy_-miny_;
}

template <typename T>
void box2d<T>::width(T w)
{
    T cx=center().x;
    minx_=static_cast<T>(cx-w*0.5);
    maxx_=static_cast<T>(cx+w*0.5);
}

template <typename T>
void box2d<T>::height(T h)
{
    T cy=center().y;
    miny_=static_cast<T>(cy-h*0.5);
    maxy_=static_cast<T>(cy+h*0.5);
}

template <typename T>
coord<T,2> box2d<T>::center() const
{
    return coord<T,2>(static_cast<T>(0.5*(minx_+maxx_)),
                      static_cast<T>(0.5*(miny_+maxy_)));
}

template <typename T>
void box2d<T>::expand_to_include(const coord<T,2>& c)
{
    expand_to_include(c.x,c.y);
}

template <typename T>
void box2d<T>::expand_to_include(T x,T y)
{
    if (x<minx_) minx_=x;
    if (x>maxx_) maxx_=x;
    if (y<miny_) miny_=y;
    if (y>maxy_) maxy_=y;
}

template <typename T>
void box2d<T>::expand_to_include(const box2d<T> &other)
{
    if (other.minx_<minx_) minx_=other.minx_;
    if (other.maxx_>maxx_) maxx_=other.maxx_;
    if (other.miny_<miny_) miny_=other.miny_;
    if (other.maxy_>maxy_) maxy_=other.maxy_;
}

template <typename T>
bool box2d<T>::contains(const coord<T,2> &c) const
{
    return contains(c.x,c.y);
}

template <typename T>
bool box2d<T>::contains(T x,T y) const
{
    return x>=minx_ && x<=maxx_ && y>=miny_ && y<=maxy_;
}

template <typename T>
bool box2d<T>::contains(const box2d<T> &other) const
{
    return other.minx_>=minx_ &&
        other.maxx_<=maxx_ &&
        other.miny_>=miny_ &&
        other.maxy_<=maxy_;
}

template <typename T>
bool box2d<T>::intersects(const coord<T,2> &c) const
{
    return intersects(c.x,c.y);
}

template <typename T>
bool box2d<T>::intersects(T x,T y) const
{
    return !(x>maxx_ || x<minx_ || y>maxy_ || y<miny_);
}

template <typename T>
bool box2d<T>::intersects(const box2d<T> &other) const
{
    return !(other.minx_>maxx_ || other.maxx_<minx_ ||
             other.miny_>maxy_ || other.maxy_<miny_);
}

template <typename T>
box2d<T> box2d<T>::intersect(const box2d_type& other) const
{
    if (intersects(other)) {
        T x0=std::max(minx_,other.minx_);
        T y0=std::max(miny_,other.miny_);

        T x1=std::min(maxx_,other.maxx_);
        T y1=std::min(maxy_,other.maxy_);

        return box2d<T>(x0,y0,x1,y1);
    } else {
        return box2d<T>();
    }
}

template <typename T>
void box2d<T>::re_center(T cx,T cy)
{
    T dx=cx-center().x;
    T dy=cy-center().y;
    minx_+=dx;
    miny_+=dy;
    maxx_+=dx;
    maxy_+=dy;
}

template <typename T>
void box2d<T>::re_center(const coord<T,2> &c)
{
    re_center(c.x,c.y);
}

template <typename T>
void box2d<T>::init(T x0,T y0,T x1,T y1)
{
    if (x0<x1)
    {
        minx_=x0;maxx_=x1;
    }
    else
    {
        minx_=x1;maxx_=x0;
    }
    if (y0<y1)
    {
        miny_=y0;maxy_=y1;
    }
    else
    {
        miny_=y1;maxy_=y0;
    }
}

template <typename T>
void box2d<T>::clip(const box2d_type& other)
{
    minx_ = std::max(minx_,other.minx());
    miny_ = std::max(miny_,other.miny());
    maxx_ = std::min(maxx_,other.maxx());
    maxy_ = std::min(maxy_,other.maxy());
}

template <typename T>
void box2d<T>::pad(T padding)
{
    minx_ -= padding;
    miny_ -= padding;
    maxx_ += padding;
    maxy_ += padding;
}

template <typename T>
inline bool box2d<T>::from_string(std::string const& str)
{
    using boost::spirit::qi::double_;
    using boost::spirit::ascii::space;
    bool r = boost::spirit::qi::phrase_parse(str.begin(),
                                             str.end(),
                                             double_ >> ',' >> double_ >> ','
                                             >> double_ >> ',' >> double_,
                                             space,
                                             *this);
    return r;
}

template <typename T>
bool box2d<T>::valid() const
{
    return (minx_ <= maxx_ && miny_ <= maxy_) ;
}

template <typename T>
box2d<T>&  box2d<T>::operator+=(box2d<T> const& other)
{
    expand_to_include(other);
    return *this;
}

template <typename T>
box2d<T>& box2d<T>::operator*=(T t)
{
    coord<T,2> c = center();
    T sx = static_cast<T>(0.5 * width()  * t);
    T sy = static_cast<T>(0.5 * height() * t);
    minx_ = c.x - sx;
    maxx_ = c.x + sx;
    miny_ = c.y - sy;
    maxy_ = c.y + sy;
    return *this;
}

template <typename T>
box2d<T>& box2d<T>::operator/=(T t)
{
    coord<T,2> c = center();
    T sx = static_cast<T>(0.5 * width() / t);
    T sy = static_cast<T>(0.5 * height() / t);
    minx_ = c.x - sx;
    maxx_ = c.x + sx;
    miny_ = c.y - sy;
    maxy_ = c.y + sy;
    return *this;
}

template <typename T>
T box2d<T>::operator[] (int index) const
{
    switch(index)
    {
    case 0:
        return minx_;
    case 1:
        return miny_;
    case 2:
        return maxx_;
    case 3:
        return maxy_;
    case -4:
        return minx_;
    case -3:
        return miny_;
    case -2:
        return maxx_;
    case -1:
        return maxy_;
    default:
        throw std::out_of_range("index out of range, max value is 3, min value is -4 ");
    }
}

template <typename T>
box2d<T> box2d<T>::operator*(agg::trans_affine const& tr) const
{
    return box2d<T>(*this, tr);
}

template <typename T>
box2d<T>& box2d<T>::operator*=(agg::trans_affine const& tr)
{
    double x0 = minx_, y0 = miny_;
    double x1 = maxx_, y1 = miny_;
    double x2 = maxx_, y2 = maxy_;
    double x3 = minx_, y3 = maxy_;
    tr.transform(&x0, &y0);
    tr.transform(&x1, &y1);
    tr.transform(&x2, &y2);
    tr.transform(&x3, &y3);
    init(static_cast<T>(x0), static_cast<T>(y0),
         static_cast<T>(x2), static_cast<T>(y2));
    expand_to_include(static_cast<T>(x1), static_cast<T>(y1));
    expand_to_include(static_cast<T>(x3), static_cast<T>(y3));
    return *this;
}

template class box2d<int>;
template class box2d<double>;
}
<commit_msg>+ make comma separator optional (preserve space delimitted syntax)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/util/trim.hpp>

// stl
#include <stdexcept>

// boost
// fusion
#include <boost/fusion/include/adapt_adt.hpp>
// spirit
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>

// agg
#include "agg_trans_affine.h"

BOOST_FUSION_ADAPT_TPL_ADT(
    (T),
    (mapnik::box2d)(T),
    (T, T, obj.minx(), obj.set_minx(val))
    (T, T, obj.miny(), obj.set_miny(val))
    (T, T, obj.maxx(), obj.set_maxx(val))
    (T, T, obj.maxy(), obj.set_maxy(val)))

namespace mapnik
{
template <typename T>
box2d<T>::box2d()
    :minx_(0),miny_(0),maxx_(-1),maxy_(-1) {}

template <typename T>
box2d<T>::box2d(T minx,T miny,T maxx,T maxy)
{
    init(minx,miny,maxx,maxy);
}

template <typename T>
box2d<T>::box2d(const coord<T,2> &c0,const coord<T,2> &c1)
{
    init(c0.x,c0.y,c1.x,c1.y);
}

template <typename T>
box2d<T>::box2d(const box2d &rhs)
    : minx_(rhs.minx_),
      miny_(rhs.miny_),
      maxx_(rhs.maxx_),
      maxy_(rhs.maxy_) {}

template <typename T>
box2d<T>::box2d(box2d_type const& rhs, const agg::trans_affine& tr)
{
    double x0 = rhs.minx_, y0 = rhs.miny_;
    double x1 = rhs.maxx_, y1 = rhs.miny_;
    double x2 = rhs.maxx_, y2 = rhs.maxy_;
    double x3 = rhs.minx_, y3 = rhs.maxy_;
    tr.transform(&x0, &y0);
    tr.transform(&x1, &y1);
    tr.transform(&x2, &y2);
    tr.transform(&x3, &y3);
    init(static_cast<T>(x0), static_cast<T>(y0),
         static_cast<T>(x2), static_cast<T>(y2));
    expand_to_include(static_cast<T>(x1), static_cast<T>(y1));
    expand_to_include(static_cast<T>(x3), static_cast<T>(y3));
}

template <typename T>
bool box2d<T>::operator==(const box2d<T>& other) const
{
    return minx_==other.minx_ &&
        miny_==other.miny_ &&
        maxx_==other.maxx_ &&
        maxy_==other.maxy_;
}

template <typename T>
T box2d<T>::minx() const
{
    return minx_;
}

template <typename T>
T box2d<T>::maxx() const
{
    return maxx_;
}

template <typename T>
T box2d<T>::miny() const
{
    return miny_;
}

template <typename T>
T box2d<T>::maxy() const
{
    return maxy_;
}

template<typename T>
void box2d<T>::set_minx(T v)
{
    minx_ = v;
}

template<typename T>
void box2d<T>::set_miny(T v)
{
    miny_ = v;
}

template<typename T>
void box2d<T>::set_maxx(T v)
{
    maxx_ = v;
}

template<typename T>
void box2d<T>::set_maxy(T v)
{
    maxy_ = v;
}

template <typename T>
T box2d<T>::width() const
{
    return maxx_-minx_;
}

template <typename T>
T box2d<T>::height() const
{
    return maxy_-miny_;
}

template <typename T>
void box2d<T>::width(T w)
{
    T cx=center().x;
    minx_=static_cast<T>(cx-w*0.5);
    maxx_=static_cast<T>(cx+w*0.5);
}

template <typename T>
void box2d<T>::height(T h)
{
    T cy=center().y;
    miny_=static_cast<T>(cy-h*0.5);
    maxy_=static_cast<T>(cy+h*0.5);
}

template <typename T>
coord<T,2> box2d<T>::center() const
{
    return coord<T,2>(static_cast<T>(0.5*(minx_+maxx_)),
                      static_cast<T>(0.5*(miny_+maxy_)));
}

template <typename T>
void box2d<T>::expand_to_include(const coord<T,2>& c)
{
    expand_to_include(c.x,c.y);
}

template <typename T>
void box2d<T>::expand_to_include(T x,T y)
{
    if (x<minx_) minx_=x;
    if (x>maxx_) maxx_=x;
    if (y<miny_) miny_=y;
    if (y>maxy_) maxy_=y;
}

template <typename T>
void box2d<T>::expand_to_include(const box2d<T> &other)
{
    if (other.minx_<minx_) minx_=other.minx_;
    if (other.maxx_>maxx_) maxx_=other.maxx_;
    if (other.miny_<miny_) miny_=other.miny_;
    if (other.maxy_>maxy_) maxy_=other.maxy_;
}

template <typename T>
bool box2d<T>::contains(const coord<T,2> &c) const
{
    return contains(c.x,c.y);
}

template <typename T>
bool box2d<T>::contains(T x,T y) const
{
    return x>=minx_ && x<=maxx_ && y>=miny_ && y<=maxy_;
}

template <typename T>
bool box2d<T>::contains(const box2d<T> &other) const
{
    return other.minx_>=minx_ &&
        other.maxx_<=maxx_ &&
        other.miny_>=miny_ &&
        other.maxy_<=maxy_;
}

template <typename T>
bool box2d<T>::intersects(const coord<T,2> &c) const
{
    return intersects(c.x,c.y);
}

template <typename T>
bool box2d<T>::intersects(T x,T y) const
{
    return !(x>maxx_ || x<minx_ || y>maxy_ || y<miny_);
}

template <typename T>
bool box2d<T>::intersects(const box2d<T> &other) const
{
    return !(other.minx_>maxx_ || other.maxx_<minx_ ||
             other.miny_>maxy_ || other.maxy_<miny_);
}

template <typename T>
box2d<T> box2d<T>::intersect(const box2d_type& other) const
{
    if (intersects(other)) {
        T x0=std::max(minx_,other.minx_);
        T y0=std::max(miny_,other.miny_);

        T x1=std::min(maxx_,other.maxx_);
        T y1=std::min(maxy_,other.maxy_);

        return box2d<T>(x0,y0,x1,y1);
    } else {
        return box2d<T>();
    }
}

template <typename T>
void box2d<T>::re_center(T cx,T cy)
{
    T dx=cx-center().x;
    T dy=cy-center().y;
    minx_+=dx;
    miny_+=dy;
    maxx_+=dx;
    maxy_+=dy;
}

template <typename T>
void box2d<T>::re_center(const coord<T,2> &c)
{
    re_center(c.x,c.y);
}

template <typename T>
void box2d<T>::init(T x0,T y0,T x1,T y1)
{
    if (x0<x1)
    {
        minx_=x0;maxx_=x1;
    }
    else
    {
        minx_=x1;maxx_=x0;
    }
    if (y0<y1)
    {
        miny_=y0;maxy_=y1;
    }
    else
    {
        miny_=y1;maxy_=y0;
    }
}

template <typename T>
void box2d<T>::clip(const box2d_type& other)
{
    minx_ = std::max(minx_,other.minx());
    miny_ = std::max(miny_,other.miny());
    maxx_ = std::min(maxx_,other.maxx());
    maxy_ = std::min(maxy_,other.maxy());
}

template <typename T>
void box2d<T>::pad(T padding)
{
    minx_ -= padding;
    miny_ -= padding;
    maxx_ += padding;
    maxy_ += padding;
}

template <typename T>
inline bool box2d<T>::from_string(std::string const& str)
{
    using boost::spirit::qi::lit;
    using boost::spirit::qi::double_;
    using boost::spirit::ascii::space;
    bool r = boost::spirit::qi::phrase_parse(str.begin(),
                                             str.end(),
                                             double_ >> -lit(',') >> double_ >> -lit(',')
                                             >> double_ >> -lit(',') >> double_,
                                             space,
                                             *this);
    return r;
}

template <typename T>
bool box2d<T>::valid() const
{
    return (minx_ <= maxx_ && miny_ <= maxy_) ;
}

template <typename T>
box2d<T>&  box2d<T>::operator+=(box2d<T> const& other)
{
    expand_to_include(other);
    return *this;
}

template <typename T>
box2d<T>& box2d<T>::operator*=(T t)
{
    coord<T,2> c = center();
    T sx = static_cast<T>(0.5 * width()  * t);
    T sy = static_cast<T>(0.5 * height() * t);
    minx_ = c.x - sx;
    maxx_ = c.x + sx;
    miny_ = c.y - sy;
    maxy_ = c.y + sy;
    return *this;
}

template <typename T>
box2d<T>& box2d<T>::operator/=(T t)
{
    coord<T,2> c = center();
    T sx = static_cast<T>(0.5 * width() / t);
    T sy = static_cast<T>(0.5 * height() / t);
    minx_ = c.x - sx;
    maxx_ = c.x + sx;
    miny_ = c.y - sy;
    maxy_ = c.y + sy;
    return *this;
}

template <typename T>
T box2d<T>::operator[] (int index) const
{
    switch(index)
    {
    case 0:
        return minx_;
    case 1:
        return miny_;
    case 2:
        return maxx_;
    case 3:
        return maxy_;
    case -4:
        return minx_;
    case -3:
        return miny_;
    case -2:
        return maxx_;
    case -1:
        return maxy_;
    default:
        throw std::out_of_range("index out of range, max value is 3, min value is -4 ");
    }
}

template <typename T>
box2d<T> box2d<T>::operator*(agg::trans_affine const& tr) const
{
    return box2d<T>(*this, tr);
}

template <typename T>
box2d<T>& box2d<T>::operator*=(agg::trans_affine const& tr)
{
    double x0 = minx_, y0 = miny_;
    double x1 = maxx_, y1 = miny_;
    double x2 = maxx_, y2 = maxy_;
    double x3 = minx_, y3 = maxy_;
    tr.transform(&x0, &y0);
    tr.transform(&x1, &y1);
    tr.transform(&x2, &y2);
    tr.transform(&x3, &y3);
    init(static_cast<T>(x0), static_cast<T>(y0),
         static_cast<T>(x2), static_cast<T>(y2));
    expand_to_include(static_cast<T>(x1), static_cast<T>(y1));
    expand_to_include(static_cast<T>(x3), static_cast<T>(y3));
    return *this;
}

template class box2d<int>;
template class box2d<double>;
}
<|endoftext|>


<commit_before>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hooks_manager.hh"
#include "context.hh"

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const BufferString& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_content(initial_content), m_last_save_undo_index(0)
{
    BufferManager::instance().register_buffer(this);

    if (type == Type::NewFile)
        GlobalHooksManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHooksManager::instance().run_hook("BufOpen", name, Context(*this));

    compute_lines();
}

Buffer::~Buffer()
{
    m_windows.clear();
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return begin();

    BufferCoord clamped = clamp(line_and_column);
    return BufferIterator(*this, m_lines[clamped.line] + clamped.column);
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    BufferCoord result;
    if (not m_lines.empty())
    {
        result.line = line_at(iterator);
        result.column = iterator.m_position - m_lines[result.line];
    }
    return result;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    for (unsigned i = 0; i < line_count(); ++i)
    {
        if (m_lines[i] > iterator.m_position)
            return i - 1;
    }
    return line_count() - 1;
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(not m_lines.empty());
    BufferPos end = (line >= line_count() - 1) ?
                    m_content.size() : m_lines[line + 1] - 1;
    return end - m_lines[line];
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, line_count() - 1, result.line);
    int max_col = std::max(0, line_length(result.line)-1);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, m_lines[line_at(iterator)]);
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = line_at(iterator) + 1;
    return line < m_lines.size() ? BufferIterator(*this, m_lines[line]) : end();
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, 0);
}

BufferIterator Buffer::end() const
{
    return BufferIterator(*this, length());
}

BufferSize Buffer::length() const
{
    return m_content.size();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

BufferString Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    return m_content.substr(begin.m_position, end - begin);
}

BufferChar Buffer::at(BufferPos position) const
{
    return m_content[position];
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::compute_lines()
{
    m_lines.clear();
    m_lines.push_back(0);
    for (BufferPos i = 0; i + 1 < m_content.size(); ++i)
    {
        if (m_content[i] == '\n')
            m_lines.push_back(i + 1);
    }
}

void Buffer::update_lines(const Modification& modification)
{
    const BufferString& content = modification.content;
    size_t length = content.length();

    if (modification.type == Modification::Insert)
    {
        auto line_it = m_lines.begin() + line_at(modification.position) + 1;
        for (auto it = line_it; it != m_lines.end(); ++it)
            *it += length;

        BufferPos pos = modification.position.m_position + 1;
        std::vector<BufferPos> new_lines;
        for (BufferPos i = 0; i < length; ++i)
        {
            if (content[i] == '\n')
                new_lines.push_back(pos);
             ++pos;
        }
        m_lines.insert(line_it, new_lines.begin(), new_lines.end());
    }
    else if (modification.type == Modification::Erase)
    {
        BufferPos line = line_at(modification.position) + 1;

        auto begin = m_lines.begin() + line;
        auto end = begin;
        BufferPos pos = modification.position.m_position;
        while (end != m_lines.end() and *end <= pos + length)
            ++end;
        m_lines.erase(begin, end);

        for (BufferPos i = line; i != m_lines.size(); ++i)
        {
            m_lines[i] -= length;
            assert(m_content[m_lines[i]-1] == '\n');
        }
    }
    else
        assert(false);
}

void Buffer::apply_modification(const Modification& modification)
{
    switch (modification.type)
    {
    case Modification::Insert:
        m_content.insert(modification.position.m_position,
                         modification.content);
        break;
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        m_content.erase(modification.position.m_position, size);
        break;
    }
    default:
        assert(false);
    }
    update_lines(modification);
    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<commit_msg>Fix last line handling in buffer<commit_after>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hooks_manager.hh"
#include "context.hh"

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const BufferString& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_content(initial_content), m_last_save_undo_index(0)
{
    BufferManager::instance().register_buffer(this);

    if (type == Type::NewFile)
        GlobalHooksManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHooksManager::instance().run_hook("BufOpen", name, Context(*this));

    compute_lines();
}

Buffer::~Buffer()
{
    m_windows.clear();
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return begin();

    BufferCoord clamped = clamp(line_and_column);
    return BufferIterator(*this, m_lines[clamped.line] + clamped.column);
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    BufferCoord result;
    if (not m_lines.empty())
    {
        result.line = line_at(iterator);
        result.column = iterator.m_position - m_lines[result.line];
    }
    return result;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    for (unsigned i = 0; i < line_count(); ++i)
    {
        if (m_lines[i] > iterator.m_position)
            return i - 1;
    }
    return line_count() - 1;
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(not m_lines.empty());
    BufferPos end = (line >= line_count() - 1) ?
                    m_content.size() : m_lines[line + 1] - 1;
    return end - m_lines[line];
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, line_count() - 1, result.line);
    int max_col = std::max(0, line_length(result.line)-1);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, m_lines[line_at(iterator)]);
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = line_at(iterator) + 1;
    return line < m_lines.size() ? BufferIterator(*this, m_lines[line]) : end();
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, 0);
}

BufferIterator Buffer::end() const
{
    return BufferIterator(*this, length());
}

BufferSize Buffer::length() const
{
    return m_content.size();
}

BufferSize Buffer::line_count() const
{
    if (m_lines.back() == m_content.size())
        return m_lines.size() - 1;
    else
        return m_lines.size();
}

BufferString Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    return m_content.substr(begin.m_position, end - begin);
}

BufferChar Buffer::at(BufferPos position) const
{
    return m_content[position];
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::compute_lines()
{
    m_lines.clear();
    m_lines.push_back(0);
    for (BufferPos i = 0; i < m_content.size(); ++i)
    {
        if (m_content[i] == '\n')
            m_lines.push_back(i + 1);
    }
}

void Buffer::update_lines(const Modification& modification)
{
    const BufferString& content = modification.content;
    size_t length = content.length();

    if (modification.type == Modification::Insert)
    {
        auto line_it = m_lines.begin() + line_at(modification.position) + 1;
        for (auto it = line_it; it != m_lines.end(); ++it)
            *it += length;

        BufferPos pos = modification.position.m_position + 1;
        std::vector<BufferPos> new_lines;
        for (BufferPos i = 0; i < length; ++i)
        {
            if (content[i] == '\n')
                new_lines.push_back(pos);
             ++pos;
        }
        m_lines.insert(line_it, new_lines.begin(), new_lines.end());
    }
    else if (modification.type == Modification::Erase)
    {
        BufferPos line = line_at(modification.position) + 1;

        auto begin = m_lines.begin() + line;
        auto end = begin;
        BufferPos pos = modification.position.m_position;
        while (end != m_lines.end() and *end <= pos + length)
            ++end;
        m_lines.erase(begin, end);

        for (BufferPos i = line; i != m_lines.size(); ++i)
        {
            m_lines[i] -= length;
            assert(m_content[m_lines[i]-1] == '\n');
        }
    }
    else
        assert(false);
}

void Buffer::apply_modification(const Modification& modification)
{
    switch (modification.type)
    {
    case Modification::Insert:
        m_content.insert(modification.position.m_position,
                         modification.content);
        break;
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        m_content.erase(modification.position.m_position, size);
        break;
    }
    default:
        assert(false);
    }
    update_lines(modification);
    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<|endoftext|>


<commit_before>#include "xml11_nodeimpl.hpp"

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

namespace xml11 {

namespace {

int WriteNodeToXml(
    const std::shared_ptr<NodeImpl>& root,
    const xmlTextWriterPtr writer,
    const bool indent,
    ValueFilter valueFilter)
{
    int rc = xmlTextWriterStartElement(writer,
                                       reinterpret_cast<const unsigned char*>(
                                           root->name().c_str()));
    if (rc < 0) {
        return -1;
    }

    if (indent) {
        xmlTextWriterSetIndent(writer, 1 /*indent*/);
    }

    for (const auto& node : root->nodes()) {
        if (node->type() == Node::Type::ATTRIBUTE) {
            rc = xmlTextWriterWriteAttribute(writer,
                                             reinterpret_cast<const unsigned char*>(
                                                 node->name().c_str()),
                                             reinterpret_cast<const unsigned char*>(
                                                 GenerateString(
                                                     node->text(), valueFilter).c_str()));
            if (rc < 0) {
                return -1;
            }
        }
    }

    for (const auto& node : root->nodes()) {
        if (node->type() == Node::Type::ELEMENT) {
            rc = WriteNodeToXml(node, writer, indent, valueFilter);
            if (rc < 0) {
                return -1;
            }
        }
    }

    if (not root->text().empty()) {
        rc = xmlTextWriterWriteRaw(writer,
                                   reinterpret_cast<const unsigned char*>(
                                       GenerateString(
                                           root->text(), valueFilter).c_str()));
        if (rc < 0) {
            return -1;
        }
    }

    rc = xmlTextWriterEndElement(writer);
    if (rc < 0) {
        return -1;
    }

    if (indent) {
        xmlTextWriterSetIndent(writer, 1 /*indent*/);
    }

    return 0;
}

void ErrorHandler(void *ctx, const xmlErrorPtr error) {
    using std::to_string;

    if (not error || error->code == XML_ERR_OK) {
        return;
    }

    auto res = static_cast<std::string*>(ctx);
    if (not res) {
        return;
    }

    auto& result = *res;
    result.reserve(1024);

    result += "LibXML2: ";

    switch (error->level) {
    case XML_ERR_NONE:
        result = "";
        break;
    case XML_ERR_WARNING:
        result = "Warning: ";
        break;
    case XML_ERR_ERROR:
        result = "Error: ";
        break;
    case XML_ERR_FATAL:
        result = "Fatal error: ";
        break;
    }

    const int line = error->line;
    const int column = error->int2;

    if (error->file != NULL) {
        result += error->file;
    } else if (line != 0) {
        result += "Entity: line " + to_string(line) + ", column: " + to_string(column);
    }

    const auto node = static_cast<xmlNodePtr>(error->node);
    if (error->node != NULL and node->type == XML_ELEMENT_NODE) {
        result += ", element ";
        result += reinterpret_cast<const char*>(node->name);
    }

    result += ": ";
    result += error->message;
    result += '\n';
}

std::string ToXml_(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    ValueFilter valueFilter,
    xmlBufferPtr buffer,
    xmlTextWriterPtr writer)
{
    std::string error;
    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    buffer = xmlBufferCreate();
    if (not buffer) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlBufferCreate() error");
        }
    }

    writer = xmlNewTextWriterMemory(buffer, 0 /* compress */);
    if (not writer) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlNewTextWriterMemory() error");
        }
    }

    int rc = xmlTextWriterStartDocument(writer, NULL/*version*/, "UTF-8", NULL/*standalone*/);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlTextWriterStartDocument() error");
        }
    }

    if (indent) {
        xmlTextWriterSetIndentString(writer, reinterpret_cast<const unsigned char*>("  "));
    }

    rc = WriteNodeToXml(root, writer, indent, valueFilter);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "WriteNodeToXml() error");
        }
    }

    rc = xmlTextWriterEndDocument(writer);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlTextWriterEndDocument() error");
        }
    }

    std::string result(reinterpret_cast<const char*>(buffer->content));

    if (not indent) {
        result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
    }

    return result;
}

void RestoreGlobalData(
    const xmlBufferPtr buffer,
    const xmlTextWriterPtr writer)
{
    xmlSetStructuredErrorFunc(NULL, NULL);

    if (writer) {
        xmlFreeTextWriter(writer);
    }

    if (buffer) {
        xmlBufferFree(buffer);
    }

    if (xmlGetLastError()) {
        xmlResetLastError();
    }
}

std::string ToXml(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    ValueFilter valueFilter)
{
    xmlBufferPtr buffer {nullptr};
    xmlTextWriterPtr writer {nullptr};

    try {
        return ToXml_(root, indent, valueFilter, buffer, writer);
    } catch (const Node::Xml11Exception& e) {
        RestoreGlobalData(buffer, writer);
        throw e;
    }
    RestoreGlobalData(buffer, writer);
    return "";
}

NodeImpl& FindLastByDepth(NodeImpl& root, size_t depth)
{
    auto* node = &root;
    while (depth-- - 1) {
        if (not node->nodes().empty()) {
            if (node->nodes().back()) {
                node = &*node->nodes().back();
            }
        }
    }
    return *node;
}

void FetchAllAttributes(
    NodeImpl& node,
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    xmlChar* name = nullptr;
    xmlChar* value = nullptr;

    if (xmlTextReaderHasAttributes(reader)) {
        while (xmlTextReaderMoveToNextAttribute(reader)) {
            name = xmlTextReaderName(reader);
            value = xmlTextReaderValue(reader);

            if (name and value) {
                NodeImpl prop {
                    reinterpret_cast<const char*>(name),
                        GenerateString(
                            reinterpret_cast<const char*>(value), valueFilter)
                };
                prop.type(Node::Type::ATTRIBUTE);
                prop.isCaseInsensitive(isCaseInsensitive);
                node.addNode(std::move(prop));
            }

            if (name) {
                xmlFree(reinterpret_cast<void*>(name)); name = nullptr;
            }

            if (value) {
                xmlFree(reinterpret_cast<void*>(value)); value = nullptr;
            }
        }
        xmlTextReaderMoveToElement(reader);
    }
}

std::shared_ptr<NodeImpl> ParseXml(
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    auto ret = xmlTextReaderRead(reader);
    auto nodeType = xmlTextReaderNodeType(reader);

    if (nodeType != XML_ELEMENT_NODE or (ret != 1 and ret != 0)) {
        return nullptr;
    }

    xmlChar* name = xmlTextReaderName(reader);
    xmlChar* value = nullptr;

    if (not name) {
        return nullptr;
    }

    const auto root = std::make_shared<NodeImpl>(
        reinterpret_cast<const char*>(name));
    root->isCaseInsensitive(isCaseInsensitive);
    xmlFree(reinterpret_cast<void*>(name)); name = nullptr;

    FetchAllAttributes(*root, reader, isCaseInsensitive, valueFilter);

    for (ret = xmlTextReaderRead(reader); ret == 1; ret = xmlTextReaderRead(reader)) {
        nodeType = xmlTextReaderNodeType(reader);

        if (nodeType == XML_ELEMENT_NODE) {
            name = xmlTextReaderName(reader);

            if (name) {
                NodeImpl node {
                    reinterpret_cast<const char*>(name)
                };
                node.type(Node::Type::ELEMENT);
                node.isCaseInsensitive(isCaseInsensitive);
                xmlFree(reinterpret_cast<void*>(name)); name = nullptr;

                FetchAllAttributes(node, reader, isCaseInsensitive, valueFilter);

                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.addNode(std::move(node));
            }
        }
        else if (nodeType == XML_TEXT_NODE) {
            value = xmlTextReaderValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.text() += GenerateString(
                    reinterpret_cast<const char*>(value), valueFilter);
            }
        }
    }

    return ret != 0 ? nullptr : root;
}

std::shared_ptr<NodeImpl> ParseXml_(
    const std::string& text,
    const bool isCaseInsensitive,
    ValueFilter valueFilter,
    xmlTextReaderPtr reader)
{
    if (text.empty()) {
        return nullptr;
    }

    std::string error;
    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    reader =
        xmlReaderForMemory(text.data(), text.size(), NULL, NULL, XML_PARSE_NOBLANKS);

    if (not reader) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlReaderForMemory() error");
        }
    }

    const auto node = ParseXml(reader, isCaseInsensitive, valueFilter);

    if ((not node) or (node and not error.empty())) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "ParseXml() error");
        }
    }

    return node;
}

void RestoreGlobalDataReader(
    const xmlTextReaderPtr reader)
{
    xmlSetStructuredErrorFunc(NULL, NULL);

    if (reader) {
        xmlFreeTextReader(reader);
    }

    if (xmlGetLastError()) {
        xmlResetLastError();
    }

    xmlCleanupParser();
}

std::shared_ptr<NodeImpl> ParseXml(
    const std::string& text,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    xmlTextReaderPtr reader {nullptr};

    try {
        return ParseXml_(text, isCaseInsensitive, valueFilter, reader);
    } catch (const Node::Xml11Exception& e) {
        RestoreGlobalDataReader(reader);
        throw e;
    }
    RestoreGlobalDataReader(reader);
    return {};
}

} /* anonymous namespace */

} /* namespace xml11 */
<commit_msg>cleanup libxml2 data<commit_after>#include "xml11_nodeimpl.hpp"

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

namespace xml11 {

namespace {

int WriteNodeToXml(
    const std::shared_ptr<NodeImpl>& root,
    const xmlTextWriterPtr writer,
    const bool indent,
    ValueFilter valueFilter)
{
    int rc = xmlTextWriterStartElement(writer,
                                       reinterpret_cast<const unsigned char*>(
                                           root->name().c_str()));
    if (rc < 0) {
        return -1;
    }

    if (indent) {
        xmlTextWriterSetIndent(writer, 1 /*indent*/);
    }

    for (const auto& node : root->nodes()) {
        if (node->type() == Node::Type::ATTRIBUTE) {
            rc = xmlTextWriterWriteAttribute(writer,
                                             reinterpret_cast<const unsigned char*>(
                                                 node->name().c_str()),
                                             reinterpret_cast<const unsigned char*>(
                                                 GenerateString(
                                                     node->text(), valueFilter).c_str()));
            if (rc < 0) {
                return -1;
            }
        }
    }

    for (const auto& node : root->nodes()) {
        if (node->type() == Node::Type::ELEMENT) {
            rc = WriteNodeToXml(node, writer, indent, valueFilter);
            if (rc < 0) {
                return -1;
            }
        }
    }

    if (not root->text().empty()) {
        rc = xmlTextWriterWriteRaw(writer,
                                   reinterpret_cast<const unsigned char*>(
                                       GenerateString(
                                           root->text(), valueFilter).c_str()));
        if (rc < 0) {
            return -1;
        }
    }

    rc = xmlTextWriterEndElement(writer);
    if (rc < 0) {
        return -1;
    }

    if (indent) {
        xmlTextWriterSetIndent(writer, 1 /*indent*/);
    }

    return 0;
}

void ErrorHandler(void *ctx, const xmlErrorPtr error) {
    using std::to_string;

    if (not error || error->code == XML_ERR_OK) {
        return;
    }

    auto res = static_cast<std::string*>(ctx);
    if (not res) {
        return;
    }

    auto& result = *res;
    result.reserve(1024);

    result += "LibXML2: ";

    switch (error->level) {
    case XML_ERR_NONE:
        result = "";
        break;
    case XML_ERR_WARNING:
        result = "Warning: ";
        break;
    case XML_ERR_ERROR:
        result = "Error: ";
        break;
    case XML_ERR_FATAL:
        result = "Fatal error: ";
        break;
    }

    const int line = error->line;
    const int column = error->int2;

    if (error->file != NULL) {
        result += error->file;
    } else if (line != 0) {
        result += "Entity: line " + to_string(line) + ", column: " + to_string(column);
    }

    const auto node = static_cast<xmlNodePtr>(error->node);
    if (error->node != NULL and node->type == XML_ELEMENT_NODE) {
        result += ", element ";
        result += reinterpret_cast<const char*>(node->name);
    }

    result += ": ";
    result += error->message;
    result += '\n';
}

std::string ToXml_(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    ValueFilter valueFilter,
    xmlBufferPtr buffer,
    xmlTextWriterPtr writer)
{
    std::string error;
    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    buffer = xmlBufferCreate();
    if (not buffer) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlBufferCreate() error");
        }
    }

    writer = xmlNewTextWriterMemory(buffer, 0 /* compress */);
    if (not writer) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlNewTextWriterMemory() error");
        }
    }

    int rc = xmlTextWriterStartDocument(writer, NULL/*version*/, "UTF-8", NULL/*standalone*/);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlTextWriterStartDocument() error");
        }
    }

    if (indent) {
        xmlTextWriterSetIndentString(writer, reinterpret_cast<const unsigned char*>("  "));
    }

    rc = WriteNodeToXml(root, writer, indent, valueFilter);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "WriteNodeToXml() error");
        }
    }

    rc = xmlTextWriterEndDocument(writer);
    if (rc < 0) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlTextWriterEndDocument() error");
        }
    }

    std::string result(reinterpret_cast<const char*>(buffer->content));

    if (not indent) {
        result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
    }

    return result;
}

void RestoreGlobalData(
    const xmlBufferPtr buffer,
    const xmlTextWriterPtr writer)
{
    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, NULL);
    initGenericErrorDefaultFunc(NULL);

    if (writer) {
        xmlFreeTextWriter(writer);
    }

    if (buffer) {
        xmlBufferFree(buffer);
    }

    if (xmlGetLastError()) {
        xmlResetError(xmlGetLastError());
        xmlResetLastError();
    }

    xmlCleanupParser();
}

std::string ToXml(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    ValueFilter valueFilter)
{
    xmlBufferPtr buffer {nullptr};
    xmlTextWriterPtr writer {nullptr};
    xmlInitParser();

    try {
        const auto result = ToXml_(root, indent, valueFilter, buffer, writer);
        RestoreGlobalData(buffer, writer);
        return result;
    } catch (const Node::Xml11Exception& e) {
        RestoreGlobalData(buffer, writer);
        throw e;
    }

    return "";
}

NodeImpl& FindLastByDepth(NodeImpl& root, size_t depth)
{
    auto* node = &root;
    while (depth-- - 1) {
        if (not node->nodes().empty()) {
            if (node->nodes().back()) {
                node = &*node->nodes().back();
            }
        }
    }
    return *node;
}

void FetchAllAttributes(
    NodeImpl& node,
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    xmlChar* name = nullptr;
    xmlChar* value = nullptr;

    if (xmlTextReaderHasAttributes(reader)) {
        while (xmlTextReaderMoveToNextAttribute(reader)) {
            name = xmlTextReaderName(reader);
            value = xmlTextReaderValue(reader);

            if (name and value) {
                NodeImpl prop {
                    reinterpret_cast<const char*>(name),
                        GenerateString(
                            reinterpret_cast<const char*>(value), valueFilter)
                };
                prop.type(Node::Type::ATTRIBUTE);
                prop.isCaseInsensitive(isCaseInsensitive);
                node.addNode(std::move(prop));
            }

            if (name) {
                xmlFree(reinterpret_cast<void*>(name)); name = nullptr;
            }

            if (value) {
                xmlFree(reinterpret_cast<void*>(value)); value = nullptr;
            }
        }
        xmlTextReaderMoveToElement(reader);
    }
}

std::shared_ptr<NodeImpl> ParseXml(
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    auto ret = xmlTextReaderRead(reader);
    auto nodeType = xmlTextReaderNodeType(reader);

    if (nodeType != XML_ELEMENT_NODE or (ret != 1 and ret != 0)) {
        return nullptr;
    }

    xmlChar* name = xmlTextReaderName(reader);
    xmlChar* value = nullptr;

    if (not name) {
        return nullptr;
    }

    const auto root = std::make_shared<NodeImpl>(
        reinterpret_cast<const char*>(name));
    root->isCaseInsensitive(isCaseInsensitive);
    xmlFree(reinterpret_cast<void*>(name)); name = nullptr;

    FetchAllAttributes(*root, reader, isCaseInsensitive, valueFilter);

    for (ret = xmlTextReaderRead(reader); ret == 1; ret = xmlTextReaderRead(reader)) {
        nodeType = xmlTextReaderNodeType(reader);

        if (nodeType == XML_ELEMENT_NODE) {
            name = xmlTextReaderName(reader);

            if (name) {
                NodeImpl node {
                    reinterpret_cast<const char*>(name)
                };
                node.type(Node::Type::ELEMENT);
                node.isCaseInsensitive(isCaseInsensitive);
                xmlFree(reinterpret_cast<void*>(name)); name = nullptr;

                FetchAllAttributes(node, reader, isCaseInsensitive, valueFilter);

                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.addNode(std::move(node));
            }
        }
        else if (nodeType == XML_TEXT_NODE) {
            value = xmlTextReaderValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.text() += GenerateString(
                    reinterpret_cast<const char*>(value), valueFilter);
            }
        }
    }

    return ret != 0 ? nullptr : root;
}

std::shared_ptr<NodeImpl> ParseXml_(
    const std::string& text,
    const bool isCaseInsensitive,
    ValueFilter valueFilter,
    xmlTextReaderPtr reader)
{
    if (text.empty()) {
        return nullptr;
    }

    std::string error;
    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    reader =
        xmlReaderForMemory(text.data(), text.size(), NULL, NULL, XML_PARSE_NOBLANKS);

    if (not reader) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "xmlReaderForMemory() error");
        }
    }

    const auto node = ParseXml(reader, isCaseInsensitive, valueFilter);

    if ((not node) or (node and not error.empty())) {
        if (not error.empty()) {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + error);
        }
        else {
            throw Node::Xml11Exception(
                std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": " + "ParseXml() error");
        }
    }

    return node;
}

void RestoreGlobalDataReader(
    const xmlTextReaderPtr reader)
{
    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, NULL);
    initGenericErrorDefaultFunc(NULL);

    if (reader) {
        xmlFreeTextReader(reader);
    }

    if (xmlGetLastError()) {
        xmlResetError(xmlGetLastError());
        xmlResetLastError();
    }

    xmlCleanupParser();
}

std::shared_ptr<NodeImpl> ParseXml(
    const std::string& text,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    xmlTextReaderPtr reader {nullptr};
    xmlInitParser();

    try {
        const auto result = ParseXml_(text, isCaseInsensitive, valueFilter, reader);
        RestoreGlobalDataReader(reader);
        return result;
    } catch (const Node::Xml11Exception& e) {
        RestoreGlobalDataReader(reader);
        throw e;
    }

    return {};
}

} /* anonymous namespace */

} /* namespace xml11 */
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006, 2007, 2008, 2009 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"

#if !OS(WIN) && !OS(ANDROID)
#include "SkFontConfigInterface.h"
#endif
#include "SkFontMgr.h"
#include "SkStream.h"
#include "SkTypeface.h"
#include "platform/fonts/AlternateFontFamily.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "public/platform/linux/WebSandboxSupport.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/CString.h"
#include <unicode/locid.h>

#if !OS(WIN) && !OS(ANDROID)
static SkStream* streamForFontconfigInterfaceId(int fontconfigInterfaceId)
{
    SkAutoTUnref<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
    SkFontConfigInterface::FontIdentity fontIdentity;
    fontIdentity.fID = fontconfigInterfaceId;
    return fci->openStream(fontIdentity);
}
#endif

namespace blink {

void FontCache::platformInit()
{
}

PassRefPtr<SimpleFontData> FontCache::fallbackOnStandardFontStyle(
    const FontDescription& fontDescription, UChar32 character)
{
    FontDescription substituteDescription(fontDescription);
    substituteDescription.setStyle(FontStyleNormal);
    substituteDescription.setWeight(FontWeightNormal);

    FontFaceCreationParams creationParams(substituteDescription.family().family());
    FontPlatformData* substitutePlatformData = getFontPlatformData(substituteDescription, creationParams);
    if (substitutePlatformData && substitutePlatformData->fontContainsCharacter(character)) {
        FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
        platformData.setSyntheticBold(fontDescription.weight() >= FontWeight600);
        platformData.setSyntheticItalic(fontDescription.style() == FontStyleItalic);
        return fontDataFromFontPlatformData(&platformData, DoNotRetain);
    }

    return nullptr;
}

#if !OS(WIN) && !OS(ANDROID)
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
{
    // First try the specified font with standard style & weight.
    if (fontDescription.style() == FontStyleItalic
        || fontDescription.weight() >= FontWeight600) {
        RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
            fontDescription, c);
        if (fontData)
            return fontData;
    }

    FontCache::PlatformFallbackFont fallbackFont;
    FontCache::getFontForCharacter(c, fontDescription.locale().ascii().data(), &fallbackFont);
    if (fallbackFont.name.isEmpty())
        return nullptr;

    FontFaceCreationParams creationParams;
    creationParams = FontFaceCreationParams(fallbackFont.filename, fallbackFont.fontconfigInterfaceId, fallbackFont.ttcIndex);

    // Changes weight and/or italic of given FontDescription depends on
    // the result of fontconfig so that keeping the correct font mapping
    // of the given character. See http://crbug.com/32109 for details.
    bool shouldSetSyntheticBold = false;
    bool shouldSetSyntheticItalic = false;
    FontDescription description(fontDescription);
    if (fallbackFont.isBold && description.weight() < FontWeightBold)
        description.setWeight(FontWeightBold);
    if (!fallbackFont.isBold && description.weight() >= FontWeightBold) {
        shouldSetSyntheticBold = true;
        description.setWeight(FontWeightNormal);
    }
    if (fallbackFont.isItalic && description.style() == FontStyleNormal)
        description.setStyle(FontStyleItalic);
    if (!fallbackFont.isItalic && description.style() == FontStyleItalic) {
        shouldSetSyntheticItalic = true;
        description.setStyle(FontStyleNormal);
    }

    FontPlatformData* substitutePlatformData = getFontPlatformData(description, creationParams);
    if (!substitutePlatformData)
        return nullptr;
    FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
    platformData.setSyntheticBold(shouldSetSyntheticBold);
    platformData.setSyntheticItalic(shouldSetSyntheticItalic);
    return fontDataFromFontPlatformData(&platformData, DoNotRetain);
}

#endif // !OS(WIN) && !OS(ANDROID)

PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain)
{
    const FontFaceCreationParams fallbackCreationParams(getFallbackFontFamily(description));
    const FontPlatformData* fontPlatformData = getFontPlatformData(description, fallbackCreationParams);

    // We should at least have Sans or Arial which is the last resort fallback of SkFontHost ports.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, sansCreationParams, (AtomicString("Sans", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, sansCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, arialCreationParams, (AtomicString("Arial", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, arialCreationParams);
    }
#if OS(WIN)
    // Try some more Windows-specific fallbacks.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, msuigothicCreationParams, (AtomicString("MS UI Gothic", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, msuigothicCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, mssansserifCreationParams, (AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, mssansserifCreationParams);
    }
#endif

    ASSERT(fontPlatformData);
    return fontDataFromFontPlatformData(fontPlatformData, shouldRetain);
}

#if OS(WIN)
static inline SkFontStyle fontStyle(const FontDescription& fontDescription)
{
    int width = static_cast<int>(fontDescription.stretch());
    int weight = (fontDescription.weight() - FontWeight100 + 1) * 100;
    SkFontStyle::Slant slant = fontDescription.style() == FontStyleItalic
        ? SkFontStyle::kItalic_Slant
        : SkFontStyle::kUpright_Slant;
    return SkFontStyle(weight, width, slant);
}

static_assert(static_cast<int>(FontStretchUltraCondensed) == static_cast<int>(SkFontStyle::kUltraCondensed_Width),
    "FontStretchUltraCondensed should map to kUltraCondensed_Width");
static_assert(static_cast<int>(FontStretchNormal) == static_cast<int>(SkFontStyle::kNormal_Width),
    "FontStretchNormal should map to kNormal_Width");
static_assert(static_cast<int>(FontStretchUltraExpanded) == static_cast<int>(SkFontStyle::kUltaExpanded_Width),
    "FontStretchUltraExpanded should map to kUltaExpanded_Width");
#endif

PassRefPtr<SkTypeface> FontCache::createTypeface(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, CString& name)
{
#if !OS(WIN) && !OS(ANDROID)
    if (creationParams.creationType() == CreateFontByFciIdAndTtcIndex) {
        SkTypeface* typeface = nullptr;
        if (Platform::current()->sandboxSupport())
            typeface = SkTypeface::CreateFromStream(streamForFontconfigInterfaceId(creationParams.fontconfigInterfaceId()), creationParams.ttcIndex());
        else
            typeface = SkTypeface::CreateFromFile(creationParams.filename().data(), creationParams.ttcIndex());

        if (typeface)
            return adoptRef(typeface);
        else
            return nullptr;
    }
#endif

    AtomicString family = creationParams.family();
    // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
    // the fallback name (like "monospace") that fontconfig understands.
    if (!family.length() || family.startsWith("-webkit-")) {
        name = getFallbackFontFamily(fontDescription).string().utf8();
    } else {
        // convert the name to utf8
        name = family.utf8();
    }

    int style = SkTypeface::kNormal;
    if (fontDescription.weight() >= FontWeight600)
        style |= SkTypeface::kBold;
    if (fontDescription.style())
        style |= SkTypeface::kItalic;

#if OS(WIN)
    if (s_sideloadedFonts) {
        HashMap<String, RefPtr<SkTypeface>>::iterator sideloadedFont =
            s_sideloadedFonts->find(name.data());
        if (sideloadedFont != s_sideloadedFonts->end())
            return sideloadedFont->value;
    }

    if (m_fontManager) {
        return adoptRef(useDirectWrite()
            ? m_fontManager->matchFamilyStyle(name.data(), fontStyle(fontDescription))
            : m_fontManager->legacyCreateTypeface(name.data(), style)
            );
    }
#endif

    // FIXME: Use m_fontManager, SkFontStyle and matchFamilyStyle instead of
    // CreateFromName on all platforms.
    return adoptRef(SkTypeface::CreateFromName(name.data(), static_cast<SkTypeface::Style>(style)));
}

#if !OS(WIN)
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
{
    CString name;
    RefPtr<SkTypeface> tf(createTypeface(fontDescription, creationParams, name));
    if (!tf)
        return 0;

    FontPlatformData* result = new FontPlatformData(tf,
        name.data(),
        fontSize,
        (fontDescription.weight() >= FontWeight600 && !tf->isBold()) || fontDescription.isSyntheticBold(),
        (fontDescription.style() && !tf->isItalic()) || fontDescription.isSyntheticItalic(),
        fontDescription.orientation(),
        fontDescription.useSubpixelPositioning());
    return result;
}
#endif // !OS(WIN)

} // namespace blink
<commit_msg>Temporary return type inference for Skia change.<commit_after>/*
 * Copyright (c) 2006, 2007, 2008, 2009 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"

#if !OS(WIN) && !OS(ANDROID)
#include "SkFontConfigInterface.h"
#endif
#include "SkFontMgr.h"
#include "SkStream.h"
#include "SkTypeface.h"
#include "platform/fonts/AlternateFontFamily.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "public/platform/linux/WebSandboxSupport.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/CString.h"
#include <unicode/locid.h>

#if !OS(WIN) && !OS(ANDROID)
// TODO(bungeman) remove this temporary code ASAP.
// This namespace exists to ease transition of SkTypeface from using SkStream to SkStreamAsset.
namespace tmp {
// Like std::declval but only returns lvalue references, ok since it isn't used on rvalue references.
template<typename T> T& declvall();
// The return type of SkFontConfigInterface::openStream(const SkFontConfigInterface::FontIdentity&).
using StreamType = decltype(tmp::declvall<SkFontConfigInterface>().openStream(tmp::declvall<const SkFontConfigInterface::FontIdentity&>()));
}
static tmp::StreamType streamForFontconfigInterfaceId(int fontconfigInterfaceId)
{
    SkAutoTUnref<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
    SkFontConfigInterface::FontIdentity fontIdentity;
    fontIdentity.fID = fontconfigInterfaceId;
    return fci->openStream(fontIdentity);
}
#endif

namespace blink {

void FontCache::platformInit()
{
}

PassRefPtr<SimpleFontData> FontCache::fallbackOnStandardFontStyle(
    const FontDescription& fontDescription, UChar32 character)
{
    FontDescription substituteDescription(fontDescription);
    substituteDescription.setStyle(FontStyleNormal);
    substituteDescription.setWeight(FontWeightNormal);

    FontFaceCreationParams creationParams(substituteDescription.family().family());
    FontPlatformData* substitutePlatformData = getFontPlatformData(substituteDescription, creationParams);
    if (substitutePlatformData && substitutePlatformData->fontContainsCharacter(character)) {
        FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
        platformData.setSyntheticBold(fontDescription.weight() >= FontWeight600);
        platformData.setSyntheticItalic(fontDescription.style() == FontStyleItalic);
        return fontDataFromFontPlatformData(&platformData, DoNotRetain);
    }

    return nullptr;
}

#if !OS(WIN) && !OS(ANDROID)
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
{
    // First try the specified font with standard style & weight.
    if (fontDescription.style() == FontStyleItalic
        || fontDescription.weight() >= FontWeight600) {
        RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
            fontDescription, c);
        if (fontData)
            return fontData;
    }

    FontCache::PlatformFallbackFont fallbackFont;
    FontCache::getFontForCharacter(c, fontDescription.locale().ascii().data(), &fallbackFont);
    if (fallbackFont.name.isEmpty())
        return nullptr;

    FontFaceCreationParams creationParams;
    creationParams = FontFaceCreationParams(fallbackFont.filename, fallbackFont.fontconfigInterfaceId, fallbackFont.ttcIndex);

    // Changes weight and/or italic of given FontDescription depends on
    // the result of fontconfig so that keeping the correct font mapping
    // of the given character. See http://crbug.com/32109 for details.
    bool shouldSetSyntheticBold = false;
    bool shouldSetSyntheticItalic = false;
    FontDescription description(fontDescription);
    if (fallbackFont.isBold && description.weight() < FontWeightBold)
        description.setWeight(FontWeightBold);
    if (!fallbackFont.isBold && description.weight() >= FontWeightBold) {
        shouldSetSyntheticBold = true;
        description.setWeight(FontWeightNormal);
    }
    if (fallbackFont.isItalic && description.style() == FontStyleNormal)
        description.setStyle(FontStyleItalic);
    if (!fallbackFont.isItalic && description.style() == FontStyleItalic) {
        shouldSetSyntheticItalic = true;
        description.setStyle(FontStyleNormal);
    }

    FontPlatformData* substitutePlatformData = getFontPlatformData(description, creationParams);
    if (!substitutePlatformData)
        return nullptr;
    FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
    platformData.setSyntheticBold(shouldSetSyntheticBold);
    platformData.setSyntheticItalic(shouldSetSyntheticItalic);
    return fontDataFromFontPlatformData(&platformData, DoNotRetain);
}

#endif // !OS(WIN) && !OS(ANDROID)

PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain)
{
    const FontFaceCreationParams fallbackCreationParams(getFallbackFontFamily(description));
    const FontPlatformData* fontPlatformData = getFontPlatformData(description, fallbackCreationParams);

    // We should at least have Sans or Arial which is the last resort fallback of SkFontHost ports.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, sansCreationParams, (AtomicString("Sans", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, sansCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, arialCreationParams, (AtomicString("Arial", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, arialCreationParams);
    }
#if OS(WIN)
    // Try some more Windows-specific fallbacks.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, msuigothicCreationParams, (AtomicString("MS UI Gothic", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, msuigothicCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, mssansserifCreationParams, (AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, mssansserifCreationParams);
    }
#endif

    ASSERT(fontPlatformData);
    return fontDataFromFontPlatformData(fontPlatformData, shouldRetain);
}

#if OS(WIN)
static inline SkFontStyle fontStyle(const FontDescription& fontDescription)
{
    int width = static_cast<int>(fontDescription.stretch());
    int weight = (fontDescription.weight() - FontWeight100 + 1) * 100;
    SkFontStyle::Slant slant = fontDescription.style() == FontStyleItalic
        ? SkFontStyle::kItalic_Slant
        : SkFontStyle::kUpright_Slant;
    return SkFontStyle(weight, width, slant);
}

static_assert(static_cast<int>(FontStretchUltraCondensed) == static_cast<int>(SkFontStyle::kUltraCondensed_Width),
    "FontStretchUltraCondensed should map to kUltraCondensed_Width");
static_assert(static_cast<int>(FontStretchNormal) == static_cast<int>(SkFontStyle::kNormal_Width),
    "FontStretchNormal should map to kNormal_Width");
static_assert(static_cast<int>(FontStretchUltraExpanded) == static_cast<int>(SkFontStyle::kUltaExpanded_Width),
    "FontStretchUltraExpanded should map to kUltaExpanded_Width");
#endif

PassRefPtr<SkTypeface> FontCache::createTypeface(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, CString& name)
{
#if !OS(WIN) && !OS(ANDROID)
    if (creationParams.creationType() == CreateFontByFciIdAndTtcIndex) {
        SkTypeface* typeface = nullptr;
        if (Platform::current()->sandboxSupport())
            typeface = SkTypeface::CreateFromStream(streamForFontconfigInterfaceId(creationParams.fontconfigInterfaceId()), creationParams.ttcIndex());
        else
            typeface = SkTypeface::CreateFromFile(creationParams.filename().data(), creationParams.ttcIndex());

        if (typeface)
            return adoptRef(typeface);
        else
            return nullptr;
    }
#endif

    AtomicString family = creationParams.family();
    // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
    // the fallback name (like "monospace") that fontconfig understands.
    if (!family.length() || family.startsWith("-webkit-")) {
        name = getFallbackFontFamily(fontDescription).string().utf8();
    } else {
        // convert the name to utf8
        name = family.utf8();
    }

    int style = SkTypeface::kNormal;
    if (fontDescription.weight() >= FontWeight600)
        style |= SkTypeface::kBold;
    if (fontDescription.style())
        style |= SkTypeface::kItalic;

#if OS(WIN)
    if (s_sideloadedFonts) {
        HashMap<String, RefPtr<SkTypeface>>::iterator sideloadedFont =
            s_sideloadedFonts->find(name.data());
        if (sideloadedFont != s_sideloadedFonts->end())
            return sideloadedFont->value;
    }

    if (m_fontManager) {
        return adoptRef(useDirectWrite()
            ? m_fontManager->matchFamilyStyle(name.data(), fontStyle(fontDescription))
            : m_fontManager->legacyCreateTypeface(name.data(), style)
            );
    }
#endif

    // FIXME: Use m_fontManager, SkFontStyle and matchFamilyStyle instead of
    // CreateFromName on all platforms.
    return adoptRef(SkTypeface::CreateFromName(name.data(), static_cast<SkTypeface::Style>(style)));
}

#if !OS(WIN)
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
{
    CString name;
    RefPtr<SkTypeface> tf(createTypeface(fontDescription, creationParams, name));
    if (!tf)
        return 0;

    FontPlatformData* result = new FontPlatformData(tf,
        name.data(),
        fontSize,
        (fontDescription.weight() >= FontWeight600 && !tf->isBold()) || fontDescription.isSyntheticBold(),
        (fontDescription.style() && !tf->isItalic()) || fontDescription.isSyntheticItalic(),
        fontDescription.orientation(),
        fontDescription.useSubpixelPositioning());
    return result;
}
#endif // !OS(WIN)

} // namespace blink
<|endoftext|>