+
+ return w;
+}
+
+
+pos_type Row::Element::x2pos(int &x) const
+{
+ //lyxerr << "x2pos: x=" << x << " w=" << width() << " " << *this;
+ size_t i = 0;
+
+ switch (type) {
+ case STRING: {
+ FontMetrics const & fm = theFontMetrics(font);
+ i = fm.x2pos(str, x, isRTL(), extra);
+ break;
+ }
+ case VIRTUAL:
+ // those elements are actually empty (but they have a width)
+ i = 0;
+ x = isRTL() ? int(full_width()) : 0;
+ break;
+ case INSET:
+ case SPACE:
+ case MARGINSPACE:
+ // those elements contain only one position. Round to
+ // the closest side.
+ if (x > (full_width() + 1) / 2) {
+ x = int(full_width());
+ i = !isRTL();
+ } else {
+ x = 0;
+ i = isRTL();
+ }
+ }
+ //lyxerr << "=> p=" << pos + i << " x=" << x << endl;
+ return pos + i;
+}
+
+
+bool Row::Element::splitAt(int const width, int next_width, bool force,
+ Row::Elements & tail)
+{
+ // Not a string or already OK.
+ if (type != STRING || (dim.wid > 0 && dim.wid < width))
+ return false;
+
+ FontMetrics const & fm = theFontMetrics(font);
+
+ // A a string that is not breakable
+ if (!(row_flags & CanBreakInside)) {
+ // has width been computed yet?
+ if (dim.wid == 0)
+ dim.wid = fm.width(str);
+ return false;
+ }
+
+ bool const wrap_any = !font.language()->wordWrap();
+ FontMetrics::Breaks breaks = fm.breakString(str, width, next_width,
+ isRTL(), wrap_any | force);
+
+ // if breaking did not really work, give up
+ if (!force && breaks.front().nspc_wid > width) {
+ if (dim.wid == 0)
+ dim.wid = fm.width(str);
+ return false;
+ }
+
+ Element first_e(STRING, pos, font, change);
+ // should next element eventually replace *this?
+ bool first = true;
+ docstring::size_type i = 0;
+ for (FontMetrics::Break const & brk : breaks) {
+ /* For some reason breakString can decide to break before the
+ * first character (normally we use a 0-width nbsp to prevent
+ * that). Skip leading empty elements, they are never wanted.
+ */
+ if (first && brk.len == 0 && breaks.size() > 1)
+ continue;
+ Element e(STRING, pos + i, font, change);
+ e.str = str.substr(i, brk.len);
+ e.endpos = e.pos + brk.len;
+ e.dim.wid = brk.wid;
+ e.nspc_wid = brk.nspc_wid;
+ e.row_flags = CanBreakInside | BreakAfter;
+ if (first) {
+ // this element eventually goes to *this
+ e.row_flags |= row_flags & ~AfterFlags;
+ first_e = e;
+ first = false;
+ } else
+ tail.push_back(e);
+ i += brk.len;
+ }
+
+ if (!tail.empty()) {
+ // Avoid having a last empty element. This happens when
+ // breaking at the trailing space of string
+ if (tail.back().str.empty())
+ tail.pop_back();
+ else {
+ // Copy the after flags of the original element to the last one.
+ tail.back().row_flags &= ~BreakAfter;
+ tail.back().row_flags |= row_flags & AfterFlags;
+ }
+ // first_e row should be broken after the original element
+ first_e.row_flags |= BreakAfter;
+ } else {
+ // Restore the after flags of the original element.
+ first_e.row_flags &= ~BreakAfter;
+ first_e.row_flags |= row_flags & AfterFlags;
+ }
+
+ // update ourselves
+ swap(first_e, *this);
+ return true;
+}
+
+
+void Row::Element::rtrim()
+{
+ if (type != STRING)
+ return;
+ /* This is intended for strings that have been created by splitAt.
+ * They may have trailing spaces, but they are not counted in the
+ * string length (QTextLayout feature, actually). We remove them,
+ * and decrease endpos, since spaces at row break are invisible.
+ */
+ str = support::rtrim(str);
+ endpos = pos + str.length();
+ dim.wid = nspc_wid;
+}
+
+
+bool Row::isMarginSelected(bool left, DocIterator const & beg,
+ DocIterator const & end) const
+{
+ pos_type const sel_pos = left ? sel_beg : sel_end;
+ pos_type const margin_pos = left ? pos_ : end_;
+
+ // Is there a selection and is the chosen margin selected ?
+ if (!selection() || sel_pos != margin_pos)
+ return false;
+ else if (beg.pos() == end.pos())
+ // This is a special case in which the space between after
+ // pos i-1 and before pos i is selected, i.e. the margins
+ // (see DocIterator::boundary_).
+ return beg.boundary() && !end.boundary();
+ else if (end.pos() == margin_pos)
+ // If the selection ends around the margin, it is only
+ // drawn if the cursor is after the margin.
+ return !end.boundary();
+ else if (beg.pos() == margin_pos)
+ // If the selection begins around the margin, it is
+ // only drawn if the cursor is before the margin.
+ return beg.boundary();
+ else
+ return true;