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

canvas.cc

///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "canvas.hh"
#include "util/rectboundary.h"
#include <stdexcept>
#include <algorithm>
#include <functional>

xml2ps::Canvas::Canvas(const xml2ps::Canvas::PageVec& pages,
                   bool allow_extra_pages)
  :pages_(pages), cur_page_(0), allow_extra_pages_(allow_extra_pages),
   substitute_font_aliases(false)
{}

xml2ps::Canvas::~Canvas() {}

void xml2ps::Canvas::newPage() {
  PageVec::iterator op = cur_page_;
  if(cur_page_ == PageVec::iterator(0)) cur_page_ = pages_.begin();
  else ++cur_page_;
  
  if(cur_page_ == pages_.end()) {
    if(!allow_extra_pages_)
      throw OutOfPages();
    if(op == PageVec::iterator(0))
      throw std::runtime_error("No pages specified");
    cur_page_ = op;
  }
  
  cur_column = 0;
  vpos = height_ = cur_page_->height();
  margin = 0;
}

void xml2ps::Canvas::setfont(const font::FontInfo& font) {
  used_fonts.insert(font.getName());
}

const float& xml2ps::Canvas::down(const float& step) {
  vpos -= margin;
  margin = 0;
  return vpos -= step;
}
void xml2ps::Canvas::reserveHeight(const float& h, bool span) {
  if ((vpos - margin) < h) {
    if(++cur_column >= cur_page_->columns()) {
      newPage();
    } else
      vpos = height_;
  }
  if (span)
    height_ -= h;
}

void xml2ps::Canvas::addMargin(const float& m) {
  margin = std::max(margin, m);
}

namespace {
  
  class IntersectAdapter {
  public:
    IntersectAdapter(xml2ps::HBox& hb) : hbox(hb) {}
    
    void operator() (const Boundary o) {
      if(!o) return;
      const Polygon p = o->get_polygon();
      if(p.empty()) return;
      
      float y1 = hbox.top(), y2 = hbox.bottom(),
      x_left = hbox.left(), x_right = hbox.right();
      for(size_t i = 0; i < p.size(); ++i) {
      const Vector from(p[i]), to(p[(i+1)%p.size()]);
      float d_f1 = y1 - from.y, d_t1 = y1 - to.y;
      float d_f2 = y2 - from.y, d_t2 = y2 - to.y;
      if((d_f1 * d_t1 < 0) || (d_f2 * d_t2 < 0)) {
        // The line crosses the "extended baseline".
        float x1 = from.x + (to.x - from.x)/(to.y-from.y) * d_f1;
        float x2 = from.x + (to.x - from.x)/(to.y-from.y) * d_f2;
        
        if((d_f1 <= 0) || (d_f2 <= 0)) // Line goes "down"; left of obstacle
          x_left = std::max(x_left, std::max(x1, x2));
        if((d_f1 >= 0) || (d_f2 >= 0)) // Line goes "up"; right of obstacle
          x_right = std::min(x_right, std::min(x1, x2));
        
      }
      }
      // The obstacle is from x_left to x_right at this height
      const float leftside = x_left - hbox.left();
      const float rightside = hbox.right() - x_right;
      
      if(leftside < 0 || rightside < 0)
      return;
      
      if(leftside > rightside)
      hbox.inRight(rightside);
      else
      hbox.inLeft(leftside);
    }
  private:
    xml2ps::HBox& hbox;
  };
  
}

void
xml2ps::Canvas::addRelObstacle(const float left, const float bottom, 
                         const float right, const float top) {
  const float x0 = cur_page_->left(cur_column);
  cur_page_->addObstacle(RectBoundary::create
                   (Matrix::translation(x0+left, vpos-bottom),
                    x0+right, vpos-top));
}

00116 xml2ps::HBox xml2ps::Canvas::hbox(bool span, float margin_left,
                          float margin_right, 
                          float ascender, float descender) {
  const float minimum_width = 10.0;/// \todo Don't hardcode this!
  HBox result;
  do {
    reserveHeight(ascender + descender, span);
    const float left = cur_page_->left(cur_column);
    down(ascender);
    result = HBox(vpos, ascender, descender, 
              left, left + cur_page_->columnWidth(span),
              margin_left, margin_right);
    down(descender);
    
    for_each(cur_page_->obegin(), cur_page_->oend(), IntersectAdapter(result));
    
  } while(result.room() < minimum_width);
  
  return result;
}

Generated by  Doxygen 1.6.0   Back to index