diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc index 2fead24..31d2cf0 100644 --- a/lily/constrained-breaking.cc +++ b/lily/constrained-breaking.cc @@ -525,4 +525,8 @@ Line_details::Line_details (Prob *pb, Output_def *paper) title_ = to_boolean (pb->get_property ("is-title")); compressed_lines_count_ = 1; compressed_nontitle_lines_count_ = title_ ? 0 : 1; + SCM last_scm = pb->get_property ("last-markup-line"); + last_markup_line_ = to_boolean (last_scm); + SCM first_scm = pb->get_property ("first-markup-line"); + first_markup_line_ = to_boolean (first_scm); } diff --git a/lily/include/constrained-breaking.hh b/lily/include/constrained-breaking.hh index bb8a1d0..f36ab74 100644 --- a/lily/include/constrained-breaking.hh +++ b/lily/include/constrained-breaking.hh @@ -52,6 +52,8 @@ struct Line_details { class. */ int compressed_lines_count_; int compressed_nontitle_lines_count_; + bool last_markup_line_; + bool first_markup_line_; Line_details () { @@ -71,6 +73,8 @@ struct Line_details { title_ = false; compressed_lines_count_ = 1; compressed_nontitle_lines_count_ = 1; + last_markup_line_ = false; + first_markup_line_ = false; } Line_details (Prob *pb, Output_def *paper); diff --git a/lily/include/page-breaking.hh b/lily/include/page-breaking.hh index 2e5283d..d497d49 100644 --- a/lily/include/page-breaking.hh +++ b/lily/include/page-breaking.hh @@ -127,6 +127,7 @@ public: bool too_few_lines (int line_count) const; Real min_whitespace_at_top_of_page (Line_details const&) const; Real min_whitespace_at_bottom_of_page (Line_details const&) const; + int orphan_penalty () const; protected: Paper_book *book_; @@ -179,6 +180,7 @@ private: int max_systems_per_page_; int min_systems_per_page_; vsize system_count_; + int orphan_penalty_; vector current_configurations_; vector current_chunks_; diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index e0a08c0..dc71659 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -174,6 +174,7 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break) systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("systems-per-page"), 0)); max_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("max-systems-per-page"), 0)); min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0)); + orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000); if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_)) { @@ -1415,3 +1416,9 @@ Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const // FIXME: take into account the height of the footer return max (0.0, max (padding, min_distance + line.extent_[DOWN])); } + +int +Page_breaking::orphan_penalty () const +{ + return orphan_penalty_; +} diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc index 8919257..8dbf183 100644 --- a/lily/page-spacing.cc +++ b/lily/page-spacing.cc @@ -245,6 +245,18 @@ Page_spacer::calc_subproblem (vsize page, vsize line) penalty += lines_[page_start-1].page_penalty_ + (page % 2 == 0) ? lines_[page_start-1].turn_penalty_ : 0; + /* Deal with widow/orphan lines */ + /* Last line of paragraph is first line on the new page */ + if ((page_start > 0) && + (page_start < lines_.size ()) && + (lines_[page_start].last_markup_line_)) + penalty += breaker_->orphan_penalty (); + /* First line of paragraph is last line on the previous page */ + if ((page_start > 0) && + (page_start < lines_.size ()) && + (lines_[page_start-1].first_markup_line_)) + penalty += breaker_->orphan_penalty (); + demerits += penalty; if (demerits < cur.demerits_ || page_start == line) { diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 79896e6..f1ee2ec 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -516,15 +516,20 @@ Paper_book::get_system_specs () paper_->self_scm (), page_properties, scm_car (s)); - for (SCM list = texts ; scm_is_pair (list) ; list = scm_cdr (list)) + Prob *ps; + SCM list; + for (list = texts ; scm_is_pair (list) ; list = scm_cdr (list)) { SCM t = scm_car (list); // TODO: init props - Prob *ps = make_paper_system (SCM_EOL); + ps = make_paper_system (SCM_EOL); ps->set_property ("page-break-permission", ly_symbol2scm ("allow")); ps->set_property ("page-turn-permission", ly_symbol2scm ("allow")); + ps->set_property ("last-markup-line", SCM_BOOL_F); + ps->set_property ("first-markup-line", + list == texts? SCM_BOOL_T : SCM_BOOL_F); paper_system_set_stencil (ps, *unsmob_stencil (t)); ps->set_property ("is-title", SCM_BOOL_T); @@ -544,6 +549,18 @@ Paper_book::get_system_specs () // FIXME: figure out penalty. //set_system_penalty (ps, scores_[i].header_); } + // We may want to place a check here, for whether the line is too short + if (list == texts) + { + // if there is only one line in the paragraph, + // do not try to avoid orphans + ps->set_property ("last-markup-line", SCM_BOOL_F); + ps->set_property ("first-markup-line", SCM_BOOL_F); + } + else + { + ps->set_property ("last-markup-line", SCM_BOOL_T); + } } else assert (0);