2006-12-29 23:54:48 +00:00
|
|
|
/**
|
2007-04-26 04:41:58 +00:00
|
|
|
* \file Paragraph.cpp
|
2006-12-29 23:54:48 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
|
|
|
* \author Asger Alstrup
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author Lars Gullik Bjønnes
|
2006-12-29 23:54:48 +00:00
|
|
|
* \author Jean-Marc Lasgouttes
|
|
|
|
* \author Angus Leeming
|
|
|
|
* \author John Levon
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author André Pönitz
|
2006-12-29 23:54:48 +00:00
|
|
|
* \author Dekel Tsur
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author Jürgen Vigna
|
2006-12-29 23:54:48 +00:00
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "ParagraphMetrics.h"
|
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Buffer.h"
|
|
|
|
#include "BufferParams.h"
|
2007-08-28 15:33:15 +00:00
|
|
|
#include "BufferView.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Counters.h"
|
|
|
|
#include "Encoding.h"
|
|
|
|
#include "Language.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
#include "LaTeXFeatures.h"
|
2007-09-29 20:02:32 +00:00
|
|
|
#include "Layout.h"
|
2007-04-29 18:17:15 +00:00
|
|
|
#include "Font.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "LyXRC.h"
|
|
|
|
#include "Row.h"
|
|
|
|
#include "OutputParams.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
#include "sgml.h"
|
2007-11-07 23:25:08 +00:00
|
|
|
#include "TextClass.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "TexRow.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
#include "frontends/FontMetrics.h"
|
|
|
|
|
2007-04-25 01:24:38 +00:00
|
|
|
#include "insets/InsetBibitem.h"
|
2010-06-04 22:44:58 +00:00
|
|
|
#include "insets/InsetArgument.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
|
2008-04-30 08:26:40 +00:00
|
|
|
#include "support/lassert.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
#include "support/debug.h"
|
2013-04-25 21:27:10 +00:00
|
|
|
#include "support/ExceptionMessage.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
#include "support/gettext.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
#include "support/lstrings.h"
|
|
|
|
#include "support/textutils.h"
|
|
|
|
|
2010-04-22 11:16:58 +00:00
|
|
|
#include "support/bind.h"
|
2007-01-06 11:12:24 +00:00
|
|
|
#include <boost/crc.hpp>
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <list>
|
|
|
|
#include <stack>
|
|
|
|
#include <sstream>
|
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2007-12-12 18:57:56 +00:00
|
|
|
using namespace lyx::support;
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
namespace lyx {
|
|
|
|
|
|
|
|
|
2008-02-24 15:44:11 +00:00
|
|
|
ParagraphMetrics::ParagraphMetrics(Paragraph const & par) :
|
|
|
|
position_(-1), par_(&par)
|
|
|
|
{}
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
|
2007-01-06 09:15:59 +00:00
|
|
|
ParagraphMetrics & ParagraphMetrics::operator=(
|
|
|
|
ParagraphMetrics const & pm)
|
|
|
|
{
|
|
|
|
rows_ = pm.rows_;
|
|
|
|
dim_ = pm.dim_;
|
|
|
|
par_ = pm.par_;
|
2007-09-11 16:04:10 +00:00
|
|
|
position_ = pm.position_;
|
2007-01-06 09:15:59 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-27 14:04:46 +00:00
|
|
|
void ParagraphMetrics::reset(Paragraph const & par)
|
|
|
|
{
|
|
|
|
par_ = ∥
|
|
|
|
dim_ = Dimension();
|
2007-09-11 16:04:10 +00:00
|
|
|
//position_ = -1;
|
2007-08-27 14:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-17 11:27:03 +00:00
|
|
|
size_t ParagraphMetrics::computeRowSignature(Row const & row,
|
|
|
|
BufferParams const & bparams) const
|
2007-01-06 09:15:59 +00:00
|
|
|
{
|
|
|
|
boost::crc_32_type crc;
|
|
|
|
for (pos_type i = row.pos(); i < row.endpos(); ++i) {
|
|
|
|
char_type const b[] = { par_->getChar(i) };
|
2007-11-18 23:46:15 +00:00
|
|
|
crc.process_bytes(b, sizeof(char_type));
|
2014-03-29 22:52:36 +00:00
|
|
|
if (bparams.track_changes) {
|
2007-08-28 22:44:09 +00:00
|
|
|
Change change = par_->lookupChange(i);
|
2012-01-07 18:29:07 +00:00
|
|
|
char_type const b[] = { static_cast<char_type>(change.type) };
|
2007-11-18 21:47:46 +00:00
|
|
|
// 1 byte is enough to encode Change::Type
|
2007-08-28 22:44:09 +00:00
|
|
|
crc.process_bytes(b, 1);
|
2014-11-14 10:13:38 +00:00
|
|
|
}
|
2007-01-06 09:15:59 +00:00
|
|
|
}
|
2007-11-17 11:27:03 +00:00
|
|
|
|
|
|
|
Dimension const & d = row.dimension();
|
2012-01-07 18:29:07 +00:00
|
|
|
char_type const b[] = { static_cast<char_type>(row.sel_beg),
|
2014-11-14 10:13:38 +00:00
|
|
|
static_cast<char_type>(row.sel_end),
|
|
|
|
row.begin_margin_sel,
|
|
|
|
row.end_margin_sel,
|
|
|
|
d.wid, d.asc, d.des };
|
2011-05-06 06:49:55 +00:00
|
|
|
crc.process_bytes(b, sizeof(b));
|
2015-01-14 10:49:05 +00:00
|
|
|
crc.process_bytes(&row.separator, sizeof(row.separator));
|
2007-11-17 11:27:03 +00:00
|
|
|
|
|
|
|
return crc.checksum();
|
2007-01-06 09:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-11 16:04:10 +00:00
|
|
|
void ParagraphMetrics::setPosition(int position)
|
|
|
|
{
|
|
|
|
position_ = position;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-21 20:39:47 +00:00
|
|
|
Dimension const & ParagraphMetrics::insetDimension(Inset const * inset) const
|
|
|
|
{
|
|
|
|
InsetDims::const_iterator it = inset_dims_.find(inset);
|
|
|
|
if (it != inset_dims_.end())
|
|
|
|
return it->second;
|
|
|
|
|
|
|
|
static Dimension dummy;
|
|
|
|
return dummy;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ParagraphMetrics::setInsetDimension(Inset const * inset,
|
|
|
|
Dimension const & dim)
|
|
|
|
{
|
|
|
|
inset_dims_[inset] = dim;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-29 23:54:48 +00:00
|
|
|
Row & ParagraphMetrics::getRow(pos_type pos, bool boundary)
|
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(!rows().empty());
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
// If boundary is set we should return the row on which
|
|
|
|
// the character before is inside.
|
|
|
|
if (pos > 0 && boundary)
|
|
|
|
--pos;
|
|
|
|
|
|
|
|
RowList::iterator rit = rows_.end();
|
|
|
|
RowList::iterator const begin = rows_.begin();
|
|
|
|
|
|
|
|
for (--rit; rit != begin && rit->pos() > pos; --rit)
|
|
|
|
;
|
|
|
|
|
|
|
|
return *rit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Row const & ParagraphMetrics::getRow(pos_type pos, bool boundary) const
|
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(!rows().empty());
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
// If boundary is set we should return the row on which
|
|
|
|
// the character before is inside.
|
|
|
|
if (pos > 0 && boundary)
|
|
|
|
--pos;
|
|
|
|
|
|
|
|
RowList::const_iterator rit = rows_.end();
|
|
|
|
RowList::const_iterator const begin = rows_.begin();
|
|
|
|
|
|
|
|
for (--rit; rit != begin && rit->pos() > pos; --rit)
|
|
|
|
;
|
|
|
|
|
|
|
|
return *rit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t ParagraphMetrics::pos2row(pos_type pos) const
|
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(!rows().empty());
|
2006-12-29 23:54:48 +00:00
|
|
|
|
|
|
|
RowList::const_iterator rit = rows_.end();
|
|
|
|
RowList::const_iterator const begin = rows_.begin();
|
|
|
|
|
|
|
|
for (--rit; rit != begin && rit->pos() > pos; --rit)
|
|
|
|
;
|
|
|
|
|
|
|
|
return rit - begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ParagraphMetrics::dump() const
|
|
|
|
{
|
|
|
|
lyxerr << "Paragraph::dump: rows.size(): " << rows_.size() << endl;
|
|
|
|
for (size_t i = 0; i != rows_.size(); ++i) {
|
2013-06-25 12:57:09 +00:00
|
|
|
lyxerr << " row " << i << ": " << rows_[i];
|
2006-12-29 23:54:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-09 17:20:23 +00:00
|
|
|
int ParagraphMetrics::rightMargin(BufferView const & bv) const
|
2006-12-29 23:54:48 +00:00
|
|
|
{
|
2008-02-09 17:20:23 +00:00
|
|
|
BufferParams const & params = bv.buffer().params();
|
2008-02-28 01:42:02 +00:00
|
|
|
DocumentClass const & tclass = params.documentClass();
|
2006-12-29 23:54:48 +00:00
|
|
|
frontend::FontMetrics const & fm = theFontMetrics(params.getFont());
|
|
|
|
int const r_margin =
|
2008-02-09 17:20:23 +00:00
|
|
|
bv.rightMargin()
|
2007-08-18 13:21:12 +00:00
|
|
|
+ fm.signedWidth(tclass.rightmargin())
|
2008-03-06 21:31:27 +00:00
|
|
|
+ fm.signedWidth(par_->layout().rightmargin)
|
2006-12-29 23:54:48 +00:00
|
|
|
* 4 / (par_->getDepth() + 4);
|
|
|
|
|
|
|
|
return r_margin;
|
|
|
|
}
|
|
|
|
|
2007-08-18 21:17:10 +00:00
|
|
|
|
|
|
|
int ParagraphMetrics::singleWidth(pos_type pos, Font const & font) const
|
|
|
|
{
|
|
|
|
// The most special cases are handled first.
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset const * inset = par_->getInset(pos))
|
|
|
|
return insetDimension(inset).wid;
|
2007-08-18 21:17:10 +00:00
|
|
|
|
2014-06-13 14:33:58 +00:00
|
|
|
char_type const c = par_->getChar(pos);
|
2007-10-24 07:08:55 +00:00
|
|
|
|
2008-09-30 18:00:02 +00:00
|
|
|
if (c == '\t')
|
|
|
|
return 4 * theFontMetrics(font).width(' ');
|
2014-06-13 14:33:58 +00:00
|
|
|
|
|
|
|
// Note that this function is only called in
|
|
|
|
// RowPainter::paintText, and only used for characters that do
|
|
|
|
// not require handling of compose chars or ligatures. It can
|
|
|
|
// therefore be kept simple.
|
2007-08-18 21:17:10 +00:00
|
|
|
return theFontMetrics(font).width(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-31 14:46:13 +00:00
|
|
|
bool ParagraphMetrics::hfillExpansion(Row const & row, pos_type pos) const
|
|
|
|
{
|
|
|
|
if (!par_->isHfill(pos))
|
|
|
|
return false;
|
|
|
|
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(pos >= row.pos() && pos < row.endpos(), return false);
|
2007-08-31 14:46:13 +00:00
|
|
|
|
|
|
|
// expand at the end of a row only if there is another hfill on the same row
|
|
|
|
if (pos == row.endpos() - 1) {
|
|
|
|
for (pos_type i = row.pos(); i < pos; i++) {
|
|
|
|
if (par_->isHfill(i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// expand at the beginning of a row only if it is the first row of a paragraph
|
2012-10-27 13:45:27 +00:00
|
|
|
if (pos == row.pos())
|
2007-08-31 14:46:13 +00:00
|
|
|
return pos == 0;
|
|
|
|
|
|
|
|
// do not expand in some labels
|
2008-03-06 21:31:27 +00:00
|
|
|
if (par_->layout().margintype != MARGIN_MANUAL && pos < par_->beginOfBody())
|
2007-08-31 14:46:13 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// if there is anything between the first char of the row and
|
|
|
|
// the specified position that is neither a newline nor an hfill,
|
|
|
|
// the hfill will be expanded, otherwise it won't
|
|
|
|
for (pos_type i = row.pos(); i < pos; i++) {
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
if (!par_->isNewline(i) && !par_->isEnvSeparator(i) && !par_->isHfill(i))
|
2007-08-31 14:46:13 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-12-29 23:54:48 +00:00
|
|
|
} // namespace lyx
|