X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=c894f89cef8150d0c88f48b6ae694cf5b8adc66c;hb=e5a91999278253d597ad1e18f322884df4a4c94e;hp=8decee6fc78569b51b10453ba1340edc4fc370b0;hpb=a81bf7731451ff333dd84d8b90b3a698a66dc90b;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index 8decee6fc7..c894f89cef 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -71,7 +71,8 @@ docstring escapeChar(char_type c, XHTMLStream::EscapeSettings e) // escape what needs escaping -docstring htmlize(docstring const & str, XHTMLStream::EscapeSettings e) { +docstring htmlize(docstring const & str, XHTMLStream::EscapeSettings e) +{ odocstringstream d; docstring::const_iterator it = str.begin(); docstring::const_iterator en = str.end(); @@ -109,7 +110,8 @@ string escapeChar(char c, XHTMLStream::EscapeSettings e) // escape what needs escaping -string htmlize(string const & str, XHTMLStream::EscapeSettings e) { +string htmlize(string const & str, XHTMLStream::EscapeSettings e) +{ ostringstream d; string::const_iterator it = str.begin(); string::const_iterator en = str.end(); @@ -125,7 +127,7 @@ string cleanAttr(string const & str) string::const_iterator it = str.begin(); string::const_iterator en = str.end(); for (; it != en; ++it) - newname += isalnum(*it) ? *it : '_'; + newname += isAlnumASCII(*it) ? *it : '_'; return newname; } @@ -145,7 +147,8 @@ docstring cleanAttr(docstring const & str) bool isFontTag(string const & s) { - return s == "em" || s == "strong"; // others? + // others? + return s == "em" || s == "strong" || s == "i" || s == "b"; } @@ -197,24 +200,50 @@ XHTMLStream::XHTMLStream(odocstream & os) {} -void XHTMLStream::cr() +#if 0 +void XHTMLStream::dumpTagStack(string const & msg) const { - // tabs? - os_ << from_ascii("\n"); + writeError(msg + ": Tag Stack"); + TagStack::const_reverse_iterator it = tag_stack_.rbegin(); + TagStack::const_reverse_iterator en = tag_stack_.rend(); + for (; it != en; ++it) { + writeError(it->tag_); + } + writeError("Pending Tags"); + it = pending_tags_.rbegin(); + en = pending_tags_.rend(); + for (; it != en; ++it) { + writeError(it->tag_); + } + writeError("End Tag Stack"); } +#endif -void XHTMLStream::writeError(std::string const & s) +void XHTMLStream::writeError(std::string const & s) const { LYXERR0(s); - os_ << from_utf8(""); + os_ << from_utf8("\n"); +} + + +namespace { + // an illegal tag for internal use + static string const parsep_tag = "&LyX_parsep_tag&"; } bool XHTMLStream::closeFontTags() { + if (isTagPending(parsep_tag)) + // we haven't had any content + return true; + + // 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()) return true; + // first, we close any open font tags we can close html::StartTag curtag = tag_stack_.back(); while (html::isFontTag(curtag.tag_)) { @@ -227,19 +256,67 @@ bool XHTMLStream::closeFontTags() return true; curtag = tag_stack_.back(); } - // so we've hit a non-font tag. let's see if any of the - // remaining tags are font tags. - TagStack::const_iterator it = tag_stack_.begin(); - TagStack::const_iterator en = tag_stack_.end(); - bool noFontTags = true; + + if (curtag.tag_ == parsep_tag) + return true; + + // so we've hit a non-font tag. + writeError("Tags still open in closeFontTags(). Probably not a problem,\n" + "but you might want to check these tags:"); + TagStack::const_reverse_iterator it = tag_stack_.rbegin(); + TagStack::const_reverse_iterator const en = tag_stack_.rend(); for (; it != en; ++it) { - if (html::isFontTag(it->tag_)) { - writeError("Font tag `" + it->tag_ + "' still open in closeFontTags().\n" - "This is likely not a problem, but you might want to check."); - noFontTags = false; + string const tagname = it->tag_; + if (tagname == parsep_tag) + break; + writeError(it->tag_); + } + return false; +} + + +void XHTMLStream::startParagraph(bool keep_empty) +{ + pending_tags_.push_back(html::StartTag(parsep_tag)); + if (keep_empty) + clearTagDeque(); +} + + +void XHTMLStream::endParagraph() +{ + if (isTagPending(parsep_tag)) { + // this case is normal. it just means we didn't have content, + // so the parsep_tag never got moved onto the tag stack. + while (!pending_tags_.empty()) { + // clear all pending tags up to and including the parsep tag. + // note that we work from the back, because we want to get rid + // of everything that hasn't been used. + html::StartTag const cur_tag = pending_tags_.back(); + string const & tag = cur_tag.tag_; + pending_tags_.pop_back(); + if (tag == parsep_tag) + break; } + return; + } + + if (!isTagOpen(parsep_tag)) { + writeError("No paragraph separation tag found in endParagraph()."); + return; + } + + // this case is also normal, if the parsep tag is the last one + // on the stack. otherwise, it's an error. + while (!tag_stack_.empty()) { + html::StartTag const cur_tag = tag_stack_.back(); + string const & tag = cur_tag.tag_; + tag_stack_.pop_back(); + if (tag == parsep_tag) + break; + writeError("Tag `" + tag + "' still open at end of paragraph. Closing."); + os_ << cur_tag.asEndTag(); } - return noFontTags; } @@ -247,8 +324,9 @@ void XHTMLStream::clearTagDeque() { while (!pending_tags_.empty()) { html::StartTag const & tag = pending_tags_.front(); - // tabs? - os_ << tag.asTag(); + if (tag.tag_ != parsep_tag) + // tabs? + os_ << tag.asTag(); tag_stack_.push_back(tag); pending_tags_.pop_front(); } @@ -326,12 +404,20 @@ XHTMLStream & XHTMLStream::operator<<(html::CompTag const & tag) clearTagDeque(); // tabs? os_ << tag.asTag(); - cr(); + *this << html::CR(); + return *this; +} + + +XHTMLStream & XHTMLStream::operator<<(html::CR const &) +{ + // tabs? + os_ << from_ascii("\n"); return *this; } -bool XHTMLStream::isTagOpen(string const & stag) +bool XHTMLStream::isTagOpen(string const & stag) const { TagStack::const_iterator sit = tag_stack_.begin(); TagStack::const_iterator const sen = tag_stack_.end(); @@ -342,6 +428,17 @@ bool XHTMLStream::isTagOpen(string const & stag) } +bool XHTMLStream::isTagPending(string const & stag) const +{ + TagStack::const_iterator sit = pending_tags_.begin(); + TagStack::const_iterator const sen = pending_tags_.end(); + for (; sit != sen; ++sit) + if (sit->tag_ == stag) + return true; + return false; +} + + // this is complicated, because we want to make sure that // everything is properly nested. the code ought to make // sure of that, but we won't assert (yet) if we run into @@ -372,8 +469,8 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // to close. // is this tag itself pending? // non-const iterators because we may call erase(). - TagDeque::iterator dit = pending_tags_.begin(); - TagDeque::iterator const den = pending_tags_.end(); + TagStack::iterator dit = pending_tags_.begin(); + TagStack::iterator const den = pending_tags_.end(); for (; dit != den; ++dit) { if (dit->tag_ == etag.tag_) { // it was pending, so we just erase it @@ -474,7 +571,8 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) html::StartTag curtag = tag_stack_.back(); while (curtag.tag_ != etag.tag_) { writeError(curtag.tag_); - os_ << curtag.asEndTag(); + if (curtag.tag_ != parsep_tag) + os_ << curtag.asEndTag(); tag_stack_.pop_back(); curtag = tag_stack_.back(); } @@ -612,7 +710,7 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, // FIXME We should see if there's a label to be output and // do something with it. if (par != pbegin) - xs.cr(); + 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. @@ -631,17 +729,16 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, // (ii) We didn't open it and html_in_par is true, // but we are in the first par, and there is a next par. ParagraphList::const_iterator nextpar = par; - nextpar++; + ++nextpar; bool const needclose = (opened && (!runparams.html_in_par || nextpar != pend)) || (!opened && runparams.html_in_par && par == pbegin && nextpar != pend); if (needclose) { closeTag(xs, lay); - xs.cr(); + xs << html::CR(); } if (!deferred.empty()) { - xs << XHTMLStream::ESCAPE_NONE << deferred; - xs.cr(); + xs << XHTMLStream::ESCAPE_NONE << deferred << html::CR(); } } return pend; @@ -657,12 +754,12 @@ ParagraphList::const_iterator makeBibliography(Buffer const & buf, { // FIXME XHTML // Use TextClass::htmlTOCLayout() to figure out how we should look. - xs << html::StartTag("h2", "class='bibliography'"); - xs << pbegin->layout().labelstring(false); - xs << html::EndTag("h2"); - xs.cr(); - xs << html::StartTag("div", "class='bibliography'"); - xs.cr(); + xs << html::StartTag("h2", "class='bibliography'") + << pbegin->layout().labelstring(false) + << html::EndTag("h2") + << html::CR() + << html::StartTag("div", "class='bibliography'") + << html::CR(); makeParagraphs(buf, xs, runparams, text, pbegin, pend); xs << html::EndTag("div"); return pend; @@ -690,7 +787,7 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, // open tag for this environment openTag(xs, bstyle); - xs.cr(); + xs << html::CR(); // we will on occasion need to remember a layout from before. Layout const * lastlay = 0; @@ -747,20 +844,20 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, xs << lbl; closeLabelTag(xs, style); } - xs.cr(); + xs << html::CR(); } } else { // some kind of list if (style.labeltype == LABEL_MANUAL) { openLabelTag(xs, style); sep = par->firstWordLyXHTML(xs, runparams); closeLabelTag(xs, style); - xs.cr(); + xs << html::CR(); } else { openLabelTag(xs, style); xs << par->params().labelString(); closeLabelTag(xs, style); - xs.cr(); + xs << html::CR(); } } } // end label output @@ -784,7 +881,7 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, lastlay = &style; } else closeItemTag(xs, style); - xs.cr(); + xs << html::CR(); } // The other possibility is that the depth has increased, in which // case we need to recurse. @@ -814,16 +911,16 @@ ParagraphList::const_iterator makeEnvironmentHtml(Buffer const & buf, if (lastlay != 0) closeItemTag(xs, *lastlay); closeTag(xs, bstyle); - xs.cr(); + xs << html::CR(); return pend; } void makeCommand(Buffer const & buf, - XHTMLStream & xs, - OutputParams const & runparams, - Text const & text, - ParagraphList::const_iterator const & pbegin) + XHTMLStream & xs, + OutputParams const & runparams, + Text const & text, + ParagraphList::const_iterator const & pbegin) { Layout const & style = pbegin->layout(); if (!style.counter.empty()) @@ -833,6 +930,7 @@ void makeCommand(Buffer const & buf, // Label around sectioning number: // FIXME Probably need to account for LABEL_MANUAL + // FIXME Probably also need now to account for labels ABOVE and CENTERED. if (style.labeltype != LABEL_NO_LABEL) { openLabelTag(xs, style); xs << pbegin->params().labelString(); @@ -845,7 +943,7 @@ void makeCommand(Buffer const & buf, pbegin->simpleLyXHTMLOnePar(buf, xs, runparams, text.outerFont(distance(begin, pbegin))); closeTag(xs, style); - xs.cr(); + xs << html::CR(); } } // end anonymous namespace @@ -857,20 +955,33 @@ void xhtmlParagraphs(Text const & text, OutputParams const & runparams) { ParagraphList const & paragraphs = text.paragraphs(); - ParagraphList::const_iterator par = paragraphs.begin(); - ParagraphList::const_iterator pend = paragraphs.end(); + if (runparams.par_begin == runparams.par_end) { + runparams.par_begin = 0; + runparams.par_end = paragraphs.size(); + } + pit_type bpit = runparams.par_begin; + pit_type const epit = runparams.par_end; + LASSERT(bpit < epit, /* */); OutputParams ourparams = runparams; - while (par != pend) { + ParagraphList::const_iterator const pend = + (epit == (int) paragraphs.size()) ? + paragraphs.end() : paragraphs.constIterator(epit); + while (bpit < epit) { + ParagraphList::const_iterator par = paragraphs.constIterator(bpit); if (par->params().startOfAppendix()) { - // FIXME: only the counter corresponding to toplevel - // sectioning should be reset - Counters & cnts = buf.masterBuffer()->params().documentClass().counters(); - cnts.reset(); - cnts.appendix(true); + // We want to reset the counter corresponding to toplevel sectioning + Layout const & lay = + buf.masterBuffer()->params().documentClass().getTOCLayout(); + docstring const cnt = lay.counter; + if (!cnt.empty()) { + Counters & cnts = + buf.masterBuffer()->params().documentClass().counters(); + cnts.reset(cnt); + } } Layout const & style = par->layout(); - ParagraphList::const_iterator lastpar = par; + ParagraphList::const_iterator const lastpar = par; ParagraphList::const_iterator send; switch (style.latextype) { @@ -907,15 +1018,13 @@ void xhtmlParagraphs(Text const & text, par = makeParagraphs(buf, xs, ourparams, text, par, send); break; } - // FIXME?? - // makeEnvironment may process more than one paragraphs and bypass pend - if (distance(lastpar, par) >= distance(lastpar, pend)) - break; + bpit += distance(lastpar, par); } } -string alignmentToCSS(LyXAlignment align) { +string alignmentToCSS(LyXAlignment align) +{ switch (align) { case LYX_ALIGN_BLOCK: // we are NOT going to use text-align: justify!!