Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

typesetter.cc

///
// Copyright (C) 2003, 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "typesetter.hh"
#include <libxml++/libxml++.h>
#include <util/stringutil.h>
#include "line.hh"
#include "paragraph.hh"
#include "pscanvas.hh"
#include "pdfcanvas.hh"
#include "xcanvas.hh"
#include "blockcontainer.hh"

namespace {
  class ParserError: public xmlpp::exception
  {
  public:
    ParserError(std::string s) : xmlpp::exception(s) {}
    virtual ~ParserError() throw () {};
    virtual void Raise() const {throw *this;}
    virtual ParserError * Clone() const {return new ParserError(*this);}
  };
}

xml2ps::PsConverter::PsConverter(xml2ps::Canvas& output)
  : out(output), root(out), node(&root)
{}

xml2ps::PsConverter::~PsConverter() {}

void xml2ps::PsConverter::on_start_element(const std::string& n, 
                           const xmlpp::SaxParser::AttributeList &p) {
      // remember which element we are in, for better error messages:
      element_stack.push_back(n);
      try {
      xml2ps::Element* newnode;
      if (n == "para") {
        newnode = new xml2ps::Paragraph(out, *node, n, p);
      } else if (n == "font") {
        newnode = new xml2ps::TextContainer(*node, n, p);
      } else if (n == "bp") {
        newnode = new xml2ps::BreakPoint(*node);
      } else if (n == "leader") {
        newnode = new xml2ps::LeaderNode(*node, p);
      } else if (n == "obstacle") {
        newnode = new xml2ps::ObstacleNode(*node, p);
      } else if (n == "block-container") {
        newnode = new xml2ps::BlockContainer(out, *node, n, p);
      } else if (n == "linebreak") {
        newnode = new xml2ps::LineBreak(*node);
      } else if (n == "pagebreak") {
        newnode = new xml2ps::PageBreak(*node, out);
      } else if (n == "pagenum") {
        newnode = new xml2ps::PageNum(*node, p);
      } else {
        throw ParserError("element <" + n + "> is unknown");
      }
      node->add(newnode);
      node = newnode;
      
      } catch(const xmlpp::exception& err) {
      throw;
      
      } catch(const std::exception& err) {
      throw(ParserError("open <" + n + "> - " + err.what()));
      }
    }
void xml2ps::PsConverter::on_end_element(const std::string &n) {
      try {      
      node->close();
      node = &node->getParent();
      
      } catch(const xmlpp::exception& err) {
      throw;
      
      } catch(const std::exception& err) {
      throw(ParserError("close <" + n + "> - " + err.what()));

      } catch(const Glib::Error& err) { // Glib::Error is not a
                              // std::exception :-(
      throw(ParserError("close <" + n + "> - " + err.what()));
      }
      if(!element_stack.empty())
      element_stack.pop_back();
    }
void xml2ps::PsConverter::on_cdata_block(const std::string& s) {
  on_characters(s);
}
void xml2ps::PsConverter::on_characters(const std::string& s) {
      try {
      using xml2ps::TextContainer;
      if(TextContainer* tc = dynamic_cast<TextContainer*>(node)) {
        tc->add(s);
      } else {
        if(strip_whitespace(s).length() > 0) {/// \todo unicode
          if(!element_stack.empty()) {
            std::cerr << "ignored text inside <" 
                  << element_stack.back()
                  << ">: \"" << s << '"' << std::endl;
          }
        }
      }
      } catch(const xmlpp::exception& err) {
      throw;
      
      } catch(const std::exception& err) {
      throw(ParserError("parsing text inside <" + element_stack.back()
                     + "> - " + err.what()));
      }
    
    }
void xml2ps::PsConverter::on_warning(const std::string &s) {
      if(!element_stack.empty())
      std::cerr << "inside <" << element_stack.back() << "> - ";
      std::cerr << s << std::endl;
    }
void xml2ps::PsConverter::on_error(const std::string &s) {
      std::string tmp;
      if(!element_stack.empty())
      tmp = "inside <" + element_stack.back() + "> - ";
      throw(ParserError(tmp + s));
    }
void xml2ps::PsConverter::on_fatal_error(const std::string &s) {on_error(s);}

namespace xml2ps {
  Typesetter::~Typesetter() {
  }

  void Typesetter::addPage(const PageBoundary &page_boundary) {
    pages.push_back(page_boundary);
  }

  void Typesetter::addObstacle(Boundary obstacle) {
    if(pages.size())
      pages.back().addObstacle(obstacle);
    else {
      throw std::runtime_error("Obstacle before page boundary"
                         " is not allowed");
    }
  }

  void Typesetter::run(std::istream &input, std::ostream &output) {
    PDF::Document::Ptr pdfdoc;
    std::auto_ptr<xml2ps::Canvas> out;
    
    switch(output_format) {
    case FORMAT_PS:
      out.reset(new xml2ps::PsCanvas(pages, extra_pages));
      break;
    case FORMAT_PDF:
      pdfdoc = PDF::Document::create();
      out.reset(new xml2ps::PDFCanvas(pdfdoc, PDFCanvas::Pages, 
                              pages, extra_pages));
      break;
    case FORMAT_X:
      out.reset(new xml2ps::XCanvas(pages, extra_pages));
      break;
    default:
      throw std::runtime_error("Uncaught output format");
      break;
    }

      out->setSubstituteFontAliases(subst_font_aliases);
      PsConverter parser(*out);
      parser.parse_stream(input);
      out->closePage();
      used_fonts = out->getUsedFonts();
      switch(output_format) {
      case FORMAT_PS:
      dynamic_cast<PsCanvas*>(out.operator->())->merge(output);
      break;
      
      case FORMAT_PDF:
      pdfdoc->write(output);
      break;
      
      default: break;
      }
  }
};

Generated by  Doxygen 1.6.0   Back to index