While investigating in Nikos' report about problems with Greek hyperref 
settings I noticed that we get an iconv conversion error currently if the 
hypersetup data consists of glyphs that exceed the current encoding (for ex., 
the author name Νίκος Αλεξανδρής in an English document with latin1 encoding).

Conversion to LaTeX macros does not work here, since hyperref expects plain 
strings. I propose the attached patch (against branch), which does the 
following: It checks whether the hypersetup data exceeds the encoding, and if 
so, it switches to utf8 and embraces the hyperref call in 
\inputencoding{utf8}...\inputencoding{<original>}.

Note that I'm not sure if this is what Nikos reported, but it's a bug anyway.
Note also that the patch contains many whitespace changes I did along the way.

Objections?

Jürgen
Index: src/PDFOptions.cpp
===================================================================
--- src/PDFOptions.cpp	(Revision 33601)
+++ src/PDFOptions.cpp	(Arbeitskopie)
@@ -12,6 +12,7 @@
 
 #include "PDFOptions.h"
 
+#include "Encoding.h"
 #include "Lexer.h"
 
 #include "support/convert.h"
@@ -86,8 +87,11 @@
 }
 
 
-void PDFOptions::writeLaTeX(odocstream & os, bool hyperref_already_provided) const
+int PDFOptions::writeLaTeX(OutputParams & runparams, odocstream & os,
+			    bool hyperref_already_provided) const
 {
+	int lines = 0;
+	// FIXME Unicode
 	string opt;
 	
 	// since LyX uses unicode, also set the PDF strings to unicode strings with the
@@ -105,17 +109,18 @@
 		opt += "bookmarksnumbered=" + convert<string>(bookmarksnumbered) + ',';
 		opt += "bookmarksopen=" + convert<string>(bookmarksopen) + ',';
 		if (bookmarksopen)
-			opt += "bookmarksopenlevel=" + convert<string>(bookmarksopenlevel) + ',';
+			opt += "bookmarksopenlevel="
+			    + convert<string>(bookmarksopenlevel) + ',';
 	}
 	opt += "\n ";
-	opt += "breaklinks="     + convert<string>(breaklinks) + ',';
+	opt += "breaklinks=" + convert<string>(breaklinks) + ',';
 
-	opt += "pdfborder={0 0 " ;
-	opt += (pdfborder ?'0':'1');
+	opt += "pdfborder={0 0 ";
+	opt += (pdfborder ? '0' : '1');
 	opt += "},";
 
 	opt += "backref=" + backref + ',';
-	opt += "colorlinks="     + convert<string>(colorlinks) + ',';
+	opt += "colorlinks=" + convert<string>(colorlinks) + ',';
 	if (!pagemode.empty())
 		opt += "pdfpagemode=" + pagemode + ',';
 	
@@ -125,9 +130,9 @@
 	// LaTeX-errors when using non-latin characters
 	string hyperset;
 	if (!title.empty())
-		hyperset += "pdftitle={"   + title + "},";
+		hyperset += "pdftitle={" + title + "},";
 	if (!author.empty())
-		hyperset += "\n pdfauthor={"  + author + "},";
+		hyperset += "\n pdfauthor={" + author + "},";
 	if (!subject.empty())
 		hyperset += "\n pdfsubject={" + subject + "},";
 	if (!keywords.empty())
@@ -138,14 +143,25 @@
 	}
 	hyperset = rtrim(hyperset,",");
 
+	// check if the hyperref settings use an encoding that exceeds
+	// ours. If so, we have to switch to utf8.
+	Encoding const * const enc = runparams.encoding;
+	docstring const hs = from_utf8(hyperset);
+	bool need_unicode = false;
+	if (enc) {
+		for (size_t n = 0; n < hs.size(); ++n) {
+			if (enc->latexChar(hs[n], true) != docstring(1, hs[n]))
+				need_unicode = true;
+		}
+	}
 
 	// use in \\usepackage parameter as not all options can be handled inside \\hypersetup
 	if (!hyperref_already_provided) {
-		opt = rtrim(opt,",");
+		opt = rtrim(opt, ",");
 		opt = "\\usepackage[" + opt + "]\n {hyperref}\n";
 
 		if (!hyperset.empty())
-			opt += "\\hypersetup{" + hyperset + "}\n ";
+			opt += "\\hypersetup{" + hyperset + "}\n";
 	} else
 		// only in case hyperref is already loaded by the current text class
 		// try to put it into hyperset
@@ -154,11 +170,24 @@
 		//        and the option is active only when part of usepackage parameter
 		//        (e.g. pdfusetitle).
 		{
-			opt = "\\hypersetup{" + opt + hyperset + "}\n ";
+			opt = "\\hypersetup{" + opt + hyperset + "}\n";
 		}
-	
-	// FIXME UNICODE
+
+	lines = int(count(opt.begin(), opt.end(), '\n'));
+
+	// hyperref expects utf8!
+	if (need_unicode && enc && enc->iconvName() != "UTF-8") {
+		os << "\\inputencoding{utf8}\n"
+		   << setEncoding("UTF-8");
+		++lines;
+	}
 	os << from_utf8(opt);
+	if (need_unicode && enc && enc->iconvName() != "UTF-8") {
+		os << setEncoding(enc->iconvName())
+		   << "\\inputencoding{" << from_ascii(enc->latexName()) << "}\n";
+		++lines;
+	}
+	return lines;
 }
 
 
Index: src/BufferParams.cpp
===================================================================
--- src/BufferParams.cpp	(Revision 33601)
+++ src/BufferParams.cpp	(Arbeitskopie)
@@ -1320,13 +1320,23 @@
 	//   before hyperref. Then hyperref has a chance to detect babel.
 	// * Has to be loaded before the "LyX specific LaTeX commands" to
 	//   avoid errors with algorithm floats.
-	// use hyperref explicitely when it is required
+	// use hyperref explicitely if it is required
 	if (features.isRequired("hyperref")) {
-		odocstringstream oss;
-		pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
-		lyxpreamble += oss.str();
+		// pass what we have to stream here, since we need 
+		// to access the stream itself in PDFOptions.
+		os << lyxpreamble;
+
+		int lines =
+			int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
+
+		OutputParams tmp_params = features.runparams();
+		lines += pdfoptions().writeLaTeX(tmp_params, os,
+					documentClass().provides("hyperref"));
+		texrow.newlines(lines);
+		// set back for the rest
+		lyxpreamble.clear();
 	}
-	
+
 	// Will be surrounded by \makeatletter and \makeatother when not empty
 	docstring atlyxpreamble;
 
@@ -1420,9 +1430,7 @@
 
 	int const nlines =
 		int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
-	for (int j = 0; j != nlines; ++j) {
-		texrow.newline();
-	}
+	texrow.newlines(nlines);
 
 	os << lyxpreamble;
 	return use_babel;
Index: src/PDFOptions.h
===================================================================
--- src/PDFOptions.h	(Revision 33601)
+++ src/PDFOptions.h	(Arbeitskopie)
@@ -12,6 +12,8 @@
 #ifndef PDFOPTIONS_H
 #define PDFOPTIONS_H
 
+#include "OutputParams.h"
+
 #include "support/strfwd.h"
 
 #include <string>
@@ -34,7 +36,8 @@
 	/// output to lyx header
 	void writeFile(std::ostream &) const;
 	/// output to tex header
-	void writeLaTeX(odocstream &, bool hyperref_already_provided) const;
+	int writeLaTeX(OutputParams &, odocstream &,
+			bool hyperref_already_provided) const;
 	/// read tokens from lyx header
 	std::string readToken(Lexer &lex, std::string const & token);
 	/// set implicit settings for hyperref

Reply via email to