Jean-Marc Lasgouttes wrote:
> >> An alternative plan is to release 1.5.3 without any CJK-fixes and
> >> make a quick 1.5.4 mainly with CJK fixes afterwards, after this has
> >> been more thoroughly tested.
> >>
> >> Opinions?
> >
> > I'd vote for this alternative plan personally. 1.5.3 has a lot of bug
> > and performance fixes that seem quite stable. I see no reason to delay
> > the release even further.
>
> +1.

Now that 1.5.3 is out, I'd like to put the CJK fixes in branch (see attached 
patch for the recent version).

Objections?

Jürgen
Index: src/output_latex.h
===================================================================
--- src/output_latex.h	(Revision 22179)
+++ src/output_latex.h	(Arbeitskopie)
@@ -48,7 +48,7 @@
 /// \return (did the encoding change?, number of characters written to \p os)
 std::pair<bool, int> switchEncoding(odocstream & os, 
 		     BufferParams const & bparams,
-		     bool moving_arg, Encoding const & oldEnc,
+		     OutputParams const &, Encoding const & oldEnc,
 		     Encoding const & newEnc);
 
 } // namespace lyx
Index: src/Font.cpp
===================================================================
--- src/Font.cpp	(Revision 22179)
+++ src/Font.cpp	(Arbeitskopie)
@@ -787,7 +787,7 @@
 
 	if (language()->encoding()->package() == Encoding::CJK) {
 		pair<bool, int> const c = switchEncoding(os, bparams,
-				runparams.moving_arg, *(runparams.encoding),
+				runparams, *(runparams.encoding),
 				*(language()->encoding()));
 		if (c.first) {
 			open_encoding_ = true;
@@ -948,7 +948,7 @@
 		// to do correct environment nesting
 		Encoding const * const ascii = encodings.getFromLyXName("ascii");
 		pair<bool, int> const c = switchEncoding(os, bparams,
-				runparams.moving_arg, *(runparams.encoding),
+				runparams, *(runparams.encoding),
 				*ascii);
 		BOOST_ASSERT(c.first);
 		count += c.second;
Index: src/Paragraph.cpp
===================================================================
--- src/Paragraph.cpp	(Revision 22179)
+++ src/Paragraph.cpp	(Arbeitskopie)
@@ -68,6 +68,7 @@
 
 using support::contains;
 using support::prefixIs;
+using support::subst;
 using support::suffixIs;
 using support::rsplit;
 
@@ -2163,11 +2164,21 @@
 			open_font = false;
 		}
 
+		// close babel's font environment before opening CJK.
+		if (!running_font.language()->babel().empty() &&
+		    font.language()->encoding()->package() == Encoding::CJK) {
+				string end_tag = subst(lyxrc.language_command_end,
+							"$$lang",
+							running_font.language()->babel());
+				os << from_ascii(end_tag);
+				column += end_tag.length();
+		}
+
 		// Switch file encoding if necessary
-		if (runparams.encoding->package() == Encoding::inputenc &&
-		    font.language()->encoding()->package() == Encoding::inputenc) {
+		if (runparams.encoding->package() != Encoding::none &&
+		    font.language()->encoding()->package() != Encoding::none) {
 			std::pair<bool, int> const enc_switch = switchEncoding(os, bparams,
-					runparams.moving_arg, *(runparams.encoding),
+					runparams, *(runparams.encoding),
 					*(font.language()->encoding()));
 			if (enc_switch.first) {
 				column += enc_switch.second;
Index: src/output_latex.cpp
===================================================================
--- src/output_latex.cpp	(Revision 22179)
+++ src/output_latex.cpp	(Arbeitskopie)
@@ -43,6 +43,17 @@
 
 namespace {
 
+
+enum OpenEncoding {
+		none,
+		inputenc,
+		CJK
+	};
+
+static int open_encoding_ = none;
+static bool cjk_inherited_ = false;
+
+
 ParagraphList::const_iterator
 TeXEnvironment(Buffer const & buf,
 	       ParagraphList const & paragraphs,
@@ -161,6 +172,18 @@
 			os << from_ascii(style->latexparam()) << '\n';
 		texrow.newline();
 	}
+
+	// in multilingual environments, the CJK tags have to be nested properly
+	bool cjk_nested = false;
+	if (par_language->encoding()->package() == Encoding::CJK &&
+	    open_encoding_ != CJK && pit->isMultiLingual(bparams)) {
+		os << "\\begin{CJK}{" << from_ascii(par_language->encoding()->latexName())
+		   << "}{}%\n";
+		open_encoding_ = CJK;
+		cjk_nested = true;
+		texrow.newline();
+	}
+
 	ParagraphList::const_iterator par = pit;
 	do {
 		par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams);
@@ -199,6 +222,14 @@
 		 && par->params().depth() == pit->params().depth()
 		 && par->params().leftIndent() == pit->params().leftIndent());
 
+	if (open_encoding_ == CJK && cjk_nested) {
+		// We need to close the encoding even if it does not change
+		// to do correct environment nesting
+		os << "\\end{CJK}\n";
+		texrow.newline();
+		open_encoding_ = none;
+	}
+
 	if (style->isEnvironment()) {
 		os << "\\end{" << from_ascii(style->latexname()) << "}\n";
 		texrow.newline();
@@ -261,6 +292,32 @@
 	OutputParams runparams = runparams_in;
 	runparams.moving_arg |= style->needprotect;
 
+	// we are at the beginning of an inset and CJK is already open.
+	if (pit == paragraphs.begin() && runparams.local_font != 0 &&
+	    open_encoding_ == CJK) {
+		cjk_inherited_ = true;
+		open_encoding_ = none;
+	}
+
+	if (pit == paragraphs.begin() && runparams.local_font == 0) {
+		// Open a CJK environment at the beginning of the main buffer
+		// if the document's language is a CJK language
+		if (bparams.encoding().package() == Encoding::CJK) {
+			os << "\\begin{CJK}{" << from_ascii(bparams.encoding().latexName())
+			<< "}{}%\n";
+			texrow.newline();
+			open_encoding_ = CJK;
+		}
+		if (!lyxrc.language_auto_begin && !bparams.language->babel().empty()) {
+			// FIXME UNICODE
+			os << from_utf8(subst(lyxrc.language_command_begin,
+					     "$$lang",
+					     bparams.language->babel()))
+			   << '\n';
+		texrow.newline();
+		}
+	}
+
 	// This paragraph's language
 	Language const * const par_language = pit->getParLanguage(bparams);
 	// The document's language
@@ -342,13 +399,16 @@
 				else
 					os << "\\L{";
 			}
-			os << from_ascii(subst(
-				lyxrc.language_command_begin,
-				"$$lang",
-				par_language->babel()))
-			   // the '%' is necessary to prevent unwanted whitespace
-			   << "%\n";
-			texrow.newline();
+			// With CJK, the CJK tag has to be closed first (see below)
+			if (runparams.encoding->package() != Encoding::CJK) {
+				os << from_ascii(subst(
+					lyxrc.language_command_begin,
+					"$$lang",
+					par_language->babel()))
+				   // the '%' is necessary to prevent unwanted whitespace
+				   << "%\n";
+				texrow.newline();
+			}
 		}
 	}
 
@@ -356,14 +416,14 @@
 	// encoding, since this only affects the position of the outputted
 	// \inputencoding command; the encoding switch will occur when necessary
 	if (bparams.inputenc == "auto" &&
-	    runparams.encoding->package() == Encoding::inputenc) {
+	    runparams.encoding->package() != Encoding::none) {
 		// Look ahead for future encoding changes.
 		// We try to output them at the beginning of the paragraph,
 		// since the \inputencoding command is not allowed e.g. in
 		// sections.
 		for (pos_type i = 0; i < pit->size(); ++i) {
 			char_type const c = pit->getChar(i);
-			if (c < 0x80)
+			if (runparams.encoding->package() == Encoding::inputenc && c < 0x80)
 				continue;
 			if (pit->isInset(i))
 				break;
@@ -372,17 +432,44 @@
 			// encoding to that required by the language of c.
 			Encoding const * const encoding =
 				pit->getFontSettings(bparams, i).language()->encoding();
-			pair<bool, int> enc_switch = switchEncoding(os, bparams, false,
+
+			// with CJK, only add switch if we have CJK content at the beginning
+			// of the paragraph
+			if (encoding->package() != Encoding::CJK || i == 0) {
+				OutputParams tmp_rp = runparams;
+				runparams.moving_arg = false;
+				pair<bool, int> enc_switch = switchEncoding(os, bparams, runparams,
 					*(runparams.encoding), *encoding);
-			if (encoding->package() == Encoding::inputenc && enc_switch.first) {
-				runparams.encoding = encoding;
-				if (enc_switch.second > 0) {
-					// the '%' is necessary to prevent unwanted whitespace
-					os << "%\n";
+				runparams = tmp_rp;
+				// the following is necessary after a CJK environment in a multilingual
+				// context (nesting issue).
+				if (par_language->encoding()->package() == Encoding::CJK &&
+				    open_encoding_ != CJK && !cjk_inherited_) {
+					os << "\\begin{CJK}{" << from_ascii(par_language->encoding()->latexName())
+					   << "}{}%\n";
+					open_encoding_ = CJK;
 					texrow.newline();
 				}
+				if (encoding->package() != Encoding::none && enc_switch.first) {
+					if (enc_switch.second > 0) {
+						// the '%' is necessary to prevent unwanted whitespace
+						os << "%\n";
+						texrow.newline();
+					}
+					// With CJK, the CJK tag had to be closed first (see above)
+					if (runparams.encoding->package() == Encoding::CJK) {
+						os << from_ascii(subst(
+							lyxrc.language_command_begin,
+							"$$lang",
+							par_language->babel()))
+						// the '%' is necessary to prevent unwanted whitespace
+						<< "%\n";
+						texrow.newline();
+					}
+					runparams.encoding = encoding;
+				}
+				break;
 			}
-			break;
 		}
 	}
 
@@ -540,20 +627,23 @@
 			os << '\n';
 			texrow.newline();
 		}
-		if (lyxrc.language_command_end.empty()) {
-			if (!prev_language->babel().empty()) {
+		// when the paragraph uses CJK, the language has to be closed earlier
+		if (font.language()->encoding()->package() != Encoding::CJK) {
+			if (lyxrc.language_command_end.empty()) {
+				if (!prev_language->babel().empty()) {
+					os << from_ascii(subst(
+						lyxrc.language_command_begin,
+						"$$lang",
+						prev_language->babel()));
+					pending_newline = true;
+				}
+			} else if (!par_language->babel().empty()) {
 				os << from_ascii(subst(
-					lyxrc.language_command_begin,
+					lyxrc.language_command_end,
 					"$$lang",
-					prev_language->babel()));
+					par_language->babel()));
 				pending_newline = true;
 			}
-		} else if (!par_language->babel().empty()) {
-			os << from_ascii(subst(
-				lyxrc.language_command_end,
-				"$$lang",
-				par_language->babel()));
-			pending_newline = true;
 		}
 	}
 	if (closing_rtl_ltr_environment)
@@ -564,6 +654,56 @@
 		texrow.newline();
 	}
 
+	// if this is a CJK-paragraph and the next isn't, close CJK
+	// also if the next paragraph is a multilingual environment (because of nesting)
+	if (boost::next(pit) != paragraphs.end() && open_encoding_ == CJK &&
+	    (boost::next(pit)->getParLanguage(bparams)->encoding()->package() != Encoding::CJK ||
+	     boost::next(pit)->layout()->isEnvironment() && boost::next(pit)->isMultiLingual(bparams))
+	     // in environments, CJK has to be closed later (nesting!)
+	     && !style->isEnvironment()) {
+		os << "\\end{CJK}\n";
+		open_encoding_ = none;
+	}
+
+	// If this is the last paragraph, close the CJK environment
+	// if necessary. If it's an environment, we'll have to \end that first.
+	if (boost::next(pit) == paragraphs.end() && !style->isEnvironment()) {
+		switch (open_encoding_) {
+			case CJK: {
+				// end of main text
+				if (runparams.local_font == 0) {
+					os << '\n';
+					texrow.newline();
+					os << "\\end{CJK}\n";
+					texrow.newline();
+				// end of an inset
+				} else
+					os << "\\end{CJK}";
+				open_encoding_ = none;
+				break;
+			}
+			case inputenc: {
+				os << "\\egroup";
+				open_encoding_ = none;
+				break;
+			}
+			case none:
+			default:
+				// do nothing
+				break;
+		}
+		// auto_end tag only if the last par is in a babel language
+		if (runparams.local_font == 0 && !lyxrc.language_auto_end && 
+		    !bparams.language->babel().empty() &&
+		    font.language()->encoding()->package() != Encoding::CJK) {
+			os << from_utf8(subst(lyxrc.language_command_end,
+					      "$$lang",
+					      bparams.language->babel()))
+			   << '\n';
+			texrow.newline();
+		}
+	}
+
 	// If this is the last paragraph, and a local_font was set upon entering
 	// the inset, the encoding should be set back to that local_font's 
 	// encoding. We don't use switchEncoding(), because no explicit encoding
@@ -693,13 +833,26 @@
 				}
 		texrow.newline();
 	}
+	// If the last paragraph is an environment, we'll have to close
+	// CJK at the very end to do proper nesting.
+	if (open_encoding_ == CJK) {
+		os << "\\end{CJK}\n";
+		texrow.newline();
+		open_encoding_ = none;
+	}
+	// reset inherited encoding
+	if (cjk_inherited_) {
+		open_encoding_ = CJK;
+		cjk_inherited_ = false;
+	}
 }
 
 
 pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
-		   bool moving_arg, Encoding const & oldEnc,
+		   OutputParams const & runparams, Encoding const & oldEnc,
 		   Encoding const & newEnc)
 {
+	bool moving_arg = runparams.moving_arg;
 	if ((bparams.inputenc != "auto" && bparams.inputenc != "default")
 		|| moving_arg)
 		return make_pair(false, 0);
@@ -724,27 +877,49 @@
 	if (bparams.inputenc == "default")
 		return make_pair(true, 0);
 
-	docstring const inputenc(from_ascii(newEnc.latexName()));
+	docstring const inputenc_arg(from_ascii(newEnc.latexName()));
 	switch (newEnc.package()) {
 		case Encoding::none:
 			// shouldn't ever reach here, see above
 			return make_pair(true, 0);
 		case Encoding::inputenc: {
-			int count = inputenc.length();
-			if (oldEnc.package() == Encoding::CJK) {
+			int count = inputenc_arg.length();
+			if (oldEnc.package() == Encoding::CJK &&
+			    open_encoding_ == CJK) {
 				os << "\\end{CJK}";
+				open_encoding_ = none;
 				count += 9;
 			}
-			os << "\\inputencoding{" << inputenc << '}';
+			else if (oldEnc.package() == Encoding::inputenc &&
+				 open_encoding_ == inputenc) {
+				os << "\\egroup";
+				open_encoding_ = none;
+				count += 7;
+			}
+			if (runparams.local_font != 0 && oldEnc.package() == Encoding::CJK) {
+				// within insets, \inputenc switches need to be 
+				// embraced within \bgroup ... \egroup; else CJK fails.
+				os << "\\bgroup";
+				count += 7;
+				open_encoding_ = inputenc;
+			}
+			os << "\\inputencoding{" << inputenc_arg << '}';
 			return make_pair(true, count + 16);
-		 }
+		}
 		case Encoding::CJK: {
-			int count = inputenc.length();
-			if (oldEnc.package() == Encoding::CJK) {
+			int count = inputenc_arg.length();
+			if (oldEnc.package() == Encoding::CJK && 
+			    open_encoding_ == CJK) {
 				os << "\\end{CJK}";
 				count += 9;
 			}
-			os << "\\begin{CJK}{" << inputenc << "}{}";
+			if (oldEnc.package() == Encoding::inputenc && 
+			    open_encoding_ == inputenc) {
+				os << "\\egroup";
+				count += 7;
+			}
+			os << "\\begin{CJK}{" << inputenc_arg << "}{}";
+			open_encoding_ = CJK;
 			return make_pair(true, count + 15);
 		}
 	}
Index: src/Buffer.cpp
===================================================================
--- src/Buffer.cpp	(Revision 22179)
+++ src/Buffer.cpp	(Arbeitskopie)
@@ -1044,26 +1044,6 @@
 	} // output_preamble
 	LYXERR(Debug::INFO) << "preamble finished, now the body." << endl;
 
-	if (!lyxrc.language_auto_begin &&
-	    !params().language->babel().empty()) {
-		// FIXME UNICODE
-		os << from_utf8(subst(lyxrc.language_command_begin,
-					   "$$lang",
-					   params().language->babel()))
-		   << '\n';
-		texrow().newline();
-	}
-
-	Encoding const & encoding = params().encoding();
-	if (encoding.package() == Encoding::CJK) {
-		// Open a CJK environment, since in contrast to the encodings
-		// handled by inputenc the document encoding is not set in
-		// the preamble if it is handled by CJK.sty.
-		os << "\\begin{CJK}{" << from_ascii(encoding.latexName())
-		   << "}{}\n";
-		texrow().newline();
-	}
-
 	// if we are doing a real file with body, even if this is the
 	// child of some other buffer, let's cut the link here.
 	// This happens for example if only a child document is printed.
@@ -1084,23 +1064,6 @@
 	os << endl;
 	texrow().newline();
 
-	if (encoding.package() == Encoding::CJK) {
-		// Close the open CJK environment.
-		// latexParagraphs will have opened one even if the last text
-		// was not CJK.
-		os << "\\end{CJK}\n";
-		texrow().newline();
-	}
-
-	if (!lyxrc.language_auto_end &&
-	    !params().language->babel().empty()) {
-		os << from_utf8(subst(lyxrc.language_command_end,
-					   "$$lang",
-					   params().language->babel()))
-		   << '\n';
-		texrow().newline();
-	}
-
 	if (output_preamble) {
 		os << "\\end{document}\n";
 		texrow().newline();

Reply via email to