/// // Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING /// #include "line.hh" xml2ps::Line::Line(const Element& elem, Canvas& o, float line_h, bool span, float margin_left, float margin_right) : out(o), hbox(out.hbox(span, margin_left, margin_right, elem.getFont().getAscender()*line_h, elem.getFont().getDescender()*line_h)), text_width(0), space_width(0), element(elem), first_node(0), last_node(0), line_height(line_h), spancolumns(span), m_left(margin_left), m_right(margin_right) {} xml2ps::Line::~Line() {} bool xml2ps::Line::add(xml2ps::Node* node) { // Container Elements must be split into pieces, or the // width calculations might go wrong: if(const Element* element = dynamic_cast(node)) if(element->begin() != element->end()) return false; if(dynamic_cast(last_node)) { // kill whitespace after line break return dynamic_cast(node); } bool force = !first_node; if(force) first_node = node; float twidth = node->getWidth(); if(dynamic_cast(node)) { last_node = node; space_width += twidth; return true; } else { // This is a factor, not a width in points or something ... const float max_wordspace = 4.0; /// \todo read this number somewhere! const float min_wordspace = 0.5; /// \todo Also configurable ... const float sw(((hbox.room() - text_width) / space_width) > max_wordspace ? space_width * min_wordspace : space_width); if (force || text_width + sw + twidth <= hbox.room()) { last_node = node; text_width += twidth; return true; } else return false; } } void xml2ps::Line::flush(bool is_last) { TextNode* hyphen = 0; bool is_linebreak = dynamic_cast(last_node); if(last_node && dynamic_cast(last_node)) { // hex 2D is a hyphen or minus according to unicode // and is a hyphen in the Adobe standard encoding // other unicode hyphenoids (hex): // 2010 - hyphen // 2011 - non-breaking hyphen // 2012 - figure dash // 2013 - en dash // 2212 - minus sign hyphen = new TextNode(last_node->getParent(), Glib::ustring(Glib::ustring::size_type(1), gunichar(0x2D))); text_width += hyphen->getWidth(); } while(last_node && last_node != first_node && dynamic_cast(last_node)) { space_width -= last_node->getWidth(); last_node = last_node->nodeBefore(); } Element::Align align = element.getAlign(); const float hpos = ((align == Element::center) ? ((hbox.right()+hbox.left())/2 - (text_width+space_width)/2) :((align == Element::right) ? hbox.right() - text_width - space_width : hbox.left())); const float max_wsw = 3; /// \todo Get from attribute float wsw = ((!is_last && !is_linebreak && align == Element::justify) ? (space_width > 0 ? ((hbox.room() - text_width) / space_width) : max_wsw + 1) // or maxfloat, or whatever ... : 1); // increase character spacing if necessary: float charw = 0; if(wsw > max_wsw) { Element::CharSpaceCount count = element.countChars(first_node, last_node); wsw = max_wsw; float desired_text_width = hbox.room() - space_width * wsw; if(count.first > 1) charw = (desired_text_width - text_width) / (count.first - 1 + count.second * wsw); } out.moveto(hpos, hbox.baseline()); element.printPart(out, first_node, last_node, wsw, charw); first_node = last_node = 0; text_width = space_width = 0; if(hyphen) { out.show(hyphen->getContent()); delete hyphen; } if(!is_last) hbox = out.hbox(spancolumns, m_left, m_right, element.getFont().getAscender() * line_height, element.getFont().getDescender() * line_height); }