X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=5130740fb743a250e556f69527e4e09c05d3586b;hb=cde541d785aaac9d45d636a7f9071353dd932eb6;hp=13e5c19f00bb9f9f9fa585182af3c8dfcce3eb3f;hpb=c5a707ba7428905432eaeaa7b0756d057efa1393;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index 13e5c19f00..5130740fb7 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -46,7 +46,6 @@ namespace lyx { namespace html { - docstring escapeChar(char_type c, XHTMLStream::EscapeSettings e) { docstring str; @@ -149,15 +148,7 @@ docstring cleanAttr(docstring const & str) } -bool isFontTag(string const & s) -{ - return s == "em" || s == "strong" || s == "i" || s == "b" - || s == "dfn" || s == "kbd" || s == "var" || s == "samp" - || s == "del" || s == "u"; -} - - -docstring StartTag::asTag() const +docstring StartTag::writeTag() const { string output = "<" + tag_; if (!attr_.empty()) @@ -167,21 +158,40 @@ docstring StartTag::asTag() const } -docstring StartTag::asEndTag() const +docstring StartTag::writeEndTag() const { string output = ""; return from_utf8(output); } -docstring EndTag::asEndTag() const +bool StartTag::operator==(FontTag const & rhs) const +{ + return rhs == *this; +} + + +docstring EndTag::writeEndTag() const { string output = ""; return from_utf8(output); } -docstring CompTag::asTag() const +docstring ParTag::writeTag() const +{ + docstring output = StartTag::writeTag(); + + if (parid_.empty()) + return output; + + string const pattr = "id='" + parid_ + "'"; + output += html::CompTag("a", pattr).writeTag(); + return output; +} + + +docstring CompTag::writeTag() const { string output = "<" + tag_; if (!attr_.empty()) @@ -190,6 +200,129 @@ docstring CompTag::asTag() const return from_utf8(output); } + + +namespace { + +string fontToTag(html::FontTypes type) + { + switch(type) { + case FT_EMPH: + return "em"; + case FT_BOLD: + return "b"; + case FT_NOUN: + return "dfn"; + case FT_UBAR: + case FT_WAVE: + case FT_DBAR: + return "u"; + case FT_SOUT: + return "del"; + case FT_ITALIC: + return "i"; + case FT_UPRIGHT: + case FT_SLANTED: + case FT_SMALLCAPS: + case FT_ROMAN: + case FT_SANS: + case FT_TYPE: + case FT_SIZE_TINY: + case FT_SIZE_SCRIPT: + case FT_SIZE_FOOTNOTE: + case FT_SIZE_SMALL: + case FT_SIZE_NORMAL: + case FT_SIZE_LARGE: + case FT_SIZE_LARGER: + case FT_SIZE_LARGEST: + case FT_SIZE_HUGE: + case FT_SIZE_HUGER: + case FT_SIZE_INCREASE: + case FT_SIZE_DECREASE: + return "span"; + } + // kill warning + return ""; +} + +StartTag fontToStartTag(html::FontTypes type) + { + string tag = fontToTag(type); + switch(type) { + case FT_EMPH: + return html::StartTag(tag); + case FT_BOLD: + return html::StartTag(tag); + case FT_NOUN: + return html::StartTag(tag, "class='lyxnoun'"); + case FT_UBAR: + return html::StartTag(tag); + case FT_DBAR: + return html::StartTag(tag, "class='dline'"); + case FT_SOUT: + return html::StartTag(tag, "class='strikeout'"); + case FT_WAVE: + return html::StartTag(tag, "class='wline'"); + case FT_ITALIC: + return html::StartTag(tag); + case FT_UPRIGHT: + return html::StartTag(tag, "style='font-style:normal;'"); + case FT_SLANTED: + return html::StartTag(tag, "style='font-style:oblique;'"); + case FT_SMALLCAPS: + return html::StartTag(tag, "style='font-variant:small-caps;'"); + case FT_ROMAN: + return html::StartTag(tag, "style='font-family:serif;'"); + case FT_SANS: + return html::StartTag(tag, "style='font-family:sans-serif;'"); + case FT_TYPE: + return html::StartTag(tag, "style='font-family:monospace;'"); + case FT_SIZE_TINY: + case FT_SIZE_SCRIPT: + case FT_SIZE_FOOTNOTE: + return html::StartTag(tag, "style='font-size:x-small;'"); + case FT_SIZE_SMALL: + return html::StartTag(tag, "style='font-size:small;'"); + case FT_SIZE_NORMAL: + return html::StartTag(tag, "style='font-size:normal;'"); + case FT_SIZE_LARGE: + return html::StartTag(tag, "style='font-size:large;'"); + case FT_SIZE_LARGER: + case FT_SIZE_LARGEST: + return html::StartTag(tag, "style='font-size:x-large;'"); + case FT_SIZE_HUGE: + case FT_SIZE_HUGER: + return html::StartTag(tag, "style='font-size:xx-large;'"); + case FT_SIZE_INCREASE: + return html::StartTag(tag, "style='font-size:larger;'"); + case FT_SIZE_DECREASE: + return html::StartTag(tag, "style='font-size:smaller;'"); + } + // kill warning + return StartTag(""); +} + +} // end anonymous namespace + + +FontTag::FontTag(FontTypes type) + : StartTag(fontToStartTag(type)), font_type_(type) +{} + + +bool FontTag::operator==(StartTag const & tag) const +{ + FontTag const * const ftag = tag.asFontTag(); + if (!ftag) + return false; + return (font_type_ == ftag->font_type_); +} + + +EndFontTag::EndFontTag(FontTypes type) + : EndTag(fontToTag(type)), font_type_(type) +{} + } // namespace html @@ -234,7 +367,7 @@ void XHTMLStream::writeError(std::string const & s) const namespace { // an illegal tag for internal use - static string const parsep_tag = "&LyX_parsep_tag&"; + static html::StartTag const parsep_tag("&LyX_parsep_tag&"); } @@ -251,8 +384,8 @@ bool XHTMLStream::closeFontTags() // first, we close any open font tags we can close TagPtr curtag = tag_stack_.back(); - while (html::isFontTag(curtag->tag_)) { - os_ << curtag->asEndTag(); + while (curtag->asFontTag()) { + os_ << curtag->writeEndTag(); tag_stack_.pop_back(); // this shouldn't happen, since then the font tags // weren't in any other tag. @@ -260,7 +393,7 @@ bool XHTMLStream::closeFontTags() curtag = tag_stack_.back(); } - if (curtag->tag_ == parsep_tag) + if (*curtag == parsep_tag) return true; // so we've hit a non-font tag. @@ -269,8 +402,7 @@ bool XHTMLStream::closeFontTags() TagDeque::const_reverse_iterator it = tag_stack_.rbegin(); TagDeque::const_reverse_iterator const en = tag_stack_.rend(); for (; it != en; ++it) { - string const tagname = (*it)->tag_; - if (tagname == parsep_tag) + if (**it == parsep_tag) break; writeError((*it)->tag_); } @@ -297,7 +429,7 @@ void XHTMLStream::endParagraph() // of everything that hasn't been used. TagPtr const cur_tag = pending_tags_.back(); pending_tags_.pop_back(); - if (cur_tag->tag_ == parsep_tag) + if (*cur_tag == parsep_tag) break; } return; @@ -313,10 +445,10 @@ void XHTMLStream::endParagraph() while (!tag_stack_.empty()) { TagPtr const cur_tag = tag_stack_.back(); tag_stack_.pop_back(); - if (cur_tag->tag_ == parsep_tag) + if (*cur_tag == parsep_tag) break; writeError("Tag `" + cur_tag->tag_ + "' still open at end of paragraph. Closing."); - os_ << cur_tag->asEndTag(); + os_ << cur_tag->writeEndTag(); } } @@ -325,9 +457,9 @@ void XHTMLStream::clearTagDeque() { while (!pending_tags_.empty()) { TagPtr const tag = pending_tags_.front(); - if (tag->tag_ != parsep_tag) + if (*tag != parsep_tag) // tabs? - os_ << tag->asTag(); + os_ << tag->writeTag(); tag_stack_.push_back(tag); pending_tags_.pop_front(); } @@ -398,17 +530,35 @@ XHTMLStream & XHTMLStream::operator<<(html::StartTag const & tag) } +XHTMLStream & XHTMLStream::operator<<(html::ParTag const & tag) +{ + if (tag.tag_.empty()) + return *this; + pending_tags_.push_back(makeTagPtr(tag)); + return *this; +} + + XHTMLStream & XHTMLStream::operator<<(html::CompTag const & tag) { if (tag.tag_.empty()) return *this; clearTagDeque(); - os_ << tag.asTag(); + os_ << tag.writeTag(); *this << html::CR(); return *this; } +XHTMLStream & XHTMLStream::operator<<(html::FontTag const & tag) +{ + if (tag.tag_.empty()) + return *this; + pending_tags_.push_back(makeTagPtr(tag)); + return *this; +} + + XHTMLStream & XHTMLStream::operator<<(html::CR const &) { // tabs? @@ -417,23 +567,34 @@ XHTMLStream & XHTMLStream::operator<<(html::CR const &) } -bool XHTMLStream::isTagOpen(string const & stag) const +bool XHTMLStream::isTagOpen(html::StartTag const & stag) const +{ + TagDeque::const_iterator sit = tag_stack_.begin(); + TagDeque::const_iterator const sen = tag_stack_.end(); + for (; sit != sen; ++sit) + if (**sit == stag) + return true; + return false; +} + + +bool XHTMLStream::isTagOpen(html::EndTag const & etag) const { TagDeque::const_iterator sit = tag_stack_.begin(); TagDeque::const_iterator const sen = tag_stack_.end(); for (; sit != sen; ++sit) - if ((*sit)->tag_ == stag) + if (etag == **sit) return true; return false; } -bool XHTMLStream::isTagPending(string const & stag) const +bool XHTMLStream::isTagPending(html::StartTag const & stag) const { TagDeque::const_iterator sit = pending_tags_.begin(); TagDeque::const_iterator const sen = pending_tags_.end(); for (; sit != sen; ++sit) - if ((*sit)->tag_ == stag) + if (**sit == stag) return true; return false; } @@ -452,7 +613,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // if this tag is pending, we can simply discard it. if (!pending_tags_.empty()) { - if (etag.tag_ == pending_tags_.back()->tag_) { + if (etag == *pending_tags_.back()) { // we have , so we discard it and remove it // from the pending_tags_. pending_tags_.pop_back(); @@ -467,17 +628,18 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) TagDeque::iterator dit = pending_tags_.begin(); TagDeque::iterator const den = pending_tags_.end(); for (; dit != den; ++dit) { - if ((*dit)->tag_ == etag.tag_) { + if (etag == **dit) { // it was pending, so we just erase it writeError("Tried to close pending tag `" + etag.tag_ + "' when other tags were pending. Last pending tag is `" - + pending_tags_.back()->tag_ + "'. Tag discarded."); + + to_utf8(pending_tags_.back()->writeTag()) + + "'. Tag discarded."); pending_tags_.erase(dit); return *this; } } // so etag isn't itself pending. is it even open? - if (!isTagOpen(etag.tag_)) { + if (!isTagOpen(etag)) { writeError("Tried to close `" + etag.tag_ + "' when tag was not open. Tag discarded."); return *this; @@ -488,7 +650,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) string estr = "Closing tag `" + etag.tag_ + "' when other tags are pending. Discarded pending tags:\n"; for (dit = pending_tags_.begin(); dit != den; ++dit) - estr += (*dit)->tag_ + "\n"; + estr += to_utf8(html::htmlize((*dit)->writeTag(), XHTMLStream::ESCAPE_ALL)) + "\n"; writeError(estr); // clear the pending tags... pending_tags_.clear(); @@ -503,9 +665,9 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) } // is the tag we are closing the last one we opened? - if (etag.tag_ == tag_stack_.back()->tag_) { + if (etag == *tag_stack_.back()) { // output it... - os_ << etag.asEndTag(); + os_ << etag.writeEndTag(); // ...and forget about it tag_stack_.pop_back(); return *this; @@ -513,7 +675,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // we are trying to close a tag other than the one last opened. // let's first see if this particular tag is still open somehow. - if (!isTagOpen(etag.tag_)) { + if (!isTagOpen(etag)) { writeError("Tried to close `" + etag.tag_ + "' when tag was not open. Tag discarded."); return *this; @@ -522,15 +684,15 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // so the tag was opened, but other tags have been opened since // and not yet closed. // if it's a font tag, though... - if (html::isFontTag(etag.tag_)) { + if (etag.asFontTag()) { // it won't be a problem if the other tags open since this one // are also font tags. TagDeque::const_reverse_iterator rit = tag_stack_.rbegin(); TagDeque::const_reverse_iterator ren = tag_stack_.rend(); for (; rit != ren; ++rit) { - if ((*rit)->tag_ == etag.tag_) + if (etag == **rit) break; - if (!html::isFontTag((*rit)->tag_)) { + if (!(*rit)->asFontTag()) { // we'll just leave it and, presumably, have to close it later. writeError("Unable to close font tag `" + etag.tag_ + "' due to open non-font tag `" + (*rit)->tag_ + "'."); @@ -546,14 +708,13 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) TagPtr curtag = tag_stack_.back(); // ...remembering them in a stack. TagDeque fontstack; - while (etag.tag_ != curtag->tag_) { - os_ << curtag->asEndTag(); + while (etag != *curtag) { + os_ << curtag->writeEndTag(); fontstack.push_back(curtag); tag_stack_.pop_back(); curtag = tag_stack_.back(); } - // now close our tag... - os_ << etag.asEndTag(); + os_ << etag.writeEndTag(); tag_stack_.pop_back(); // ...and restore the other tags. @@ -571,15 +732,15 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) writeError("Closing tag `" + etag.tag_ + "' when other tags are open, namely:"); TagPtr curtag = tag_stack_.back(); - while (etag.tag_ != curtag->tag_) { + while (etag != *curtag) { writeError(curtag->tag_); - if (curtag->tag_ != parsep_tag) - os_ << curtag->asEndTag(); + if (*curtag != parsep_tag) + os_ << curtag->writeEndTag(); tag_stack_.pop_back(); curtag = tag_stack_.back(); } // curtag is now the one we actually want. - os_ << curtag->asEndTag(); + os_ << curtag->writeEndTag(); tag_stack_.pop_back(); return *this; @@ -611,6 +772,28 @@ void openTag(XHTMLStream & xs, Layout const & lay, } +inline void openParTag(XHTMLStream & xs, Layout const & lay, + std::string parlabel) +{ + xs << html::ParTag(lay.htmltag(), lay.htmlattr(), parlabel); +} + + +void openParTag(XHTMLStream & xs, Layout const & lay, + ParagraphParameters const & params, + std::string parlabel) +{ + // FIXME Are there other things we should handle here? + string const align = alignmentToCSS(params.align()); + if (align.empty()) { + openParTag(xs, lay, parlabel); + return; + } + string attrs = lay.htmlattr() + " style='text-align: " + align + ";'"; + xs << html::ParTag(lay.htmltag(), attrs, parlabel); +} + + inline void closeTag(XHTMLStream & xs, Layout const & lay) { xs << html::EndTag(lay.htmltag()); @@ -721,8 +904,12 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, // 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) - openTag(xs, lay, par->params()); + openParTag(xs, lay, par->params(), + make_parid ? par->magicLabel() : ""); + docstring const deferred = par->simpleLyXHTMLOnePar(buf, xs, runparams, text.outerFont(distance(begin, par))); @@ -789,7 +976,7 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, depth_type const origdepth = pbegin->params().depth(); // open tag for this environment - openTag(xs, bstyle); + openParTag(xs, bstyle, pbegin->magicLabel()); xs << html::CR(); // we will on occasion need to remember a layout from before. @@ -930,7 +1117,10 @@ void makeCommand(Buffer const & buf, buf.masterBuffer()->params(). documentClass().counters().step(style.counter, OutputUpdate); - openTag(xs, style, pbegin->params()); + bool const make_parid = !runparams.for_toc && runparams.html_make_pars; + + openParTag(xs, style, pbegin->params(), + make_parid ? pbegin->magicLabel() : ""); // Label around sectioning number: // FIXME Probably need to account for LABEL_MANUAL