Handle \n chars.

This commit is contained in:
Hermann Kraus 2012-07-29 23:24:24 +02:00
parent 66cbf45cd7
commit d6c8fe37a9
4 changed files with 77 additions and 13 deletions

View file

@ -29,6 +29,7 @@
// stl
#include <string>
#include <list>
#include <vector>
// ICU
#include <unicode/unistr.h>
@ -63,7 +64,13 @@ public:
void add_text(UnicodeString str, char_properties_ptr format);
std::list<text_item> const& itemize(unsigned start=0, unsigned end=0);
void clear();
UnicodeString const& get_text() { return text_; }
UnicodeString const& get_text() const { return text_; }
/** Returns the start and end position of a certain line.
*
* Only forced line breaks with \n characters are handled here.
*/
std::pair<unsigned, unsigned> get_line(unsigned i) const;
unsigned num_lines() const;
private:
template<typename T> struct run
{
@ -91,6 +98,7 @@ private:
void create_item_list();
std::list<text_item> output_;
template <typename T> typename T::const_iterator find_run(T const& list, unsigned position);
std::vector<unsigned> forced_line_breaks_; //Positions of \n characters
};
} //ns mapnik

View file

@ -65,6 +65,9 @@ public:
double line_height() const { return line_height_; }
void set_first_line(bool first_line);
unsigned get_first_char() const;
unsigned get_last_char() const;
private:
glyph_vector glyphs_;
double line_height_; //Includes line spacing (returned by freetype)
@ -97,7 +100,7 @@ public:
private:
void break_line(text_line_ptr line, double wrap_width, unsigned text_ratio);
void shape_text(text_line_ptr line, unsigned start, unsigned end);
void shape_text(text_line_ptr line);
void add_line(text_line_ptr line);
//input

View file

@ -33,7 +33,7 @@ namespace mapnik
text_itemizer::text_itemizer() : text_(), format_runs_(), direction_runs_(), script_runs_()
{
forced_line_breaks_.push_back(0);
}
void text_itemizer::add_text(UnicodeString str, char_properties_ptr format)
@ -41,6 +41,11 @@ void text_itemizer::add_text(UnicodeString str, char_properties_ptr format)
unsigned start = text_.length();
text_ += str;
format_runs_.push_back(format_run_t(format, start, text_.length()));
while ((start = text_.indexOf('\n', start)+1) > 0)
{
forced_line_breaks_.push_back(start);
}
}
std::list<text_item> const& text_itemizer::itemize(unsigned start, unsigned end)
@ -60,6 +65,26 @@ void text_itemizer::clear()
output_.clear();
text_.remove();
format_runs_.clear();
forced_line_breaks_.clear();
forced_line_breaks_.push_back(0);
}
std::pair<unsigned, unsigned> text_itemizer::get_line(unsigned i) const
{
#ifdef MAPNIK_DEBUG
if (i >= forced_line_breaks_.size()) return std::make_pair(0, 0);
#endif
if (i == forced_line_breaks_.size()-1)
{
return std::make_pair(forced_line_breaks_[i], text_.length());
}
//Note -1 offset to exclude the \n char
return std::make_pair(forced_line_breaks_[i], forced_line_breaks_[i+1]-1);
}
unsigned text_itemizer::num_lines() const
{
return forced_line_breaks_.size();
}
void text_itemizer::itemize_direction(unsigned start, unsigned end)

View file

@ -56,15 +56,19 @@ void text_layout::add_text(const UnicodeString &str, char_properties_ptr format)
void text_layout::layout(double wrap_width, unsigned text_ratio)
{
text_line_ptr line = boost::make_shared<text_line>(0, itemizer_.get_text().length());
shape_text(line, 0, itemizer_.get_text().length()); //Process full text
break_line(line, wrap_width, text_ratio); //Break line if neccessary
unsigned num_lines = itemizer_.num_lines();
for (unsigned i = 0; i < num_lines; i++)
{
std::pair<unsigned, unsigned> line_limits = itemizer_.get_line(i);
text_line_ptr line = boost::make_shared<text_line>(line_limits.first, line_limits.second);
shape_text(line);
break_line(line, wrap_width, text_ratio); //Break line if neccessary
}
}
void text_layout::break_line(text_line_ptr line, double wrap_width, unsigned text_ratio)
{
//TODO: Handle \n chars.
if (!wrap_width || line->width() < wrap_width)
{
add_line(line);
@ -77,6 +81,7 @@ void text_layout::break_line(text_line_ptr line, double wrap_width, unsigned tex
double string_width = line->width();
double string_height = line->line_height();
for (double i = 1.0; ((wrap_at = string_width/i)/(string_height*i)) > text_ratio && (string_width/i) > wrap_width; i += 1.0) ;
wrap_width = wrap_at;
}
UnicodeString const& text = itemizer_.get_text();
@ -88,7 +93,7 @@ void text_layout::break_line(text_line_ptr line, double wrap_width, unsigned tex
breakitr->setText(text);
unsigned current_line_length = 0;
unsigned last_break_position = 0;
for (unsigned i=0; i<text.length(); i++)
for (unsigned i=line->get_first_char(); i<line->get_last_char(); i++)
{
//TODO: Char spacing
std::map<unsigned, double>::const_iterator width_itr = width_map_.find(i);
@ -99,16 +104,21 @@ void text_layout::break_line(text_line_ptr line, double wrap_width, unsigned tex
if (current_line_length > wrap_width)
{
unsigned break_position = breakitr->preceding(i);
if (break_position <= last_break_position)
if (break_position <= last_break_position || break_position == BreakIterator::DONE)
{
//A single word is longer than the maximum line width.
//Violate line width requirement and choose next break position
break_position = breakitr->following(i);
std::cout << "Line overflow!\n";
if (break_position == BreakIterator::DONE)
{
break_position = line->get_last_char();
MAPNIK_LOG_WARN(text_layout) << "Unexpected result in break_line. Trying to recover...\n";
}
// std::cout << "Line overflow!\n";
}
std::cout << "Line to long ("<< current_line_length << ") at "<< i << " going to " << break_position << ". Last break was at " << last_break_position << "\n";
// std::cout << "Line to long ("<< current_line_length << ") at "<< i << " going to " << break_position << ". Last break was at " << last_break_position << "\n";
text_line_ptr new_line = boost::make_shared<text_line>(last_break_position, break_position);
shape_text(new_line, last_break_position, break_position);
shape_text(new_line);
add_line(new_line);
last_break_position = break_position;
i = break_position - 1;
@ -116,10 +126,18 @@ void text_layout::break_line(text_line_ptr line, double wrap_width, unsigned tex
current_line_length = 0;
}
}
if (last_break_position != line->get_last_char())
{
text_line_ptr new_line = boost::make_shared<text_line>(last_break_position, line->get_last_char());
shape_text(new_line);
add_line(new_line);
}
}
void text_layout::shape_text(text_line_ptr line, unsigned start, unsigned end)
void text_layout::shape_text(text_line_ptr line)
{
unsigned start = line->get_first_char();
unsigned end = line->get_last_char();
UnicodeString const& text = itemizer_.get_text();
size_t length = end - start;
@ -260,4 +278,14 @@ void text_line::set_first_line(bool first_line)
first_line_ = first_line;
}
unsigned text_line::get_first_char() const
{
return first_char_;
}
unsigned text_line::get_last_char() const
{
return last_char_;
}
} //ns mapnik