+int Row::left_x() const
+{
+ double x = left_margin;
+ const_iterator const end = elements_.end();
+ const_iterator cit = elements_.begin();
+ while (cit != end && cit->isVirtual()) {
+ x += cit->full_width();
+ ++cit;
+ }
+ return int(x + 0.5);
+}
+
+
+int Row::right_x() const
+{
+ double x = dim_.wid;
+ const_iterator const begin = elements_.begin();
+ const_iterator cit = elements_.end();
+ while (cit != begin) {
+ --cit;
+ if (cit->isVirtual())
+ x -= cit->full_width();
+ else
+ break;
+ }
+ return int(x + 0.5);
+}
+
+
+int Row::countSeparators() const
+{
+ int n = 0;
+ const_iterator const end = elements_.end();
+ for (const_iterator cit = elements_.begin() ; cit != end ; ++cit)
+ n += cit->countSeparators();
+ return n;
+}
+
+
+bool Row::setExtraWidth(int w)
+{
+ if (w < 0)
+ // this is not expected to happen (but it does)
+ return false;
+ // amount of expansion: number of expanders time the em value for each
+ // string element
+ int exp_amount = 0;
+ for (Row::Element const & e : elements_)
+ exp_amount += e.expansionAmount();
+ if (!exp_amount)
+ return false;
+ // extra length per expander per em
+ double extra_per_em = double(w) / exp_amount;
+ if (extra_per_em > MAX_SPACE_STRETCH)
+ // do not stretch more than MAX_SPACE_STRETCH em per expander
+ return false;
+ // add extra length to each element proportionally to its em.
+ for (Row::Element & e : elements_)
+ if (e.type == Row::STRING)
+ e.setExtra(extra_per_em);
+ // update row dimension
+ dim_.wid += w;
+ return true;
+}
+
+