+ // is the tag we are closing the last one we opened?
+ if (etag.tag_ == tag_stack_.back().tag_) {
+ // output it...
+ os_ << etag.asEndTag();
+ // ...and forget about it
+ tag_stack_.pop_back();
+ return *this;
+ }
+
+ // 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_)) {
+ 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...
+ if (html::isFontTag(etag.tag_)) {
+ // it won't be a problem if the other tags open since this one
+ // are also font tags.
+ TagStack::const_reverse_iterator rit = tag_stack_.rbegin();
+ TagStack::const_reverse_iterator ren = tag_stack_.rend();
+ for (; rit != ren; ++rit) {
+ if (rit->tag_ == etag.tag_)
+ break;
+ if (!html::isFontTag(rit->tag_)) {
+ // 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_ + "'.");
+ return *this;
+ }
+ }
+
+ // so we have e.g.:
+ // <em>this is <strong>bold
+ // and are being asked to closed em. we want:
+ // <em>this is <strong>bold</strong></em><strong>
+ // first, we close the intervening tags...
+ html::StartTag curtag = tag_stack_.back();
+ // ...remembering them in a stack.
+ TagStack fontstack;
+ while (curtag.tag_ != etag.tag_) {
+ os_ << curtag.asEndTag();
+ fontstack.push_back(curtag);
+ tag_stack_.pop_back();
+ curtag = tag_stack_.back();
+ }
+ // now close our tag...
+ os_ << etag.asEndTag();
+ tag_stack_.pop_back();
+
+ // ...and restore the other tags.
+ rit = fontstack.rbegin();
+ ren = fontstack.rend();
+ for (; rit != ren; ++rit)
+ 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
+ // at least guarantees proper nesting.
+ writeError("Closing tag `" + etag.tag_
+ + "' when other tags are open, namely:");
+ html::StartTag curtag = tag_stack_.back();
+ while (curtag.tag_ != etag.tag_) {
+ writeError(curtag.tag_);
+ os_ << curtag.asEndTag();
+ tag_stack_.pop_back();
+ curtag = tag_stack_.back();
+ }
+ // curtag is now the one we actually want.
+ os_ << curtag.asEndTag();
+ tag_stack_.pop_back();
+
+ return *this;
+}
+
+// End code for XHTMLStream