int Row::Element::countExpanders() const
{
- if (type != STRING)
+ if (type != STRING || font.fontInfo().family() == TYPEWRITER_FAMILY)
return 0;
return support::countExpanders(str);
}
int Row::Element::expansionAmount() const
{
- if (type != STRING)
+ if (type != STRING || font.fontInfo().family() == TYPEWRITER_FAMILY)
return 0;
return countExpanders() * theFontMetrics(font).em();
}
void Row::Element::setExtra(double extra_per_em)
{
- if (type != STRING)
+ if (type != STRING || font.fontInfo().family() == TYPEWRITER_FAMILY)
return;
extra = extra_per_em * theFontMetrics(font).em();
}
}
-bool Row::Element::splitAt(int const width, int next_width, bool force,
+bool Row::Element::splitAt(int const width, int next_width, SplitType split_type,
Row::Elements & tail)
{
// Not a string or already OK.
bool const wrap_any = !font.language()->wordWrap();
FontMetrics::Breaks breaks = fm.breakString(str, width, next_width,
- isRTL(), wrap_any | force);
+ isRTL(), wrap_any || split_type == FORCE);
/** if breaking did not really work, give up
- * case 1: we do not force break and the first element is longer than the limit;
+ * case 1: split type is FIT and the first element is longer than the limit;
* case 2: the first break occurs at the front of the string
*/
- if ((!force && breaks.front().nspc_wid > width)
+ if ((split_type == FIT && breaks.front().nspc_wid > width)
|| (breaks.size() > 1 && breaks.front().len == 0)) {
if (dim.wid == 0)
dim.wid = fm.width(str);
}
+// FIXME: remove this and move the changebar update to Row::push_back()
void Row::finalizeLast()
{
if (elements_.empty())
}
-Row::Elements Row::shortenIfNeeded(int const w, int const next_width)
+Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
{
// FIXME: performance: if the last element is a string, we would
// like to avoid computing its length.
finalizeLast();
- if (empty() || width() <= w)
+ if (empty() || width() <= max_width)
return Elements();
Elements::iterator const beg = elements_.begin();
Elements::iterator const end = elements_.end();
int wid = left_margin;
+ // the smallest row width we know we can achieve by breaking a string.
+ int min_row_wid = dim_.wid;
// Search for the first element that goes beyond right margin
Elements::iterator cit = beg;
for ( ; cit != end ; ++cit) {
- if (wid + cit->dim.wid > w)
+ if (wid + cit->dim.wid > max_width)
break;
wid += cit->dim.wid;
}
--cit_brk;
// make a copy of the element to work on it.
Element brk = *cit_brk;
- /* If the current element is an inset that allows breaking row
- * after itself, and if the row is already short enough after
- * this element, then cut right after it.
+ /* If the current element allows breaking row after itself,
+ * and if the row is already short enough after this element,
+ * then cut right after it.
*/
- if (wid_brk <= w && brk.row_flags & CanBreakAfter) {
+ if (wid_brk <= max_width && brk.row_flags & CanBreakAfter) {
end_ = brk.endpos;
dim_.wid = wid_brk;
moveElements(elements_, cit_brk + 1, tail);
}
// assume now that the current element is not there
wid_brk -= brk.dim.wid;
- /* If the current element is an inset that allows breaking row
- * before itself, and if the row is already short enough before
- * this element, then cut right before it.
+ /* If the current element allows breaking row before itself,
+ * and if the row is already short enough before this element,
+ * then cut right before it.
*/
- if (wid_brk <= w && brk.row_flags & CanBreakBefore && cit_brk != beg) {
+ if (wid_brk <= max_width && brk.row_flags & CanBreakBefore && cit_brk != beg) {
end_ = (cit_brk -1)->endpos;
dim_.wid = wid_brk;
moveElements(elements_, cit_brk, tail);
* - shorter than the natural width of the element, in order to enforce
* break-up.
*/
- if (brk.splitAt(min(w - wid_brk, brk.dim.wid - 2), next_width, false, tail)) {
+ int const split_width = min(max_width - wid_brk, brk.dim.wid - 2);
+ if (brk.splitAt(split_width, next_width, BEST_EFFORT, tail)) {
/* if this element originally did not cause a row overflow
* in itself, and the remainder of the row would still be
* too large after breaking, then we will have issues in
- * next row. Thus breaking does not help.
+ * next row. Thus breaking here does not help.
*/
- if (wid_brk + cit_brk->dim.wid < w
- && dim_.wid - (wid_brk + brk.dim.wid) >= next_width) {
+ if (wid_brk + cit_brk->dim.wid < max_width
+ && min_row_wid - (wid_brk + brk.dim.wid) >= next_width) {
tail.clear();
break;
}
+ /* if we did not manage to fit a part of the element into
+ * the split_width limit, at least remember that we can
+ * shorten the row if needed.
+ */
+ if (brk.dim.wid > split_width) {
+ min_row_wid = wid_brk + brk.dim.wid;
+ tail.clear();
+ continue;
+ }
+ // We have found a proper place where to break this string element.
end_ = brk.endpos;
*cit_brk = brk;
dim_.wid = wid_brk + brk.dim.wid;
* shorten the row. Let's try to break it again, but force
* splitting this time.
*/
- if (cit->splitAt(w - wid, next_width, true, tail)) {
+ if (cit->splitAt(max_width - wid, next_width, FORCE, tail)) {
end_ = cit->endpos;
dim_.wid = wid + cit->dim.wid;
// If there are other elements, they should be removed.
* to accept virtual elements, in which case the position
* will be before the virtual element.
*/
- if (cit->isVirtual() && pos + boundary_corr == cit->pos)
- break;
- else if (pos + boundary_corr >= cit->pos
- && pos + boundary_corr < cit->endpos) {
+ if ((pos + boundary_corr >= cit->pos && pos + boundary_corr < cit->endpos)
+ || (cit->isVirtual() && pos + boundary_corr == cit->pos)) {
+ // FIXME: shall we use `pos + boundary_corr' here?
x += cit->pos2x(pos);
break;
}