<commit_before>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* based on the Null Theme Engine for Gtk+.
* Copyright (c) 2008 Robert Staudinger <robert.staudinger@gmail.com>
*
* 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 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.
*/

#include "oxygeninfowidget.h"
#include "config.h"

#include <iostream>
#include <string>
#include <sstream>

namespace Oxygen
{

    //____________________________________________________
    InfoWidget::InfoWidget( void )
    {

        // main widget
        GtkWidget* mainWidget( gtk_vbox_new( false, 0 ) );
        gtk_box_set_spacing( GTK_BOX( mainWidget ), 5 );
        setWidget( mainWidget );

        // setup
        setName( "About" );
        setComments( "Shows information about this application" );
        setIconName( "dialog-information" );
        realize();

        // about information
        {
            GtkWidget* frame( gtk_frame_new( "About" ) );
            gtk_box_pack_start( GTK_BOX( mainWidget ), frame, false, true, 0 );
            gtk_widget_show( frame );

            // vbox
            GtkWidget* box( gtk_vbox_new( false, 0 ) );
            gtk_box_set_spacing( GTK_BOX( box ), 5 );
            gtk_container_add( GTK_CONTAINER( frame ), box );
            gtk_container_set_border_width( GTK_CONTAINER( box ), 10 );
            gtk_widget_show( box );

            // application name
            GtkWidget* label;
            label = boldLabel();
            gtk_label_set_text( GTK_LABEL( label ), "oxygen-gtk-demo" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // version
            std::ostringstream stream;
            stream << "version " << OXYGEN_VERSION;
            label = boldLabel();
            gtk_label_set_text( GTK_LABEL( label ), stream.str().c_str() );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // description
            label = gtk_label_new( "Gtk+ widgets preview for Oxygen" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "(C) 2010 Hugo Pereira Da Costa, Ruslan Kabatsayev, Cédric Bellegarde" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "https://projects.kde.org/projects/playground/artwork/oxygen-gtk" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "http://kde-look.org/content/show.php/?content=136216" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "License: GNU Lesser General Public License Version 2" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

        }

        // authors information
        {
            GtkWidget* frame( gtk_frame_new( "Authors" ) );
            gtk_box_pack_start( GTK_BOX( mainWidget ), frame, false, true, 0 );
            gtk_widget_show( frame );

            // vbox
            GtkWidget* box( gtk_vbox_new( false, 0 ) );
            gtk_box_set_spacing( GTK_BOX( box ), 5 );
            gtk_container_add( GTK_CONTAINER( frame ), box );
            gtk_container_set_border_width( GTK_CONTAINER( box ), 10 );
            gtk_widget_show( box );

            GtkWidget* label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "Please use bugs.kde.org to report bugs" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // table
            GtkWidget* table( gtk_table_new( 3, 3, false ) );
            gtk_box_pack_start( GTK_BOX( box ), table, false, false, 0 );
            gtk_container_set_border_width( GTK_CONTAINER( table ), 0 );
            gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
            gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
            gtk_widget_show( table );

            // spacing
            GtkWidget* spacing( gtk_label_new( "" ) );
            gtk_table_attach( GTK_TABLE( table ), spacing, 2, 3, 0, 1, GTK_EXPAND, GTK_FILL, 2, 0  );
            gtk_widget_show( spacing );

            addAuthor( table, 0, "Hugo Pereira Da Costa", "Maintainer and developer" );
            addAuthor( table, 1, "Ruslan Kabatsayev", "Maintainer and developer" );
            addAuthor( table, 2, "Cédric Bellegarde", "Developer" );

        }

    }

    //____________________________________________________
    InfoWidget::~InfoWidget( void )
    {}

    //____________________________________________________
    GtkWidget* InfoWidget::boldLabel( void ) const
    {
        GtkWidget* label = gtk_label_new( 0L );

        // create pango attributes list
        PangoAttrList* attributes( pango_attr_list_new() );
        pango_attr_list_insert( attributes, pango_attr_weight_new( PANGO_WEIGHT_BOLD ) );

        GValue val = { 0, };
        g_value_init(&val, PANGO_TYPE_ATTR_LIST );
        g_value_set_boxed( &val, attributes );
        g_object_set_property( G_OBJECT( label ), "attributes", &val );

        pango_attr_list_unref( attributes );

        return label;
    }

    //____________________________________________________
    void InfoWidget::addAuthor( GtkWidget* table, int row, const std::string& author, const std::string& comment ) const
    {

        GtkWidget* label;
        label = gtk_label_new( 0L );
        gtk_label_set_markup( GTK_LABEL( label ), author.c_str() );
        gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
        gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0 );
        gtk_widget_show( label );

        label = gtk_label_new( 0L );
        gtk_label_set_markup( GTK_LABEL( label ), comment.c_str() );
        gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
        gtk_table_attach( GTK_TABLE( table ), label, 1, 2, row, row+1, GTK_FILL, GTK_FILL, 0, 0 );
        gtk_widget_show( label );

        return;

    }

}
<commit_msg>added link to LGPL v2.1<commit_after>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
*
* based on the Null Theme Engine for Gtk+.
* Copyright (c) 2008 Robert Staudinger <robert.staudinger@gmail.com>
*
* 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 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.
*/

#include "oxygeninfowidget.h"
#include "config.h"

#include <iostream>
#include <string>
#include <sstream>

namespace Oxygen
{

    //____________________________________________________
    InfoWidget::InfoWidget( void )
    {

        // main widget
        GtkWidget* mainWidget( gtk_vbox_new( false, 0 ) );
        gtk_box_set_spacing( GTK_BOX( mainWidget ), 5 );
        setWidget( mainWidget );

        // setup
        setName( "About" );
        setComments( "Shows information about this application" );
        setIconName( "dialog-information" );
        realize();

        // about information
        {
            GtkWidget* frame( gtk_frame_new( "About" ) );
            gtk_box_pack_start( GTK_BOX( mainWidget ), frame, false, true, 0 );
            gtk_widget_show( frame );

            // vbox
            GtkWidget* box( gtk_vbox_new( false, 0 ) );
            gtk_box_set_spacing( GTK_BOX( box ), 5 );
            gtk_container_add( GTK_CONTAINER( frame ), box );
            gtk_container_set_border_width( GTK_CONTAINER( box ), 10 );
            gtk_widget_show( box );

            // application name
            GtkWidget* label;
            label = boldLabel();
            gtk_label_set_text( GTK_LABEL( label ), "oxygen-gtk-demo" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // version
            std::ostringstream stream;
            stream << "version " << OXYGEN_VERSION;
            label = boldLabel();
            gtk_label_set_text( GTK_LABEL( label ), stream.str().c_str() );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // description
            label = gtk_label_new( "Gtk+ widgets preview for Oxygen" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "(C) 2010 Hugo Pereira Da Costa, Ruslan Kabatsayev, Cédric Bellegarde" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "https://projects.kde.org/projects/playground/artwork/oxygen-gtk" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "http://kde-look.org/content/show.php/?content=136216" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "License: GNU Lesser General Public License Version 2" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

        }

        // authors information
        {
            GtkWidget* frame( gtk_frame_new( "Authors" ) );
            gtk_box_pack_start( GTK_BOX( mainWidget ), frame, false, true, 0 );
            gtk_widget_show( frame );

            // vbox
            GtkWidget* box( gtk_vbox_new( false, 0 ) );
            gtk_box_set_spacing( GTK_BOX( box ), 5 );
            gtk_container_add( GTK_CONTAINER( frame ), box );
            gtk_container_set_border_width( GTK_CONTAINER( box ), 10 );
            gtk_widget_show( box );

            GtkWidget* label = gtk_label_new( 0L );
            gtk_label_set_markup( GTK_LABEL( label ), "Please use bugs.kde.org to report bugs" );
            gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            label = gtk_label_new( "" );
            gtk_box_pack_start( GTK_BOX( box ), label, true, true, 0 );
            gtk_widget_show( label );

            // table
            GtkWidget* table( gtk_table_new( 3, 3, false ) );
            gtk_box_pack_start( GTK_BOX( box ), table, false, false, 0 );
            gtk_container_set_border_width( GTK_CONTAINER( table ), 0 );
            gtk_table_set_row_spacings( GTK_TABLE( table ), 5 );
            gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
            gtk_widget_show( table );

            // spacing
            GtkWidget* spacing( gtk_label_new( "" ) );
            gtk_table_attach( GTK_TABLE( table ), spacing, 2, 3, 0, 1, GTK_EXPAND, GTK_FILL, 2, 0  );
            gtk_widget_show( spacing );

            addAuthor( table, 0, "Hugo Pereira Da Costa", "Maintainer and developer" );
            addAuthor( table, 1, "Ruslan Kabatsayev", "Maintainer and developer" );
            addAuthor( table, 2, "Cédric Bellegarde", "Developer" );

        }

    }

    //____________________________________________________
    InfoWidget::~InfoWidget( void )
    {}

    //____________________________________________________
    GtkWidget* InfoWidget::boldLabel( void ) const
    {
        GtkWidget* label = gtk_label_new( 0L );

        // create pango attributes list
        PangoAttrList* attributes( pango_attr_list_new() );
        pango_attr_list_insert( attributes, pango_attr_weight_new( PANGO_WEIGHT_BOLD ) );

        GValue val = { 0, };
        g_value_init(&val, PANGO_TYPE_ATTR_LIST );
        g_value_set_boxed( &val, attributes );
        g_object_set_property( G_OBJECT( label ), "attributes", &val );

        pango_attr_list_unref( attributes );

        return label;
    }

    //____________________________________________________
    void InfoWidget::addAuthor( GtkWidget* table, int row, const std::string& author, const std::string& comment ) const
    {

        GtkWidget* label;
        label = gtk_label_new( 0L );
        gtk_label_set_markup( GTK_LABEL( label ), author.c_str() );
        gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
        gtk_table_attach( GTK_TABLE( table ), label, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 0, 0 );
        gtk_widget_show( label );

        label = gtk_label_new( 0L );
        gtk_label_set_markup( GTK_LABEL( label ), comment.c_str() );
        gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
        gtk_table_attach( GTK_TABLE( table ), label, 1, 2, row, row+1, GTK_FILL, GTK_FILL, 0, 0 );
        gtk_widget_show( label );

        return;

    }

}
<|endoftext|>


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

//$Id$

#include <QtGui>

#include <boost/bind.hpp>

#include <mapnik/agg_renderer.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/memory_datasource.hpp>
#include "mapwidget.hpp"
#include "info_dialog.hpp"

using mapnik::image_32;
using mapnik::Map;
using mapnik::layer;
using mapnik::box2d;
using mapnik::coord2d;
using mapnik::feature_ptr;
using mapnik::geometry_ptr;
using mapnik::CoordTransform;
using mapnik::projection;
using mapnik::scale_denominator;

double scales [] = {279541132.014,
                    139770566.007,
                    69885283.0036,
                    34942641.5018,
                    17471320.7509,
                    8735660.37545,
                    4367830.18772,
                    2183915.09386,
                    1091957.54693,
                    545978.773466,
                    272989.386733,
                    136494.693366,
                    68247.3466832,
                    34123.6733416,
                    17061.8366708,
                    8530.9183354,
                    4265.4591677,
                    2132.72958385,
                    1066.36479192,
                    533.182395962};

MapWidget::MapWidget(QWidget *parent)
   : QWidget(parent),
     map_(),
     selected_(1),
     extent_(),
     cur_tool_(ZoomToBox),
     start_x_(0),
     start_y_(0),
     end_x_(0),
     end_y_(0),
     drag_(false),
     first_(true),
     pen_(QColor(0,0,255,96)),
     selectedLayer_(-1),
     scaling_factor_(1.0)
{
   pen_.setWidth(3);
   pen_.setCapStyle(Qt::RoundCap);
   pen_.setJoinStyle(Qt::RoundJoin);
}

void MapWidget::setTool(eTool tool)
{
   cur_tool_=tool;
}

void MapWidget::paintEvent(QPaintEvent*)
{
   QPainter painter(this);

   if (drag_)
   {
      if (cur_tool_ == ZoomToBox)
      {
         unsigned width = end_x_-start_x_;
         unsigned height = end_y_-start_y_;
         painter.drawPixmap(QPoint(0, 0),pix_);
         painter.setPen(pen_);
         painter.setBrush(QColor(200,200,255,128));
         painter.drawRect(start_x_,start_y_,width,height);
      }
      else if (cur_tool_ == Pan)
      {
         int dx = end_x_-start_x_;
         int dy = end_y_-start_y_;
         painter.setBrush(QColor(200,200,200,128));
         painter.drawRect(0,0,width(),height());
         painter.drawPixmap(QPoint(dx,dy),pix_);
      }
   }
   else
   {
      painter.drawPixmap(QPoint(0, 0),pix_);
   }
   painter.end();
}

void MapWidget::resizeEvent(QResizeEvent * ev)
{
   if (map_)
   {
      map_->resize(ev->size().width(),ev->size().height());
      updateMap();
   }
}

void MapWidget::mousePressEvent(QMouseEvent* e)
{
   if (e->button()==Qt::LeftButton)
   {
      if (cur_tool_ == ZoomToBox || cur_tool_==Pan)
      {
         start_x_ = e->x();
         start_y_ = e->y();
         drag_=true;
      }
      else if (cur_tool_==Info)
      {
         if (map_)
         {
            QVector<QPair<QString,QString> > info;

            projection map_proj(map_->srs()); // map projection
            double scale_denom = scale_denominator(*map_,map_proj.is_geographic());
            CoordTransform t(map_->width(),map_->height(),map_->get_current_extent());

            for (unsigned index = 0; index <  map_->layer_count();++index)
            {
               if (int(index) != selectedLayer_) continue;

               layer & layer = map_->layers()[index];
               if (!layer.isVisible(scale_denom)) continue;
               std::string name = layer.name();
               double x = e->x();
               double y = e->y();
               std::cout << "query at " << x << "," << y << "\n";
               projection layer_proj(layer.srs());
               mapnik::proj_transform prj_trans(map_proj,layer_proj);
               //std::auto_ptr<mapnik::memory_datasource> data(new mapnik::memory_datasource);
               mapnik::featureset_ptr fs = map_->query_map_point(index,x,y);

               if (fs)
               {
                  feature_ptr feat  = fs->next();
                  if (feat)
                  {
                      // FIXME
                      /*
                     std::map<std::string,mapnik::value> const& props = feat->props();
                     std::map<std::string,mapnik::value>::const_iterator itr=props.begin();
                     for (; itr!=props.end();++itr)
                     {
                        if (itr->second.to_string().length() > 0)
                        {
                           info.push_back(QPair<QString,QString>(QString(itr->first.c_str()),
                                                                 itr->second.to_string().c_str()));
                        }
                     }
                      */
                     typedef mapnik::coord_transform2<mapnik::CoordTransform,mapnik::geometry_type> path_type;

                     for  (unsigned i=0; i<feat->num_geometries();++i)
                     {
                        mapnik::geometry_type & geom = feat->get_geometry(i);
                        path_type path(t,geom,prj_trans);
                        if (geom.num_points() > 0)
                        {
                           QPainterPath qpath;
                           double x,y;
                           path.vertex(&x,&y);
                           qpath.moveTo(x,y);
                           for (unsigned j = 1; j < geom.num_points(); ++j)
                           {
                              path.vertex(&x,&y);
                              qpath.lineTo(x,y);
                           }
                           QPainter painter(&pix_);
                           QPen pen(QColor(255,0,0,96));
                           pen.setWidth(3);
                           pen.setCapStyle(Qt::RoundCap);
                           pen.setJoinStyle(Qt::RoundJoin);
                           painter.setPen(pen);
                           painter.drawPath(qpath);
                           update();
                        }
                     }
                  }
               }

               if (info.size() > 0)
               {
                  info_dialog info_dlg(info,this);
                  info_dlg.exec();
                  break;
               }
            }

            // remove annotation layer
            map_->layers().erase(remove_if(map_->layers().begin(),
                                           map_->layers().end(),
                                           bind(&layer::name,_1) == "*annotations*")
                                 , map_->layers().end());
         }
      }
   }
   else if (e->button()==Qt::RightButton)
   {
      //updateMap();
   }
}

void MapWidget::mouseMoveEvent(QMouseEvent* e)
{
   if (cur_tool_ == ZoomToBox || cur_tool_==Pan)
   {
      end_x_ = e->x();
      end_y_ = e->y();
      update();
   }
}

void MapWidget::mouseReleaseEvent(QMouseEvent* e)
{
   if (e->button()==Qt::LeftButton)
   {
      end_x_ = e->x();
      end_y_ = e->y();
      if (cur_tool_ == ZoomToBox)
      {
         drag_=false;
         if (map_)
         {
            CoordTransform t(map_->width(),map_->height(),map_->get_current_extent());
            box2d<double> box = t.backward(box2d<double>(start_x_,start_y_,end_x_,end_y_));
            map_->zoom_to_box(box);
            updateMap();
         }
      }
      else if (cur_tool_==Pan)
      {
         drag_=false;
         if (map_)
         {
            int cx = int(0.5 * map_->width());
            int cy = int(0.5 * map_->height());
            int dx = end_x_ - start_x_;
            int dy = end_y_ - start_y_;
            map_->pan(cx - dx ,cy - dy);
            updateMap();
         }
      }
   }
}

void MapWidget::keyPressEvent(QKeyEvent *e)
{
   std::cout << "key pressed:"<< e->key()<<"\n";
   switch (e->key()) {
      case Qt::Key_Minus:
         zoomOut();
         break;
      case Qt::Key_Plus:
      case 61:
         zoomIn();
         break;
      case 65:
         defaultView();
         break;
      case Qt::Key_Up:
         panUp();
         break;
      case Qt::Key_Down:
         panDown();
         break;
      case Qt::Key_Left:
         panLeft();
         break;
      case Qt::Key_Right:
         panRight();
         break;
      case 49:
         zoomToLevel(10);
         break;
      case 50:
         zoomToLevel(11);
         break;
      case 51:
         zoomToLevel(12);
         break;
      case 52:
         zoomToLevel(13);
         break;
      case 53:
         zoomToLevel(14);
         break;
      case 54:
         zoomToLevel(15);
         break;
      case 55:
         zoomToLevel(16);
         break;
      case 56:
         zoomToLevel(17);
         break;
      case 57:
         zoomToLevel(18);
         break;
   default:
       QWidget::keyPressEvent(e);
   }

}

void MapWidget::zoomToBox(mapnik::box2d<double> const& bbox)
{
   if (map_)
   {
      map_->zoom_to_box(bbox);
      updateMap();
   }
}

void MapWidget::defaultView()
{
   if (map_)
   {
      map_->resize(width(),height());
      map_->zoom_all();
      updateMap();
   }
}

void MapWidget::zoomIn()
{
   if (map_)
   {
      map_->zoom(0.5);
      updateMap();
   }
}

void MapWidget::zoomOut()
{
   if (map_)
   {
      map_->zoom(2.0);
      updateMap();
   }
}

void MapWidget::panUp()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx),int(cy - cy*0.25));
      updateMap();
   }
}

void MapWidget::panDown()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx),int(cy + cy*0.25));
      updateMap();
   }
}

void MapWidget::panLeft()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx - cx * 0.25),int(cy));
      updateMap();
   }
}

void MapWidget::panRight()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx + cx * 0.25),int(cy));
      updateMap();
   }
}

void MapWidget::zoomToLevel(int level)
{
   if ( map_ && level >= 0 && level < 19 )
   {
      double scale_denom  = scales[level];
      std::cerr << "scale denominator = " << scale_denom << "\n";
      mapnik::box2d<double> ext = map_->get_current_extent();
      double width = static_cast<double>(map_->width());
      double height= static_cast<double>(map_->height());
      mapnik::coord2d pt = ext.center();

      double res = scale_denom * 0.00028;

      mapnik::box2d<double> box(pt.x - 0.5 * width * res,
                                   pt.y - 0.5 * height*res,
                                   pt.x + 0.5 * width * res,
                                   pt.y + 0.5 * height*res);
      map_->zoom_to_box(box);
      updateMap();
   }
}

void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&)
{
   //image_32 image(width,height);
   //agg_renderer renderer(map,image);
   //renderer.apply();
   //image.saveToFile(filename,type);
}

void MapWidget::set_scaling_factor(double scaling_factor)
{
    scaling_factor_ = scaling_factor;
}

void MapWidget::updateMap()
{
   if (map_)
   {
      unsigned width=map_->width();
      unsigned height=map_->height();

      image_32 buf(width,height);

      try
      {
          mapnik::agg_renderer<image_32> ren(*map_,buf,scaling_factor_);
          ren.apply();

          QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
          pix_=QPixmap::fromImage(image.rgbSwapped());
          projection prj(map_->srs()); // map projection

          box2d<double> ext = map_->get_current_extent();
          double x0 = ext.minx();
          double y0 = ext.miny();
          double x1 = ext.maxx();
          double y1 = ext.maxy();
          prj.inverse(x0,y0);
          prj.inverse(x1,y1);
          std::cout << "BBOX (WGS84): " << x0 << "," << y0 << "," << x1 << "," << y1 << "\n";
          update();
          // emit signal to interested widgets
          emit mapViewChanged();
      }
      catch (mapnik::config_error & ex)
      {
          std::cerr << ex.what() << std::endl;
      }
      catch (...)
      {
          std::cerr << "Unknown exception caught!\n";
      }
   }
}

boost::shared_ptr<Map> MapWidget::getMap()
{
   return map_;
}

void MapWidget::setMap(boost::shared_ptr<Map> map)
{
   map_ = map;
}

void MapWidget::layerSelected(int index)
{
   selectedLayer_ = index;
}
<commit_msg>update 'info' tool to work with new feature impl<commit_after>/* This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * Mapnik is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id$

#include <QtGui>

#include <boost/bind.hpp>

#include <mapnik/agg_renderer.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/memory_datasource.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include "mapwidget.hpp"
#include "info_dialog.hpp"

using mapnik::image_32;
using mapnik::Map;
using mapnik::layer;
using mapnik::box2d;
using mapnik::coord2d;
using mapnik::feature_ptr;
using mapnik::geometry_ptr;
using mapnik::CoordTransform;
using mapnik::projection;
using mapnik::scale_denominator;
using mapnik::feature_kv_iterator;

double scales [] = {279541132.014,
                    139770566.007,
                    69885283.0036,
                    34942641.5018,
                    17471320.7509,
                    8735660.37545,
                    4367830.18772,
                    2183915.09386,
                    1091957.54693,
                    545978.773466,
                    272989.386733,
                    136494.693366,
                    68247.3466832,
                    34123.6733416,
                    17061.8366708,
                    8530.9183354,
                    4265.4591677,
                    2132.72958385,
                    1066.36479192,
                    533.182395962};

MapWidget::MapWidget(QWidget *parent)
   : QWidget(parent),
     map_(),
     selected_(1),
     extent_(),
     cur_tool_(ZoomToBox),
     start_x_(0),
     start_y_(0),
     end_x_(0),
     end_y_(0),
     drag_(false),
     first_(true),
     pen_(QColor(0,0,255,96)),
     selectedLayer_(-1),
     scaling_factor_(1.0)
{
   pen_.setWidth(3);
   pen_.setCapStyle(Qt::RoundCap);
   pen_.setJoinStyle(Qt::RoundJoin);
}

void MapWidget::setTool(eTool tool)
{
   cur_tool_=tool;
}

void MapWidget::paintEvent(QPaintEvent*)
{
   QPainter painter(this);

   if (drag_)
   {
      if (cur_tool_ == ZoomToBox)
      {
         unsigned width = end_x_-start_x_;
         unsigned height = end_y_-start_y_;
         painter.drawPixmap(QPoint(0, 0),pix_);
         painter.setPen(pen_);
         painter.setBrush(QColor(200,200,255,128));
         painter.drawRect(start_x_,start_y_,width,height);
      }
      else if (cur_tool_ == Pan)
      {
         int dx = end_x_-start_x_;
         int dy = end_y_-start_y_;
         painter.setBrush(QColor(200,200,200,128));
         painter.drawRect(0,0,width(),height());
         painter.drawPixmap(QPoint(dx,dy),pix_);
      }
   }
   else
   {
      painter.drawPixmap(QPoint(0, 0),pix_);
   }
   painter.end();
}

void MapWidget::resizeEvent(QResizeEvent * ev)
{
   if (map_)
   {
      map_->resize(ev->size().width(),ev->size().height());
      updateMap();
   }
}

void MapWidget::mousePressEvent(QMouseEvent* e)
{
   if (e->button()==Qt::LeftButton)
   {
      if (cur_tool_ == ZoomToBox || cur_tool_==Pan)
      {
         start_x_ = e->x();
         start_y_ = e->y();
         drag_=true;
      }
      else if (cur_tool_==Info)
      {
         if (map_)
         {
            QVector<QPair<QString,QString> > info;

            projection map_proj(map_->srs()); // map projection
            double scale_denom = scale_denominator(*map_,map_proj.is_geographic());
            CoordTransform t(map_->width(),map_->height(),map_->get_current_extent());

            for (unsigned index = 0; index <  map_->layer_count();++index)
            {
               if (int(index) != selectedLayer_) continue;

               layer & layer = map_->layers()[index];
               if (!layer.isVisible(scale_denom)) continue;
               std::string name = layer.name();
               double x = e->x();
               double y = e->y();
               std::cout << "query at " << x << "," << y << "\n";
               projection layer_proj(layer.srs());
               mapnik::proj_transform prj_trans(map_proj,layer_proj);
               //std::auto_ptr<mapnik::memory_datasource> data(new mapnik::memory_datasource);
               mapnik::featureset_ptr fs = map_->query_map_point(index,x,y);

               if (fs)
               {
                  feature_ptr feat  = fs->next();
                  if (feat)
                  {

                      feature_kv_iterator itr(*feat,true);
                      feature_kv_iterator end(*feat);

                      for ( ;itr!=end; ++itr)
                      {
                          info.push_back(QPair<QString,QString>(QString(boost::get<0>(*itr).c_str()),
                                                                boost::get<1>(*itr).to_string().c_str()));
                      }

                      typedef mapnik::coord_transform2<mapnik::CoordTransform,mapnik::geometry_type> path_type;

                     for  (unsigned i=0; i<feat->num_geometries();++i)
                     {
                        mapnik::geometry_type & geom = feat->get_geometry(i);
                        path_type path(t,geom,prj_trans);
                        if (geom.num_points() > 0)
                        {
                           QPainterPath qpath;
                           double x,y;
                           path.vertex(&x,&y);
                           qpath.moveTo(x,y);
                           for (unsigned j = 1; j < geom.num_points(); ++j)
                           {
                              path.vertex(&x,&y);
                              qpath.lineTo(x,y);
                           }
                           QPainter painter(&pix_);
                           QPen pen(QColor(255,0,0,96));
                           pen.setWidth(3);
                           pen.setCapStyle(Qt::RoundCap);
                           pen.setJoinStyle(Qt::RoundJoin);
                           painter.setPen(pen);
                           painter.drawPath(qpath);
                           update();
                        }
                     }
                  }
               }

               if (info.size() > 0)
               {
                  info_dialog info_dlg(info,this);
                  info_dlg.exec();
                  break;
               }
            }

            // remove annotation layer
            map_->layers().erase(remove_if(map_->layers().begin(),
                                           map_->layers().end(),
                                           bind(&layer::name,_1) == "*annotations*")
                                 , map_->layers().end());
         }
      }
   }
   else if (e->button()==Qt::RightButton)
   {
      //updateMap();
   }
}

void MapWidget::mouseMoveEvent(QMouseEvent* e)
{
   if (cur_tool_ == ZoomToBox || cur_tool_==Pan)
   {
      end_x_ = e->x();
      end_y_ = e->y();
      update();
   }
}

void MapWidget::mouseReleaseEvent(QMouseEvent* e)
{
   if (e->button()==Qt::LeftButton)
   {
      end_x_ = e->x();
      end_y_ = e->y();
      if (cur_tool_ == ZoomToBox)
      {
         drag_=false;
         if (map_)
         {
            CoordTransform t(map_->width(),map_->height(),map_->get_current_extent());
            box2d<double> box = t.backward(box2d<double>(start_x_,start_y_,end_x_,end_y_));
            map_->zoom_to_box(box);
            updateMap();
         }
      }
      else if (cur_tool_==Pan)
      {
         drag_=false;
         if (map_)
         {
            int cx = int(0.5 * map_->width());
            int cy = int(0.5 * map_->height());
            int dx = end_x_ - start_x_;
            int dy = end_y_ - start_y_;
            map_->pan(cx - dx ,cy - dy);
            updateMap();
         }
      }
   }
}

void MapWidget::keyPressEvent(QKeyEvent *e)
{
   std::cout << "key pressed:"<< e->key()<<"\n";
   switch (e->key()) {
      case Qt::Key_Minus:
         zoomOut();
         break;
      case Qt::Key_Plus:
      case 61:
         zoomIn();
         break;
      case 65:
         defaultView();
         break;
      case Qt::Key_Up:
         panUp();
         break;
      case Qt::Key_Down:
         panDown();
         break;
      case Qt::Key_Left:
         panLeft();
         break;
      case Qt::Key_Right:
         panRight();
         break;
      case 49:
         zoomToLevel(10);
         break;
      case 50:
         zoomToLevel(11);
         break;
      case 51:
         zoomToLevel(12);
         break;
      case 52:
         zoomToLevel(13);
         break;
      case 53:
         zoomToLevel(14);
         break;
      case 54:
         zoomToLevel(15);
         break;
      case 55:
         zoomToLevel(16);
         break;
      case 56:
         zoomToLevel(17);
         break;
      case 57:
         zoomToLevel(18);
         break;
   default:
       QWidget::keyPressEvent(e);
   }

}

void MapWidget::zoomToBox(mapnik::box2d<double> const& bbox)
{
   if (map_)
   {
      map_->zoom_to_box(bbox);
      updateMap();
   }
}

void MapWidget::defaultView()
{
   if (map_)
   {
      map_->resize(width(),height());
      map_->zoom_all();
      updateMap();
   }
}

void MapWidget::zoomIn()
{
   if (map_)
   {
      map_->zoom(0.5);
      updateMap();
   }
}

void MapWidget::zoomOut()
{
   if (map_)
   {
      map_->zoom(2.0);
      updateMap();
   }
}

void MapWidget::panUp()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx),int(cy - cy*0.25));
      updateMap();
   }
}

void MapWidget::panDown()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx),int(cy + cy*0.25));
      updateMap();
   }
}

void MapWidget::panLeft()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx - cx * 0.25),int(cy));
      updateMap();
   }
}

void MapWidget::panRight()
{
   if (map_)
   {
      double cx = 0.5*map_->width();
      double cy = 0.5*map_->height();
      map_->pan(int(cx + cx * 0.25),int(cy));
      updateMap();
   }
}

void MapWidget::zoomToLevel(int level)
{
   if ( map_ && level >= 0 && level < 19 )
   {
      double scale_denom  = scales[level];
      std::cerr << "scale denominator = " << scale_denom << "\n";
      mapnik::box2d<double> ext = map_->get_current_extent();
      double width = static_cast<double>(map_->width());
      double height= static_cast<double>(map_->height());
      mapnik::coord2d pt = ext.center();

      double res = scale_denom * 0.00028;

      mapnik::box2d<double> box(pt.x - 0.5 * width * res,
                                   pt.y - 0.5 * height*res,
                                   pt.x + 0.5 * width * res,
                                   pt.y + 0.5 * height*res);
      map_->zoom_to_box(box);
      updateMap();
   }
}

void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&)
{
   //image_32 image(width,height);
   //agg_renderer renderer(map,image);
   //renderer.apply();
   //image.saveToFile(filename,type);
}

void MapWidget::set_scaling_factor(double scaling_factor)
{
    scaling_factor_ = scaling_factor;
}

void MapWidget::updateMap()
{
   if (map_)
   {
      unsigned width=map_->width();
      unsigned height=map_->height();

      image_32 buf(width,height);

      try
      {
          mapnik::agg_renderer<image_32> ren(*map_,buf,scaling_factor_);
          ren.apply();

          QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
          pix_=QPixmap::fromImage(image.rgbSwapped());
          projection prj(map_->srs()); // map projection

          box2d<double> ext = map_->get_current_extent();
          double x0 = ext.minx();
          double y0 = ext.miny();
          double x1 = ext.maxx();
          double y1 = ext.maxy();
          prj.inverse(x0,y0);
          prj.inverse(x1,y1);
          std::cout << "BBOX (WGS84): " << x0 << "," << y0 << "," << x1 << "," << y1 << "\n";
          update();
          // emit signal to interested widgets
          emit mapViewChanged();
      }
      catch (mapnik::config_error & ex)
      {
          std::cerr << ex.what() << std::endl;
      }
      catch (...)
      {
          std::cerr << "Unknown exception caught!\n";
      }
   }
}

boost::shared_ptr<Map> MapWidget::getMap()
{
   return map_;
}

void MapWidget::setMap(boost::shared_ptr<Map> map)
{
   map_ = map;
}

void MapWidget::layerSelected(int index)
{
   selectedLayer_ = index;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

/**
 * @file
 *   This file implements common methods for manipulating MLE TLVs.
 */

#include <common/code_utils.hpp>
#include <common/message.hpp>
#include <thread/mle_tlvs.hpp>

namespace Thread {

ThreadError Tlv::Get(const Message &aMessage, uint8_t aType, uint16_t aMaxLength, Tlv &aTlv)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset;

    SuccessOrExit(error = GetOffset(aMessage, aType, offset));
    aMessage.Read(offset, sizeof(Tlv), &aTlv);

    if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
    {
        aMaxLength = sizeof(aTlv) + aTlv.GetLength();
    }

    aMessage.Read(offset, aMaxLength, &aTlv);

exit:
    return error;
}

ThreadError Tlv::GetOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset = aMessage.GetOffset();
    uint16_t end = aMessage.GetLength();
    Tlv tlv;

    while (offset < end)
    {
        aMessage.Read(offset, sizeof(Tlv), &tlv);

        if (tlv.GetType() == aType && (offset + sizeof(tlv) + tlv.GetLength()) <= end)
        {
            aOffset = offset;
            ExitNow(error = kThreadError_None);
        }

        offset += sizeof(tlv) + tlv.GetLength();
    }

exit:
    return error;
}

ThreadError Tlv::GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset, uint16_t &aLength)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset = aMessage.GetOffset();
    uint16_t end = aMessage.GetLength();

    while (offset < end)
    {
        Tlv tlv;
        uint16_t length;

        aMessage.Read(offset, sizeof(tlv), &tlv);
        offset += sizeof(tlv);

        length = tlv.GetLength();

        if (length == kExtendedLength)
        {
            aMessage.Read(offset, sizeof(length), &length);
            offset += sizeof(length);
            length = HostSwap16(length);
        }

        if (tlv.GetType() == aType)
        {
            aOffset = offset;
            aLength = length;
            ExitNow(error = kThreadError_None);
        }

        offset += length;
    }

exit:
    return error;
}

}  // namespace Thread
<commit_msg>Skip extended tlv when searching for Base TLV (#1172)<commit_after>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

/**
 * @file
 *   This file implements common methods for manipulating MLE TLVs.
 */

#include <common/code_utils.hpp>
#include <common/message.hpp>
#include <thread/mle_tlvs.hpp>

namespace Thread {

ThreadError Tlv::Get(const Message &aMessage, uint8_t aType, uint16_t aMaxLength, Tlv &aTlv)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset;

    SuccessOrExit(error = GetOffset(aMessage, aType, offset));
    aMessage.Read(offset, sizeof(Tlv), &aTlv);

    if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
    {
        aMaxLength = sizeof(aTlv) + aTlv.GetLength();
    }

    aMessage.Read(offset, aMaxLength, &aTlv);

exit:
    return error;
}

ThreadError Tlv::GetOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset = aMessage.GetOffset();
    uint16_t end = aMessage.GetLength();
    Tlv tlv;

    while (offset < end)
    {
        aMessage.Read(offset, sizeof(Tlv), &tlv);

        // skip extended TLV
        if (tlv.GetLength() == kExtendedLength)
        {
            uint16_t length = 0;

            offset += sizeof(tlv);
            aMessage.Read(offset, sizeof(length), &length);
            offset += sizeof(length) + HostSwap16(length);
        }
        else if (tlv.GetType() == aType && (offset + sizeof(tlv) + tlv.GetLength()) <= end)
        {
            aOffset = offset;
            ExitNow(error = kThreadError_None);
        }
        else
        {
            offset += sizeof(tlv) + tlv.GetLength();
        }
    }

exit:
    return error;
}

ThreadError Tlv::GetValueOffset(const Message &aMessage, uint8_t aType, uint16_t &aOffset, uint16_t &aLength)
{
    ThreadError error = kThreadError_Parse;
    uint16_t offset = aMessage.GetOffset();
    uint16_t end = aMessage.GetLength();

    while (offset < end)
    {
        Tlv tlv;
        uint16_t length;

        aMessage.Read(offset, sizeof(tlv), &tlv);
        offset += sizeof(tlv);

        length = tlv.GetLength();

        if (length == kExtendedLength)
        {
            aMessage.Read(offset, sizeof(length), &length);
            offset += sizeof(length);
            length = HostSwap16(length);
        }

        if (tlv.GetType() == aType)
        {
            aOffset = offset;
            aLength = length;
            ExitNow(error = kThreadError_None);
        }

        offset += length;
    }

exit:
    return error;
}

}  // namespace Thread
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/operators/math/math_function.h"
#include <vector>
#include "paddle/fluid/framework/data_type.h"
#include "paddle/fluid/operators/math/math_function_impl.h"
#include "paddle/fluid/platform/float16.h"

namespace paddle {
namespace operators {
namespace math {

using float16 = paddle::platform::float16;

template struct SetConstant<platform::CPUDeviceContext, platform::float16>;
template struct SetConstant<platform::CPUDeviceContext, float>;
template struct SetConstant<platform::CPUDeviceContext, double>;
template struct SetConstant<platform::CPUDeviceContext, int>;
template struct SetConstant<platform::CPUDeviceContext, int64_t>;
template struct SetConstant<platform::CPUDeviceContext, bool>;

#define DEFINE_CPU_TRANS(RANK)                                             \
  template struct Transpose<platform::CPUDeviceContext, platform::float16, \
                            RANK>;                                         \
  template struct Transpose<platform::CPUDeviceContext, float, RANK>;      \
  template struct Transpose<platform::CPUDeviceContext, double, RANK>;     \
  template struct Transpose<platform::CPUDeviceContext, int, RANK>;        \
  template struct Transpose<platform::CPUDeviceContext, int64_t, RANK>;    \
  template struct Transpose<platform::CPUDeviceContext, bool, RANK>;       \
  template struct Transpose<platform::CPUDeviceContext, int16_t, RANK>;    \
  template struct Transpose<platform::CPUDeviceContext, uint8_t, RANK>;

DEFINE_CPU_TRANS(1);
DEFINE_CPU_TRANS(2);
DEFINE_CPU_TRANS(3);
DEFINE_CPU_TRANS(4);
DEFINE_CPU_TRANS(5);
DEFINE_CPU_TRANS(6);

struct TensorSetConstantCPU {
  TensorSetConstantCPU(framework::Tensor* tensor, float value)
      : tensor_(tensor), value_(value) {}
  template <typename T>
  void operator()() const {
    auto cpu = platform::CPUPlace();
    auto* begin = tensor_->mutable_data<T>(cpu);
    std::fill(begin, begin + tensor_->numel(), static_cast<T>(value_));
  }
  framework::Tensor* tensor_;
  float value_;
};

template <>
void set_constant_with_place<platform::CPUPlace>(
    const platform::DeviceContext& context, framework::Tensor* tensor,
    float value) {
  framework::VisitDataType(framework::ToDataType(tensor->type()),
                           TensorSetConstantCPU(tensor, value));
}

template <>
void set_constant_with_place<platform::CUDAPinnedPlace>(
    const platform::DeviceContext& context, framework::Tensor* tensor,
    float value) {
  framework::VisitDataType(framework::ToDataType(tensor->type()),
                           TensorSetConstantCPU(tensor, value));
}

struct TensorSetConstantWithPlace : public boost::static_visitor<void> {
  TensorSetConstantWithPlace(const platform::DeviceContext& context,
                             framework::Tensor* tensor, float value)
      : context_(context), tensor_(tensor), value_(value) {}

  template <typename Place>
  void operator()(Place place) const {
    set_constant_with_place<Place>(context_, tensor_, value_);
  }

  const platform::DeviceContext& context_;
  framework::Tensor* tensor_;
  float value_;
};

void set_constant(const platform::DeviceContext& context,
                  framework::Tensor* tensor, float value) {
  TensorSetConstantWithPlace func(context, tensor, value);
#ifdef PADDLE_WITH_CUDA
  tensor->place().apply_visitor(func);
#else
  func(platform::CPUPlace());
#endif
}

template <typename T>
struct RowwiseAdd<platform::CPUDeviceContext, T> {
  void operator()(const platform::CPUDeviceContext& context,
                  const framework::Tensor& input,
                  const framework::Tensor& vector, framework::Tensor* output) {
    auto in_dims = input.dims();
    auto size = input.numel() / in_dims[0];
    PADDLE_ENFORCE_EQ(vector.numel(), size);
    PADDLE_ENFORCE_EQ(output->dims(), in_dims);

    auto in = framework::EigenMatrix<T>::From(input);
    auto vec = framework::EigenVector<T>::Flatten(vector);
    auto out = framework::EigenMatrix<T>::From(*output);

    for (int64_t i = 0; i < in_dims[0]; ++i) {
      out.chip(i, 0) = in.chip(i, 0) + vec;
    }
  }
};

template struct RowwiseAdd<platform::CPUDeviceContext, float>;
template struct RowwiseAdd<platform::CPUDeviceContext, double>;

template struct ColwiseSum<platform::CPUDeviceContext, float>;
template struct ColwiseSum<platform::CPUDeviceContext, double>;
template struct ColwiseSum<platform::CPUDeviceContext, int>;
template struct ColwiseSum<platform::CPUDeviceContext, int64_t>;

template struct RowwiseSum<platform::CPUDeviceContext, float>;
template struct RowwiseSum<platform::CPUDeviceContext, double>;

template struct RowwiseMean<platform::CPUDeviceContext, float>;
template struct RowwiseMean<platform::CPUDeviceContext, double>;

}  // namespace math
}  // namespace operators
}  // namespace paddle
<commit_msg>fix a compile error<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/operators/math/math_function.h"
#include <vector>
#include "paddle/fluid/framework/data_type.h"
#include "paddle/fluid/operators/math/math_function_impl.h"
#include "paddle/fluid/platform/float16.h"

namespace paddle {
namespace operators {
namespace math {

using float16 = paddle::platform::float16;

template struct SetConstant<platform::CPUDeviceContext, platform::float16>;
template struct SetConstant<platform::CPUDeviceContext, float>;
template struct SetConstant<platform::CPUDeviceContext, double>;
template struct SetConstant<platform::CPUDeviceContext, int>;
template struct SetConstant<platform::CPUDeviceContext, int64_t>;
template struct SetConstant<platform::CPUDeviceContext, bool>;
template struct SetConstant<platform::CPUDeviceContext, uint8_t>;

#define DEFINE_CPU_TRANS(RANK)                                             \
  template struct Transpose<platform::CPUDeviceContext, platform::float16, \
                            RANK>;                                         \
  template struct Transpose<platform::CPUDeviceContext, float, RANK>;      \
  template struct Transpose<platform::CPUDeviceContext, double, RANK>;     \
  template struct Transpose<platform::CPUDeviceContext, int, RANK>;        \
  template struct Transpose<platform::CPUDeviceContext, int64_t, RANK>;    \
  template struct Transpose<platform::CPUDeviceContext, bool, RANK>;       \
  template struct Transpose<platform::CPUDeviceContext, int16_t, RANK>;    \
  template struct Transpose<platform::CPUDeviceContext, uint8_t, RANK>;

DEFINE_CPU_TRANS(1);
DEFINE_CPU_TRANS(2);
DEFINE_CPU_TRANS(3);
DEFINE_CPU_TRANS(4);
DEFINE_CPU_TRANS(5);
DEFINE_CPU_TRANS(6);

struct TensorSetConstantCPU {
  TensorSetConstantCPU(framework::Tensor* tensor, float value)
      : tensor_(tensor), value_(value) {}
  template <typename T>
  void operator()() const {
    auto cpu = platform::CPUPlace();
    auto* begin = tensor_->mutable_data<T>(cpu);
    std::fill(begin, begin + tensor_->numel(), static_cast<T>(value_));
  }
  framework::Tensor* tensor_;
  float value_;
};

template <>
void set_constant_with_place<platform::CPUPlace>(
    const platform::DeviceContext& context, framework::Tensor* tensor,
    float value) {
  framework::VisitDataType(framework::ToDataType(tensor->type()),
                           TensorSetConstantCPU(tensor, value));
}

template <>
void set_constant_with_place<platform::CUDAPinnedPlace>(
    const platform::DeviceContext& context, framework::Tensor* tensor,
    float value) {
  framework::VisitDataType(framework::ToDataType(tensor->type()),
                           TensorSetConstantCPU(tensor, value));
}

struct TensorSetConstantWithPlace : public boost::static_visitor<void> {
  TensorSetConstantWithPlace(const platform::DeviceContext& context,
                             framework::Tensor* tensor, float value)
      : context_(context), tensor_(tensor), value_(value) {}

  template <typename Place>
  void operator()(Place place) const {
    set_constant_with_place<Place>(context_, tensor_, value_);
  }

  const platform::DeviceContext& context_;
  framework::Tensor* tensor_;
  float value_;
};

void set_constant(const platform::DeviceContext& context,
                  framework::Tensor* tensor, float value) {
  TensorSetConstantWithPlace func(context, tensor, value);
#ifdef PADDLE_WITH_CUDA
  tensor->place().apply_visitor(func);
#else
  func(platform::CPUPlace());
#endif
}

template <typename T>
struct RowwiseAdd<platform::CPUDeviceContext, T> {
  void operator()(const platform::CPUDeviceContext& context,
                  const framework::Tensor& input,
                  const framework::Tensor& vector, framework::Tensor* output) {
    auto in_dims = input.dims();
    auto size = input.numel() / in_dims[0];
    PADDLE_ENFORCE_EQ(vector.numel(), size);
    PADDLE_ENFORCE_EQ(output->dims(), in_dims);

    auto in = framework::EigenMatrix<T>::From(input);
    auto vec = framework::EigenVector<T>::Flatten(vector);
    auto out = framework::EigenMatrix<T>::From(*output);

    for (int64_t i = 0; i < in_dims[0]; ++i) {
      out.chip(i, 0) = in.chip(i, 0) + vec;
    }
  }
};

template struct RowwiseAdd<platform::CPUDeviceContext, float>;
template struct RowwiseAdd<platform::CPUDeviceContext, double>;

template struct ColwiseSum<platform::CPUDeviceContext, float>;
template struct ColwiseSum<platform::CPUDeviceContext, double>;
template struct ColwiseSum<platform::CPUDeviceContext, int>;
template struct ColwiseSum<platform::CPUDeviceContext, int64_t>;

template struct RowwiseSum<platform::CPUDeviceContext, float>;
template struct RowwiseSum<platform::CPUDeviceContext, double>;

template struct RowwiseMean<platform::CPUDeviceContext, float>;
template struct RowwiseMean<platform::CPUDeviceContext, double>;

}  // namespace math
}  // namespace operators
}  // namespace paddle
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////////////////////
///
/// @file
/// @author     Kuba Sejdak
/// @date       21.08.2016
///
/// @copyright  This file is a part of cosmos OS. All rights reserved.
///
////////////////////////////////////////////////////////////////////////////////////////////////

#include "beaglebone_black.h"
#include "beaglebone_black_pinmux.h"

#include <core/console.h>
#include <dev/gpio.h>
#include <dev/ti_am335x/am335x_gpio.h>

using namespace Device;

namespace Board {

IBoard* IBoard::create()
{
    return new BeagleBoneBlack();
}

BeagleBoneBlack::BeagleBoneBlack()
{
    m_name = "BeagleBone Black";
    m_vendor = "Texas Instruments";
    m_version = "1.0";
}

bool BeagleBoneBlack::initDevice()
{
    // Initialize console on UART1.
    GPIOPin consoleTx(PIN_P9_24);
    consoleTx.setFunction(AM335X_PAD_FUNC_0);
    consoleTx.setDirection(GPIO_OUTPUT);

    GPIOPin consoleRx(PIN_P9_26);
    consoleRx.setFunction(AM335X_PAD_FUNC_0);
    consoleTx.setDirection(GPIO_INPUT);

    if (!console.init())
        return false;

    return true;
}

} // namespace Board
<commit_msg>board: Init user led0.<commit_after>////////////////////////////////////////////////////////////////////////////////////////////////
///
/// @file
/// @author     Kuba Sejdak
/// @date       21.08.2016
///
/// @copyright  This file is a part of cosmos OS. All rights reserved.
///
////////////////////////////////////////////////////////////////////////////////////////////////

#include "beaglebone_black.h"
#include "beaglebone_black_pinmux.h"

#include <core/console.h>
#include <dev/gpio.h>
#include <dev/ti_am335x/am335x_gpio.h>

using namespace Device;

namespace Board {

IBoard* IBoard::create()
{
    return new BeagleBoneBlack();
}

BeagleBoneBlack::BeagleBoneBlack()
{
    m_name = "BeagleBone Black";
    m_vendor = "Texas Instruments";
    m_version = "1.0";
}

bool BeagleBoneBlack::initDevice()
{
    // Init user led0.
    GPIOPin led0(PIN_USER_LED0);
    led0.setFunction(AM335X_PAD_FUNC_0);
    led0.setDirection(GPIO_OUTPUT);
    led0.setResistor(GPIO_RESISTOR_NONE);
    led0.write(true);

    // Init console on UART1.
    GPIOPin consoleTx(PIN_P9_24);
    consoleTx.setFunction(AM335X_PAD_FUNC_0);
    consoleTx.setDirection(GPIO_OUTPUT);

    GPIOPin consoleRx(PIN_P9_26);
    consoleRx.setFunction(AM335X_PAD_FUNC_0);
    consoleTx.setDirection(GPIO_INPUT);

    if (!console.init())
        return false;

    return true;
}

} // namespace Board
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 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
 *
 *****************************************************************************/

#ifndef MAPNIK_HARFBUZZ_SHAPER_HPP
#define MAPNIK_HARFBUZZ_SHAPER_HPP

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <unicode/uscript.h>
#pragma GCC diagnostic pop

namespace mapnik
{

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(), hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();
    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();

        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        // rendering information for a single glyph
        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };

        // this table is filled with information for rendering each glyph, so that
        // several font faces can be used in a single text_item
        std::size_t pos = 0;
        std::map<unsigned, std::vector<glyph_face_info>> glyphinfos;

        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
            hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            // https://github.com/mapnik/test-data-visual/pull/25

#if (HB_VERSION_MAJOR > 0 && HB_VERSION_ATLEAST(1, 0, 5))
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
#endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());
            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), &num_glyphs);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), &num_glyphs);

            unsigned cluster = 0;
            bool in_cluster = false;
            std::vector<unsigned> clusters;

            for (unsigned i = 0; i < num_glyphs; ++i)
            {
                if (i == 0)
                {
                    cluster = glyphs[0].cluster;
                    clusters.push_back(cluster);
                }
                if (cluster != glyphs[i].cluster)
                {
                    cluster = glyphs[i].cluster;
                    clusters.push_back(cluster);
                    in_cluster = false;
                }
                else if (i != 0)
                {
                    in_cluster = true;
                }

                // if we have a valid codepoint, save rendering info.

                auto itr = glyphinfos.find(cluster);
                if (itr == glyphinfos.end())
                {
                    std::vector<glyph_face_info> v = {{ face, glyphs[i], positions[i] }};
                    bool result = false;
                    std::tie(itr, result) = glyphinfos.insert(std::make_pair(cluster, v));

                }
                if (itr->second.front().glyph.codepoint == 0)
                {
                    itr->second.front() = { face, glyphs[i], positions[i] };
                }
                else if (in_cluster)
                {
                    itr->second.push_back({ face, glyphs[i], positions[i] });
                }
            }

            bool all_set = true;
            for (auto c : clusters)
            {
                auto itr = glyphinfos.find(c);
                if (itr == glyphinfos.end() || (!itr->second.empty() && itr->second.front().glyph.codepoint == 0))
                {
                    all_set = false;
                    break;
                }
            }
            if (!all_set && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }
            double max_glyph_height = 0;
            for (auto const& c : clusters)
            {
                auto itr = glyphinfos.find(c);
                if (itr != glyphinfos.end())
                {
                    for (auto const& info : itr->second)
                    {
                        face_ptr theface = face;
                        auto & gpos = info.position;
                        auto & glyph = info.glyph;
                        if (info.glyph.codepoint != 0)
                        {
                            theface = info.face;
                        }
                        unsigned char_index = glyph.cluster;
                        glyph_info g(glyph.codepoint,char_index,text_item.format_);
                        if (theface->glyph_dimensions(g))
                        {
                            g.face = theface;
                            g.scale_multiplier = size / theface->get_face()->units_per_EM;
                            //Overwrite default advance with better value provided by HarfBuzz
                            g.unscaled_advance = gpos.x_advance;
                            g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                            double tmp_height = g.height();
                            if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                            width_map[char_index] += g.advance();
                            line.add_glyph(std::move(g), scale_factor);
                        }
                    }
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<commit_msg>fix test logic<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 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
 *
 *****************************************************************************/

#ifndef MAPNIK_HARFBUZZ_SHAPER_HPP
#define MAPNIK_HARFBUZZ_SHAPER_HPP

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <unicode/uscript.h>
#pragma GCC diagnostic pop

namespace mapnik
{

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(), hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();
    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();

        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        // rendering information for a single glyph
        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };

        // this table is filled with information for rendering each glyph, so that
        // several font faces can be used in a single text_item
        std::size_t pos = 0;
        std::map<unsigned, std::vector<glyph_face_info>> glyphinfos;

        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
            hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            // https://github.com/mapnik/test-data-visual/pull/25

#if (HB_VERSION_MAJOR > 0 && HB_VERSION_ATLEAST(1, 0, 5))
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
#endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());
            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), &num_glyphs);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), &num_glyphs);

            unsigned cluster = 0;
            bool in_cluster = false;
            std::vector<unsigned> clusters;

            for (unsigned i = 0; i < num_glyphs; ++i)
            {
                if (i == 0)
                {
                    cluster = glyphs[0].cluster;
                    clusters.push_back(cluster);
                }
                if (cluster != glyphs[i].cluster)
                {
                    cluster = glyphs[i].cluster;
                    clusters.push_back(cluster);
                    in_cluster = false;
                }
                else if (i != 0)
                {
                    in_cluster = true;
                }

                // if we have a valid codepoint, save rendering info.

                auto itr = glyphinfos.find(cluster);
                if (itr == glyphinfos.end())
                {
                    std::vector<glyph_face_info> v = {{ face, glyphs[i], positions[i] }};
                    bool result = false;
                    std::tie(itr, result) = glyphinfos.insert(std::make_pair(cluster, v));

                }
                if (itr->second.front().glyph.codepoint == 0)
                {
                    itr->second.front() = { face, glyphs[i], positions[i] };
                }
                else if (in_cluster)
                {
                    itr->second.push_back({ face, glyphs[i], positions[i] });
                }
            }

            bool all_set = true;
            for (auto c : clusters)
            {
                auto itr = glyphinfos.find(c);
                if (itr == glyphinfos.end() || itr->second.empty() || (itr->second.front().glyph.codepoint == 0))
                {
                    all_set = false;
                    break;
                }
            }
            if (!all_set && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }
            double max_glyph_height = 0;
            for (auto const& c : clusters)
            {
                auto itr = glyphinfos.find(c);
                if (itr != glyphinfos.end())
                {
                    for (auto const& info : itr->second)
                    {
                        face_ptr theface = face;
                        auto & gpos = info.position;
                        auto & glyph = info.glyph;
                        if (info.glyph.codepoint != 0)
                        {
                            theface = info.face;
                        }
                        unsigned char_index = glyph.cluster;
                        glyph_info g(glyph.codepoint,char_index,text_item.format_);
                        if (theface->glyph_dimensions(g))
                        {
                            g.face = theface;
                            g.scale_multiplier = size / theface->get_face()->units_per_EM;
                            //Overwrite default advance with better value provided by HarfBuzz
                            g.unscaled_advance = gpos.x_advance;
                            g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                            double tmp_height = g.height();
                            if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                            width_map[char_index] += g.advance();
                            line.add_glyph(std::move(g), scale_factor);
                        }
                    }
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<|endoftext|>