mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 13:18:28 +00:00
Rework that way that font tags are handled in XHTML output. We need
to do this in order to handle span tags properly, when they act as font tags.
This commit is contained in:
parent
64f0cffbba
commit
5cadeed4d7
@ -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?
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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_; }
|
||||
EndFontTag const * asFontTag() const { return this; }
|
||||
///
|
||||
bool operator!=(StartTag const & rhs) const
|
||||
{ return !(*this == rhs); }
|
||||
///
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user