X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=080369f104e935535a2be7e6a548416584717b29;hb=e694199837172dd4927eb64112e00f85a426eb8e;hp=959262d9cd469c595c08b6eb12be502902a5c66d;hpb=b6aed54c45cf4a479cfd11e3e6851194f5a05947;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index 959262d9cd..080369f104 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -85,53 +85,10 @@ docstring htmlize(docstring const & str, XHTMLStream::EscapeSettings e) } -string escapeChar(char c, XHTMLStream::EscapeSettings e) +docstring escapeChar(char c, XHTMLStream::EscapeSettings e) { - string str; - switch (e) { - case XHTMLStream::ESCAPE_NONE: - str += c; - break; - case XHTMLStream::ESCAPE_ALL: - if (c == '<') { - str += "<"; - break; - } else if (c == '>') { - str += ">"; - break; - } - // fall through - case XHTMLStream::ESCAPE_AND: - if (c == '&') - str += "&"; - else - str +=c ; - break; - } - return str; -} - - -// escape what needs escaping -string htmlize(string const & str, XHTMLStream::EscapeSettings e) -{ - ostringstream d; - string::const_iterator it = str.begin(); - string::const_iterator en = str.end(); - for (; it != en; ++it) - d << escapeChar(*it, e); - return d.str(); -} - - -string cleanAttr(string const & str) -{ - string newname; - string::const_iterator it = str.begin(); - string::const_iterator en = str.end(); - for (; it != en; ++it) - newname += isAlnumASCII(*it) ? *it : '_'; - return newname; + LATTEST(static_cast(c) < 0x80); + return escapeChar(static_cast(c), e); } @@ -150,11 +107,11 @@ docstring cleanAttr(docstring const & str) docstring StartTag::writeTag() const { - string output = "<" + tag_; + docstring output = '<' + from_utf8(tag_); if (!attr_.empty()) - output += " " + html::htmlize(attr_, XHTMLStream::ESCAPE_NONE); + output += ' ' + html::htmlize(from_utf8(attr_), XHTMLStream::ESCAPE_NONE); output += ">"; - return from_utf8(output); + return output; } @@ -178,26 +135,23 @@ docstring EndTag::writeEndTag() const } -docstring ParTag::writeTag() const +ParTag::ParTag(std::string const & tag, std::string attr, + std::string const & parid) + : StartTag(tag) { - docstring output = StartTag::writeTag(); - - if (parid_.empty()) - return output; - - string const pattr = "id='" + parid_ + "'"; - output += html::CompTag("a", pattr).writeTag(); - return output; + if (!parid.empty()) + attr += " id='" + parid + "'"; + attr_ = attr; } docstring CompTag::writeTag() const { - string output = "<" + tag_; + docstring output = '<' + from_utf8(tag_); if (!attr_.empty()) - output += " " + html::htmlize(attr_, XHTMLStream::ESCAPE_NONE); + output += ' ' + html::htmlize(from_utf8(attr_), XHTMLStream::ESCAPE_NONE); output += " />"; - return from_utf8(output); + return output; } @@ -218,6 +172,7 @@ string fontToTag(html::FontTypes type) case FT_DBAR: return "u"; case FT_SOUT: + case FT_XOUT: return "del"; case FT_ITALIC: return "i"; @@ -257,6 +212,7 @@ string fontToAttribute(html::FontTypes type) return ""; case FT_DBAR: return "class='dline'"; + case FT_XOUT: case FT_SOUT: return "class='strikeout'"; case FT_WAVE: @@ -337,21 +293,27 @@ XHTMLStream::XHTMLStream(odocstream & os) #ifdef XHTML_DEBUG -void XHTMLStream::dumpTagStack(string const & msg) const +void XHTMLStream::dumpTagStack(string const & msg) { - writeError(msg + ": Tag Stack"); - TagStack::const_reverse_iterator it = tag_stack_.rbegin(); - TagStack::const_reverse_iterator en = tag_stack_.rend(); + *this << html::CR(); + writeError(msg); + *this << html::CR(); + writeError("Tag Stack"); + TagDeque::const_reverse_iterator it = tag_stack_.rbegin(); + TagDeque::const_reverse_iterator en = tag_stack_.rend(); for (; it != en; ++it) { - writeError(it->tag_); + writeError(it->get()->tag_); } + writeError("End Tag Stack"); + *this << html::CR(); writeError("Pending Tags"); it = pending_tags_.rbegin(); en = pending_tags_.rend(); for (; it != en; ++it) { - writeError(it->tag_); + writeError(it->get()->tag_); } - writeError("End Tag Stack"); + writeError("End Pending Tags"); + *this << html::CR(); } #endif @@ -366,7 +328,7 @@ void XHTMLStream::writeError(std::string const & s) const namespace { // an illegal tag for internal use static html::StartTag const parsep_tag("&LyX_parsep_tag&"); -} +} // namespace bool XHTMLStream::closeFontTags() @@ -375,6 +337,10 @@ bool XHTMLStream::closeFontTags() // we haven't had any content return true; +#ifdef XHTML_DEBUG + dumpTagStack("Beging Close Font Tags"); +#endif + // this may be a useless check, since we ought at least to have // the parsep_tag. but it can't hurt too much to be careful. if (tag_stack_.empty()) @@ -387,10 +353,14 @@ bool XHTMLStream::closeFontTags() tag_stack_.pop_back(); // this shouldn't happen, since then the font tags // weren't in any other tag. - LBUFERR(!tag_stack_.empty()); + LASSERT(!tag_stack_.empty(), return true); curtag = tag_stack_.back(); } +#ifdef XHTML_DEBUG + dumpTagStack("End Close Font Tags"); +#endif + if (*curtag == parsep_tag) return true; @@ -408,15 +378,18 @@ bool XHTMLStream::closeFontTags() } -void XHTMLStream::startParagraph(bool keep_empty) +void XHTMLStream::startDivision(bool keep_empty) { pending_tags_.push_back(makeTagPtr(html::StartTag(parsep_tag))); if (keep_empty) clearTagDeque(); +#ifdef XHTML_DEBUG + dumpTagStack("StartDivision"); +#endif } -void XHTMLStream::endParagraph() +void XHTMLStream::endDivision() { if (isTagPending(parsep_tag)) { // this case is normal. it just means we didn't have content, @@ -430,11 +403,16 @@ void XHTMLStream::endParagraph() if (*cur_tag == parsep_tag) break; } + +#ifdef XHTML_DEBUG + dumpTagStack("EndDivision"); +#endif + return; } if (!isTagOpen(parsep_tag)) { - writeError("No paragraph separation tag found in endParagraph()."); + writeError("No division separation tag found in endDivision()."); return; } @@ -448,6 +426,10 @@ void XHTMLStream::endParagraph() writeError("Tag `" + cur_tag->tag_ + "' still open at end of paragraph. Closing."); os_ << cur_tag->writeEndTag(); } + +#ifdef XHTML_DEBUG + dumpTagStack("EndDivision"); +#endif } @@ -495,7 +477,7 @@ XHTMLStream & XHTMLStream::operator<<(char_type c) XHTMLStream & XHTMLStream::operator<<(char c) { clearTagDeque(); - string const d = html::escapeChar(c, escape_); + os_ << html::escapeChar(c, escape_); escape_ = ESCAPE_ALL; return *this; } @@ -875,25 +857,42 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, if (!lay.counter.empty()) buf.masterBuffer()->params(). documentClass().counters().step(lay.counter, OutputUpdate); + // FIXME We should see if there's a label to be output and // do something with it. if (par != pbegin) xs << html::CR(); - // If we are already in a paragraph, and this is the first one, then we - // do not want to open the paragraph tag. - // we also do not want to open it if the current layout does not permit - // multiple paragraphs. - bool const opened = runparams.html_make_pars && - (par != pbegin || !runparams.html_in_par); - bool const make_parid = !runparams.for_toc && runparams.html_make_pars; - - if (opened) - openParTag(xs, lay, par->params(), - make_parid ? par->magicLabel() : ""); + // We want to open the paragraph tag if: + // (i) the current layout permits multiple paragraphs + // (ii) we are either not already inside a paragraph (HTMLIsBlock) OR + // we are, but this is not the first paragraph + // + // But there is also a special case, and we first see whether we are in it. + // We do not want to open the paragraph tag if this paragraph contains + // only one item, and that item is "inline", i.e., not HTMLIsBlock (such + // as a branch). On the other hand, if that single item has a font change + // applied to it, then we still do need to open the paragraph. + // + // Obviously, this is very fragile. The main reason we need to do this is + // because of branches, e.g., a branch that contains an entire new section. + // We do not really want to wrap that whole thing in a
...
. + bool special_case = false; + Inset const * specinset = par->size() == 1 ? par->getInset(0) : 0; + if (specinset && !specinset->getLayout().htmlisblock()) { + Layout const & style = par->layout(); + FontInfo const first_font = style.labeltype == LABEL_MANUAL ? + style.labelfont : style.font; + FontInfo const our_font = + par->getFont(buf.masterBuffer()->params(), 0, + text.outerFont(distance(begin, par))).fontInfo(); + if (first_font == our_font) + special_case = true; + } - docstring const deferred = - par->simpleLyXHTMLOnePar(buf, xs, runparams, text.outerFont(distance(begin, par))); + bool const open_par = runparams.html_make_pars + && (!runparams.html_in_par || par != pbegin) + && !special_case; // We want to issue the closing tag if either: // (i) We opened it, and either html_in_par is false, @@ -902,13 +901,26 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, // but we are in the first par, and there is a next par. ParagraphList::const_iterator nextpar = par; ++nextpar; - bool const needclose = - (opened && (!runparams.html_in_par || nextpar != pend)) - || (!opened && runparams.html_in_par && par == pbegin && nextpar != pend); - if (needclose) { + bool const close_par = + (open_par && (!runparams.html_in_par || nextpar != pend)) + || (!open_par && runparams.html_in_par && par == pbegin && nextpar != pend); + + if (open_par) { + // We do not issue the paragraph id if we are doing + // this for the TOC (or some similar purpose) + openParTag(xs, lay, par->params(), + runparams.for_toc ? "" : par->magicLabel()); + } + + docstring const deferred = par->simpleLyXHTMLOnePar(buf, xs, + runparams, text.outerFont(distance(begin, par)), + open_par, close_par); + + if (close_par) { closeTag(xs, lay); xs << html::CR(); } + if (!deferred.empty()) { xs << XHTMLStream::ESCAPE_NONE << deferred << html::CR(); } @@ -1037,8 +1049,9 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, if (labelfirst) openItemTag(xs, style, par->params()); - par->simpleLyXHTMLOnePar(buf, xs, runparams, - text.outerFont(distance(begin, par)), sep); + docstring deferred = par->simpleLyXHTMLOnePar(buf, xs, runparams, + text.outerFont(distance(begin, par)), true, true, sep); + xs << XHTMLStream::ESCAPE_NONE << deferred; ++par; // We may not want to close the tag yet, in particular: