]> git.lyx.org Git - lyx.git/blobdiff - src/output_xhtml.cpp
New \cite_engine_type default.
[lyx.git] / src / output_xhtml.cpp
index 13e5c19f00bb9f9f9fa585182af3c8dfcce3eb3f..5130740fb743a250e556f69527e4e09c05d3586b 100644 (file)
@@ -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 = "</" + 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 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 <tag></tag>, 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