Handle \n chars.
This commit is contained in:
parent
66cbf45cd7
commit
d6c8fe37a9
4 changed files with 77 additions and 13 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue