X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_xhtml.cpp;h=e960e2c5d53ea0f8ba846e612b5c6dcd60cd26b0;hb=0fa905ceab4f665e4e90d424b071255f1b1ff345;hp=e6d53666f0530ca6a0c9b2a4064eca502b09e5db;hpb=c713030edbfc09db59358e07711a169a1a65c7a4;p=lyx.git diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp index e6d53666f0..e960e2c5d5 100644 --- a/src/output_xhtml.cpp +++ b/src/output_xhtml.cpp @@ -4,7 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Richard Heck - * + * * This code is based upon output_docbook.cpp * * Full author contact details are available in file CREDITS. @@ -85,53 +85,10 @@ docstring htmlize(docstring const & str, XHTMLStream::EscapeSettings e) } -string escapeChar(char c, XHTMLStream::EscapeSettings e) -{ - string str; - switch (e) { - case XHTMLStream::ESCAPE_NONE: - str += c; - break; - case XHTMLStream::ESCAPE_ALL: - if (c == '<') { - str += "<"; - break; - } else if (c == '>') { - str += ">"; - break; - } - // fall through - case XHTMLStream::ESCAPE_AND: - if (c == '&') - str += "&"; - else - str +=c ; - break; - } - return str; -} - - -// escape what needs escaping -string htmlize(string const & str, XHTMLStream::EscapeSettings e) -{ - ostringstream d; - string::const_iterator it = str.begin(); - string::const_iterator en = str.end(); - for (; it != en; ++it) - d << escapeChar(*it, e); - return d.str(); -} - - -string cleanAttr(string const & str) +docstring escapeChar(char c, XHTMLStream::EscapeSettings e) { - string newname; - string::const_iterator it = str.begin(); - string::const_iterator en = str.end(); - for (; it != en; ++it) - newname += isAlnumASCII(*it) ? *it : '_'; - return newname; + LATTEST(static_cast(c) < 0x80); + return escapeChar(static_cast(c), e); } @@ -144,17 +101,17 @@ docstring cleanAttr(docstring const & str) char_type const c = *it; newname += isAlnumASCII(c) ? c : char_type('_'); } - return newname; + return newname; } docstring StartTag::writeTag() const { - string output = "<" + tag_; + docstring output = '<' + from_utf8(tag_); if (!attr_.empty()) - output += " " + html::htmlize(attr_, XHTMLStream::ESCAPE_NONE); + output += ' ' + html::htmlize(from_utf8(attr_), XHTMLStream::ESCAPE_NONE); output += ">"; - return from_utf8(output); + return output; } @@ -193,11 +150,11 @@ docstring ParTag::writeTag() const docstring CompTag::writeTag() const { - string output = "<" + tag_; + docstring output = '<' + from_utf8(tag_); if (!attr_.empty()) - output += " " + html::htmlize(attr_, XHTMLStream::ESCAPE_NONE); + output += ' ' + html::htmlize(from_utf8(attr_), XHTMLStream::ESCAPE_NONE); output += " />"; - return from_utf8(output); + return output; } @@ -205,7 +162,7 @@ docstring CompTag::writeTag() const namespace { string fontToTag(html::FontTypes type) - { +{ switch(type) { case FT_EMPH: return "em"; @@ -227,54 +184,84 @@ string fontToTag(html::FontTypes type) 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); +string fontToAttribute(html::FontTypes type) +{ switch(type) { case FT_EMPH: - return html::StartTag(tag); case FT_BOLD: - return html::StartTag(tag); + return ""; case FT_NOUN: - return html::StartTag(tag, "class='lyxnoun'"); + return "class='lyxnoun'"; case FT_UBAR: - return html::StartTag(tag); + return ""; case FT_DBAR: - return html::StartTag(tag, "class='dline'"); + return "class='dline'"; case FT_SOUT: - return html::StartTag(tag, "class='strikeout'"); + return "class='strikeout'"; case FT_WAVE: - return html::StartTag(tag, "class='wline'"); + return "class='wline'"; case FT_ITALIC: - return html::StartTag(tag); + return ""; case FT_UPRIGHT: - return html::StartTag(tag, "style='font-style:normal;'"); + return "style='font-style:normal;'"; case FT_SLANTED: - return html::StartTag(tag, "style='font-style:oblique;'"); + return "style='font-style:oblique;'"; case FT_SMALLCAPS: - return html::StartTag(tag, "style='font-variant:small-caps;'"); + return "style='font-variant:small-caps;'"; case FT_ROMAN: - return html::StartTag(tag, "style='font-family:serif;'"); + return "style='font-family:serif;'"; case FT_SANS: - return html::StartTag(tag, "style='font-family:sans-serif;'"); + return "style='font-family:sans-serif;'"; case FT_TYPE: - return html::StartTag(tag, "style='font-family:monospace;'"); + return "style='font-family:monospace;'"; + case FT_SIZE_TINY: + case FT_SIZE_SCRIPT: + case FT_SIZE_FOOTNOTE: + return "style='font-size:x-small;'"; + case FT_SIZE_SMALL: + return "style='font-size:small;'"; + case FT_SIZE_NORMAL: + return "style='font-size:normal;'"; + case FT_SIZE_LARGE: + return "style='font-size:large;'"; + case FT_SIZE_LARGER: + case FT_SIZE_LARGEST: + return "style='font-size:x-large;'"; + case FT_SIZE_HUGE: + case FT_SIZE_HUGER: + return "style='font-size:xx-large;'"; + case FT_SIZE_INCREASE: + return "style='font-size:larger;'"; + case FT_SIZE_DECREASE: + return "style='font-size:smaller;'"; } // kill warning - return StartTag(""); + return ""; } } // end anonymous namespace FontTag::FontTag(FontTypes type) - : StartTag(fontToStartTag(type)), font_type_(type) + : StartTag(fontToTag(type), fontToAttribute(type)), font_type_(type) {} @@ -360,7 +347,7 @@ bool XHTMLStream::closeFontTags() LBUFERR(!tag_stack_.empty()); curtag = tag_stack_.back(); } - + if (*curtag == parsep_tag) return true; @@ -408,7 +395,7 @@ void XHTMLStream::endParagraph() return; } - // this case is also normal, if the parsep tag is the last one + // this case is also normal, if the parsep tag is the last one // on the stack. otherwise, it's an error. while (!tag_stack_.empty()) { TagPtr const cur_tag = tag_stack_.back(); @@ -465,7 +452,7 @@ XHTMLStream & XHTMLStream::operator<<(char_type c) XHTMLStream & XHTMLStream::operator<<(char c) { clearTagDeque(); - string const d = html::escapeChar(c, escape_); + os_ << html::escapeChar(c, escape_); escape_ = ESCAPE_ALL; return *this; } @@ -481,13 +468,13 @@ XHTMLStream & XHTMLStream::operator<<(int i) XHTMLStream & XHTMLStream::operator<<(EscapeSettings e) -{ +{ escape_ = e; return *this; } -XHTMLStream & XHTMLStream::operator<<(html::StartTag const & tag) +XHTMLStream & XHTMLStream::operator<<(html::StartTag const & tag) { if (tag.tag_.empty()) return *this; @@ -507,7 +494,7 @@ XHTMLStream & XHTMLStream::operator<<(html::ParTag const & tag) } -XHTMLStream & XHTMLStream::operator<<(html::CompTag const & tag) +XHTMLStream & XHTMLStream::operator<<(html::CompTag const & tag) { if (tag.tag_.empty()) return *this; @@ -569,7 +556,7 @@ bool XHTMLStream::isTagPending(html::StartTag const & stag) const // this is complicated, because we want to make sure that -// everything is properly nested. the code ought to make +// everything is properly nested. the code ought to make // sure of that, but we won't assert (yet) if we run into // a problem. we'll just output error messages and try our // best to make things work. @@ -582,14 +569,14 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) if (!pending_tags_.empty()) { if (etag == *pending_tags_.back()) { - // we have , so we discard it and remove it + // we have , so we discard it and remove it // from the pending_tags_. pending_tags_.pop_back(); return *this; } // there is a pending tag that isn't the one we are trying - // to close. + // to close. // is this tag itself pending? // non-const iterators because we may call erase(). @@ -598,9 +585,9 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) for (; dit != den; ++dit) { if (etag == **dit) { // it was pending, so we just erase it - writeError("Tried to close pending tag `" + etag.tag_ + writeError("Tried to close pending tag `" + etag.tag_ + "' when other tags were pending. Last pending tag is `" - + to_utf8(pending_tags_.back()->writeTag()) + + to_utf8(pending_tags_.back()->writeTag()) + "'. Tag discarded."); pending_tags_.erase(dit); return *this; @@ -608,14 +595,14 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) } // so etag isn't itself pending. is it even open? if (!isTagOpen(etag)) { - writeError("Tried to close `" + etag.tag_ + writeError("Tried to close `" + etag.tag_ + "' when tag was not open. Tag discarded."); return *this; } // ok, so etag is open. - // our strategy will be as below: we will do what we need to + // our strategy will be as below: we will do what we need to // do to close this tag. - string estr = "Closing tag `" + etag.tag_ + string estr = "Closing tag `" + etag.tag_ + "' when other tags are pending. Discarded pending tags:\n"; for (dit = pending_tags_.begin(); dit != den; ++dit) estr += to_utf8(html::htmlize((*dit)->writeTag(), XHTMLStream::ESCAPE_ALL)) + "\n"; @@ -629,7 +616,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) if (tag_stack_.empty()) { writeError("Tried to close `" + etag.tag_ + "' when no tags were open!"); - return *this; + return *this; } // is the tag we are closing the last one we opened? @@ -639,16 +626,16 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // ...and forget about it tag_stack_.pop_back(); return *this; - } - - // we are trying to close a tag other than the one last opened. + } + + // 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)) { - writeError("Tried to close `" + etag.tag_ + writeError("Tried to close `" + etag.tag_ + "' when tag was not open. Tag discarded."); 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... @@ -662,12 +649,12 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) break; if (!(*rit)->asFontTag()) { // we'll just leave it and, presumably, have to close it later. - writeError("Unable to close font tag `" + etag.tag_ + writeError("Unable to close font tag `" + etag.tag_ + "' due to open non-font tag `" + (*rit)->tag_ + "'."); return *this; } } - + // so we have e.g.: // this is bold // and are being asked to closed em. we want: @@ -682,7 +669,7 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) tag_stack_.pop_back(); curtag = tag_stack_.back(); } - os_ << etag.writeEndTag(); + os_ << etag.writeEndTag(); tag_stack_.pop_back(); // ...and restore the other tags. @@ -692,12 +679,12 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) pending_tags_.push_back(*rit); return *this; } - + // it wasn't a font tag. - // so other tags were opened before this one and not properly closed. - // so we'll close them, too. that may cause other issues later, but it + // so other tags were opened before this one and not properly closed. + // so we'll close them, too. that may cause other issues later, but it // at least guarantees proper nesting. - writeError("Closing tag `" + etag.tag_ + writeError("Closing tag `" + etag.tag_ + "' when other tags are open, namely:"); TagPtr curtag = tag_stack_.back(); while (etag != *curtag) { @@ -710,35 +697,15 @@ XHTMLStream & XHTMLStream::operator<<(html::EndTag const & etag) // curtag is now the one we actually want. os_ << curtag->writeEndTag(); tag_stack_.pop_back(); - + return *this; } // End code for XHTMLStream namespace { - -// convenience functions - -inline void openTag(XHTMLStream & xs, Layout const & lay) -{ - xs << html::StartTag(lay.htmltag(), lay.htmlattr()); -} - - -void openTag(XHTMLStream & xs, Layout const & lay, - ParagraphParameters const & params) -{ - // FIXME Are there other things we should handle here? - string const align = alignmentToCSS(params.align()); - if (align.empty()) { - openTag(xs, lay); - return; - } - string attrs = lay.htmlattr() + " style='text-align: " + align + ";'"; - xs << html::StartTag(lay.htmltag(), attrs); -} +// convenience functions inline void openParTag(XHTMLStream & xs, Layout const & lay, std::string parlabel) @@ -786,7 +753,7 @@ inline void openItemTag(XHTMLStream & xs, Layout const & lay) } -void openItemTag(XHTMLStream & xs, Layout const & lay, +void openItemTag(XHTMLStream & xs, Layout const & lay, ParagraphParameters const & params) { // FIXME Are there other things we should handle here? @@ -819,7 +786,7 @@ ParagraphList::const_iterator findLastParagraph( ParagraphList::const_iterator findEndOfEnvironment( - ParagraphList::const_iterator const pstart, + ParagraphList::const_iterator const & pstart, ParagraphList::const_iterator const & pend) { ParagraphList::const_iterator p = pstart; @@ -832,15 +799,19 @@ ParagraphList::const_iterator findEndOfEnvironment( // it can happen. We pretend that it's just at lowest depth. if (style.latextype == LATEX_COMMAND) return p; + // If depth is down, we're done if (p->params().depth() < depth) return p; + // If depth is up, we're not done if (p->params().depth() > depth) continue; - // Now we know we are at the same depth - if (style.latextype == LATEX_PARAGRAPH - || style.latexname() != bstyle.latexname()) + + // FIXME I am not sure about the first check. + // Surely we *could* have different layouts that count as + // LATEX_PARAGRAPH, right? + if (style.latextype == LATEX_PARAGRAPH || style != bstyle) return p; } return pend; @@ -878,17 +849,17 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf, openParTag(xs, lay, par->params(), make_parid ? par->magicLabel() : ""); - docstring const deferred = + docstring const deferred = par->simpleLyXHTMLOnePar(buf, xs, runparams, text.outerFont(distance(begin, par))); // We want to issue the closing tag if either: // (i) We opened it, and either html_in_par is false, // or we're not in the last paragraph, anyway. - // (ii) We didn't open it and html_in_par is true, + // (ii) We didn't open it and html_in_par is true, // but we are in the first par, and there is a next par. ParagraphList::const_iterator nextpar = par; ++nextpar; - bool const needclose = + bool const needclose = (opened && (!runparams.html_in_par || nextpar != pend)) || (!opened && runparams.html_in_par && par == pbegin && nextpar != pend); if (needclose) { @@ -908,7 +879,7 @@ ParagraphList::const_iterator makeBibliography(Buffer const & buf, OutputParams const & runparams, Text const & text, ParagraphList::const_iterator const & pbegin, - ParagraphList::const_iterator const & pend) + ParagraphList::const_iterator const & pend) { // FIXME XHTML // Use TextClass::htmlTOCLayout() to figure out how we should look. @@ -930,13 +901,13 @@ bool isNormalEnv(Layout const & lay) || lay.latextype == LATEX_BIB_ENVIRONMENT; } - + ParagraphList::const_iterator makeEnvironment(Buffer const & buf, XHTMLStream & xs, OutputParams const & runparams, Text const & text, ParagraphList::const_iterator const & pbegin, - ParagraphList::const_iterator const & pend) + ParagraphList::const_iterator const & pend) { ParagraphList::const_iterator const begin = text.paragraphs().begin(); ParagraphList::const_iterator par = pbegin; @@ -960,22 +931,19 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, // "ii", etc, as with enum. Counters & cnts = buf.masterBuffer()->params().documentClass().counters(); docstring const & cntr = style.counter; - if (!style.counter.empty() - && (par == pbegin || !isNormalEnv(style)) + if (!style.counter.empty() + && (par == pbegin || !isNormalEnv(style)) && cnts.hasCounter(cntr) ) cnts.step(cntr, OutputUpdate); ParagraphList::const_iterator send; - // this will be positive, if we want to skip the initial word - // (if it's been taken for the label). - pos_type sep = 0; switch (style.latextype) { case LATEX_ENVIRONMENT: case LATEX_LIST_ENVIRONMENT: case LATEX_ITEM_ENVIRONMENT: { - // There are two possiblities in this case. - // One is that we are still in the environment in which we + // There are two possiblities in this case. + // One is that we are still in the environment in which we // started---which we will be if the depth is the same. if (par->params().depth() == origdepth) { LATTEST(bstyle == style); @@ -983,19 +951,22 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, closeItemTag(xs, *lastlay); lastlay = 0; } - + + // this will be positive, if we want to skip the + // initial word (if it's been taken for the label). + pos_type sep = 0; bool const labelfirst = style.htmllabelfirst(); if (!labelfirst) openItemTag(xs, style, par->params()); - + // label output - if (style.labeltype != LABEL_NO_LABEL && + if (style.labeltype != LABEL_NO_LABEL && style.htmllabeltag() != "NONE") { if (isNormalEnv(style)) { - // in this case, we print the label only for the first + // in this case, we print the label only for the first // paragraph (as in a theorem). if (par == pbegin) { - docstring const lbl = + docstring const lbl = pbegin->params().labelString(); if (!lbl.empty()) { openLabelTag(xs, style); @@ -1004,7 +975,7 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, } xs << html::CR(); } - } else { // some kind of list + } else { // some kind of list if (style.labeltype == LABEL_MANUAL) { openLabelTag(xs, style); sep = par->firstWordLyXHTML(xs, runparams); @@ -1023,13 +994,13 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf, if (labelfirst) openItemTag(xs, style, par->params()); - par->simpleLyXHTMLOnePar(buf, xs, runparams, + par->simpleLyXHTMLOnePar(buf, xs, runparams, text.outerFont(distance(begin, par)), sep); ++par; // We may not want to close the tag yet, in particular: // If we're not at the end... - if (par != pend + if (par != pend // and are doing items... && !isNormalEnv(style) // and if the depth has changed... @@ -1151,7 +1122,7 @@ void xhtmlParagraphs(Text const & text, case LATEX_COMMAND: { // The files with which we are working never have more than // one paragraph in a command structure. - // FIXME + // FIXME // if (ourparams.html_in_par) // fix it so we don't get sections inside standard, e.g. // note that we may then need to make runparams not const, so we