X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=5130740fb743a250e556f69527e4e09c05d3586b;hb=cde541d785aaac9d45d636a7f9071353dd932eb6;hp=b06f8bd5d12aec2338294d5aef45d88d16b700f7;hpb=ad56bb7286cabddefb4d2e470b833ac1874623a3;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index b06f8bd5d1..5130740fb7 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -148,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()) @@ -166,34 +158,40 @@ docstring StartTag::asTag() const } -docstring StartTag::asEndTag() const +docstring StartTag::writeEndTag() const { string output = ""; return from_utf8(output); } -docstring ParTag::asTag() const +bool StartTag::operator==(FontTag const & rhs) const { - docstring output = StartTag::asTag(); - - if (parid_.empty()) - return output; - - string const pattr = "id='" + parid_ + "'"; - output += html::CompTag("a", pattr).asTag(); - return output; + return rhs == *this; } -docstring EndTag::asEndTag() const +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()) @@ -202,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 @@ -246,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&"); } @@ -263,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. @@ -272,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. @@ -281,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_); } @@ -309,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; @@ -325,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(); } } @@ -337,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(); } @@ -424,12 +544,21 @@ 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? @@ -438,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; } @@ -473,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(); @@ -488,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; @@ -509,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(); @@ -524,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; @@ -534,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; @@ -543,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_ + "'."); @@ -567,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. @@ -592,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;