]> git.lyx.org Git - features.git/commitdiff
Rework that way that font tags are handled in XHTML output. We need
authorRichard Heck <rgheck@lyx.org>
Tue, 7 May 2013 06:34:15 +0000 (02:34 -0400)
committerRichard Heck <rgheck@lyx.org>
Mon, 13 May 2013 14:45:12 +0000 (10:45 -0400)
to do this in order to handle span tags properly, when they act as
font tags.

src/Paragraph.cpp
src/output_xhtml.cpp
src/output_xhtml.h

index 535506f9d4eba45de05e4e88da09dfed999e283e..a95163ef3924d249e9e0d68cdbe12b06566e7880 100644 (file)
@@ -2831,17 +2831,19 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 }
 
 
+namespace {
 void doFontSwitch(XHTMLStream & xs, bool startrange,
-       bool & flag, FontState curstate, std::string tag, std::string attr = "")
+       bool & flag, FontState curstate, html::FontTypes type)
 {
        if (curstate == FONT_ON) {
-               xs << html::StartTag(tag, attr);
+               xs << html::FontTag(type);
                flag = true;
        } else if (flag && !startrange) {
-               xs << html::EndTag(tag);
+               xs << html::EndFontTag(type);
                flag = false;
        }
 }
+}
 
 
 docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
@@ -2879,47 +2881,39 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
                // emphasis
                FontState curstate = font.fontInfo().emph();
                if (font_old.emph() != curstate)
-                       doFontSwitch(xs, at_start, emph_flag, curstate, "em");
+                       doFontSwitch(xs, at_start, emph_flag, curstate, html::FT_EMPH);
 
                // noun
                curstate = font.fontInfo().noun();
                if (font_old.noun() != curstate)
-                       doFontSwitch(xs, at_start, noun_flag, curstate, "dfn", "class='lyxnoun'");
+                       doFontSwitch(xs, at_start, noun_flag, curstate, html::FT_NOUN);
 
                // underbar
                curstate = font.fontInfo().underbar();
                if (font_old.underbar() != curstate)
-                       doFontSwitch(xs, at_start, ubar_flag, curstate, "u");
+                       doFontSwitch(xs, at_start, ubar_flag, curstate, html::FT_UBAR);
        
                // strikeout
                curstate = font.fontInfo().strikeout();
                if (font_old.strikeout() != curstate)
-                       doFontSwitch(xs, at_start, sout_flag, curstate, "del", "class='strikeout'");
-
-               // HTML does not really have an equivalent of the next two, so we will just
-               // output a single underscore with a class, and people can style it if they
-               // wish to do so
+                       doFontSwitch(xs, at_start, sout_flag, curstate, html::FT_SOUT);
 
                // double underbar
                curstate = font.fontInfo().uuline();
                if (font_old.uuline() != curstate)
-                       doFontSwitch(xs, at_start, dbar_flag, curstate, "u", "class='dline'");
+                       doFontSwitch(xs, at_start, dbar_flag, curstate, html::FT_DBAR);
 
                // wavy line
                curstate = font.fontInfo().uwave();
                if (font_old.uwave() != curstate)
-                       doFontSwitch(xs, at_start, wave_flag, curstate, "u", "class='wavyline'");
+                       doFontSwitch(xs, at_start, wave_flag, curstate, html::FT_WAVE);
 
                // bold
-               if (font_old.series() != font.fontInfo().series()) {
-                       if (font.fontInfo().series() == BOLD_SERIES) {
-                               xs << html::StartTag("b");
-                               bold_flag = true;
-                       } else if (bold_flag && !at_start) {
-                               xs << html::EndTag("b");
-                               bold_flag = false;
-                       }
-               }
+               // a little hackish, but allows us to reuse what we have.
+               curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF);
+               if (font_old.series() != font.fontInfo().series())
+                       doFontSwitch(xs, at_start, bold_flag, curstate, html::FT_BOLD);
+
                // FIXME XHTML
                // Other such tags? What about the other text ranges?
 
index cbb2c5c3d40514b8293176804f621b8e66ff46fa..7212bb2de10651867be456f4f49dd4f111a09e44 100644 (file)
@@ -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 = "</" + tag_ + ">";
        return from_utf8(output);
 }
 
 
-docstring EndTag::asEndTag() const
+bool StartTag::operator==(FontTag const & rhs) const
+{
+       return rhs == *this;
+}
+
+
+docstring EndTag::writeEndTag() const
 {
        string output = "</" + tag_ + ">";
        return from_utf8(output);
 }
 
 
-docstring ParTag::asTag() const
+docstring ParTag::writeTag() const
 {
-       docstring output = StartTag::asTag();
+       docstring output = StartTag::writeTag();
 
        if (parid_.empty())
                return output;
 
        string const pattr = "id='" + parid_ + "'";
-       output += html::CompTag("a", pattr).asTag();
+       output += html::CompTag("a", pattr).writeTag();
        return output;
 }
 
 
-docstring CompTag::asTag() const
+docstring CompTag::writeTag() const
 {
        string output = "<" + tag_;
        if (!attr_.empty())
@@ -202,6 +200,94 @@ 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_SLANTED:
+       case FT_SMALLCAPS:
+       case FT_ROMAN:
+       case FT_SANS:
+       case FT_TYPER:
+               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_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_TYPER:
+               return html::StartTag(tag, "style='font-family:monospace;'");
+       }
+       // 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
 
 
@@ -263,8 +349,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.
@@ -327,7 +413,7 @@ void XHTMLStream::endParagraph()
                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();
        }
 }
 
@@ -338,7 +424,7 @@ void XHTMLStream::clearTagDeque()
                TagPtr const tag = pending_tags_.front();
                if (*tag != parsep_tag)
                        // tabs?
-                       os_ << tag->asTag();
+                       os_ << tag->writeTag();
                tag_stack_.push_back(tag);
                pending_tags_.pop_front();
        }
@@ -423,12 +509,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?
@@ -536,7 +631,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag)
        // is the tag we are closing the last one we opened?
        if (etag == *tag_stack_.back()) {
                // output it...
-               os_ << etag.asEndTag();
+               os_ << etag.writeEndTag();
                // ...and forget about it
                tag_stack_.pop_back();
                return *this;
@@ -553,7 +648,7 @@ 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();
@@ -561,7 +656,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag)
                for (; rit != ren; ++rit) {
                        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_ + "'.");
@@ -578,13 +673,12 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag)
                // ...remembering them in a stack.
                TagDeque fontstack;
                while (etag != *curtag) {
-                       os_ << curtag->asEndTag();
+                       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.
@@ -605,12 +699,12 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag)
        while (etag != *curtag) {
                writeError(curtag->tag_);
                if (*curtag != parsep_tag)
-                       os_ << curtag->asEndTag();
+                       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;
index 0bcc9849c0e354c9781cfcccdbe4bc7e06000589..c825a4d805f509e0be1898402639ae00b672b587 100644 (file)
@@ -31,6 +31,9 @@ class Text;
 
 namespace html {
 
+class FontTag;
+class EndFontTag;
+
 /// Attributes will be escaped automatically and so should NOT
 /// be escaped before being passed to the constructor.
 struct StartTag
@@ -44,16 +47,20 @@ struct StartTag
        ///
        ~StartTag() {}
        /// <tag_ attr_>
-       virtual docstring asTag() const;
+       virtual docstring writeTag() const;
        /// </tag_>
-       virtual docstring asEndTag() const;
+       virtual docstring writeEndTag() const;
        ///
-       bool operator==(StartTag const & rhs) const
+       virtual FontTag const * asFontTag() const { return 0; }
+       ///
+       virtual bool operator==(StartTag const & rhs) const
                { return tag_ == rhs.tag_; }
        ///
-       bool operator!=(StartTag const & rhs) const
+       virtual bool operator!=(StartTag const & rhs) const
                { return !(*this == rhs); }
        ///
+       virtual bool operator==(FontTag const & rhs) const;
+       ///
        std::string tag_;
        ///
        std::string attr_;
@@ -63,6 +70,46 @@ struct StartTag
 };
 
 
+///
+struct EndTag
+{
+       ///
+       explicit EndTag(std::string tag) : tag_(tag) {}
+       /// </tag_>
+       virtual docstring writeEndTag() const;
+       ///
+       bool operator==(StartTag const & rhs) const
+               { return tag_ == rhs.tag_; }
+       ///
+       bool operator!=(StartTag const & rhs) const
+               { return !(*this == rhs); }
+       ///
+       virtual EndFontTag const * asFontTag() const { return 0; }
+       ///
+       std::string tag_;
+};
+
+
+/// Tags like <img />
+/// Attributes will be escaped automatically and so should NOT
+/// be escaped before being passed to the constructor.
+struct CompTag
+{
+       ///
+       explicit CompTag(std::string const & tag)
+               : tag_(tag) {}
+       ///
+       explicit CompTag(std::string const & tag, std::string const & attr)
+               : tag_(tag), attr_(attr) {}
+       /// <tag_ attr_ />
+       docstring writeTag() const;
+       ///
+       std::string tag_;
+       ///
+       std::string attr_;
+};
+
+
 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
 struct ParTag : public StartTag
 {
@@ -74,7 +121,7 @@ struct ParTag : public StartTag
        ///
        ~ParTag() {}
        ///
-       docstring asTag() const;
+       docstring writeTag() const;
        /// the "magic par label" for this paragraph
        std::string parid_;
 };
@@ -105,56 +152,23 @@ struct FontTag : public StartTag
        ///
        explicit FontTag(FontTypes type);
        ///
-       docstring asTag() const;
+       FontTag const * asFontTag() const { return this; }
        ///
-       docstring asEndTag() const;
-       ///
-       bool isFontTag() { return true; }
-       ///
-       bool operator==(FontTag const & rhs)
-               { return font_type_ == rhs.font_type_; }
-       /// Asserts.
-       bool operator==(StartTag const &);
+       bool operator==(StartTag const &) const;
        ///
        FontTypes font_type_;
 };
 
 
 ///
-struct EndTag
+struct EndFontTag : public EndTag
 {
        ///
-       explicit EndTag(std::string tag) : tag_(tag) {}
-       /// </tag_>
-       docstring asEndTag() const;
+       explicit EndFontTag(FontTypes type);
        ///
-       bool operator==(StartTag const & rhs) const
-               { return tag_ == rhs.tag_; }
-       ///
-       bool operator!=(StartTag const & rhs) const
-               { return !(*this == rhs); }
+       EndFontTag const * asFontTag() const { return this; }
        ///
-       std::string tag_;
-};
-
-
-/// Tags like <img />
-/// Attributes will be escaped automatically and so should NOT
-/// be escaped before being passed to the constructor.
-struct CompTag
-{
-       ///
-       explicit CompTag(std::string const & tag)
-               : tag_(tag) {}
-       ///
-       explicit CompTag(std::string const & tag, std::string const & attr)
-               : tag_(tag), attr_(attr) {}
-       /// <tag_ attr_ />
-       docstring asTag() const;
-       ///
-       std::string tag_;
-       ///
-       std::string attr_;
+       FontTypes font_type_;
 };
 
 
@@ -201,6 +215,8 @@ public:
        ///
        XHTMLStream & operator<<(html::ParTag const &);
        ///
+       XHTMLStream & operator<<(html::FontTag const &);
+       ///
        XHTMLStream & operator<<(html::CR const &);
        ///
        enum EscapeSettings {