}
+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,
// 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?
}
-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())
}
-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())
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
// 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.
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();
}
}
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();
}
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?
// 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;
// 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();
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_ + "'.");
// ...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.
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;
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
///
~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_;
};
+///
+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
{
///
~ParTag() {}
///
- docstring asTag() const;
+ docstring writeTag() const;
/// the "magic par label" for this paragraph
std::string parid_;
};
///
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_;
};
///
XHTMLStream & operator<<(html::ParTag const &);
///
+ XHTMLStream & operator<<(html::FontTag const &);
+ ///
XHTMLStream & operator<<(html::CR const &);
///
enum EscapeSettings {