PATCH: RTF style export


Subject: PATCH: RTF style export
From: David Mandelin (mandelin@cs.wisc.edu)
Date: Wed Sep 12 2001 - 17:06:43 CDT


A diff for abi/src/wp and 2 new files. It's sort of rough right now, but
it works for me. Still left:

1. handle list styles
2. merge more style/content code.

Regarding #2, I based a lot of the style sheet code on the document
content code. For example, I reused the part that generates character
formatting information. In some cases, I modified the code to make it
reusable and then reused it. In others, I copied code. I want to fix
that.

The 2 new files are for an adapter class that I use so that the RTF
export code doesn't have to worry about the 2 different methods of
getting properties.

Index: impexp/xp/Makefile
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/Makefile,v
retrieving revision 1.62
diff -u -r1.62 Makefile
--- impexp/xp/Makefile 2001/08/29 10:02:38 1.62
+++ impexp/xp/Makefile 2001/09/12 22:00:40
@@ -33,6 +33,7 @@
                         ie_exp_Text.cpp \
                         ie_exp_HRText.cpp \
                         ie_exp_RTF.cpp \
+ ie_exp_RTF_AttrProp.cpp \
                         ie_exp_RTF_listenerGetProps.cpp \
                         ie_exp_RTF_listenerWriteDoc.cpp \
                         ie_exp_LaTeX.cpp \
Index: impexp/xp/ie_exp_RTF.cpp
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/ie_exp_RTF.cpp,v
retrieving revision 1.24
diff -u -r1.24 ie_exp_RTF.cpp
--- impexp/xp/ie_exp_RTF.cpp 2001/07/27 20:49:47 1.24
+++ impexp/xp/ie_exp_RTF.cpp 2001/09/12 22:00:40
@@ -23,6 +23,7 @@
 #include "ut_base64.h"
 #include "ut_misc.h"
 #include "ut_units.h"
+#include "ut_vector.h"
 #include "pt_Types.h"
 #include "ie_exp_RTF.h"
 #include "pd_Document.h"
@@ -43,6 +44,7 @@
 /*****************************************************************/
 /*****************************************************************/
 
+#include "ie_exp_RTF_AttrProp.h"
 #include "ie_exp_RTF_listenerWriteDoc.h"
 #include "ie_exp_RTF_listenerGetProps.h"
 
@@ -77,6 +79,7 @@
 {
         UT_VECTOR_FREEALL(char *,m_vecColors);
         UT_VECTOR_PURGEALL(_rtf_font_info *,m_vecFonts);
+ _clearStyles();
 }
 
 /*****************************************************************/
@@ -159,6 +162,10 @@
                 getDoc()->tellListener(static_cast<PL_Listener *>(m_pListenerGetProps));
         DELETEP(m_pListenerGetProps);
 
+ // Important: This must come before the header is written so
+ // every font used in a style is properly entered in the font table.
+ _selectStyles();
+
         // write rtf header
 
         if (!_write_rtf_header())
@@ -187,33 +194,6 @@
 /*****************************************************************/
 /*****************************************************************/
 #if 0
-void s_RTF_Listener::_handleStyles(void)
-{
- bool bWroteOpenStyleSection = false;
-
- const char * szName;
- const PD_Style * pStyle;
-
- for (UT_uint32 k=0; (m_pDocument->enumStyles(k,&szName,&pStyle)); k++)
- {
- if (!pStyle->isUsed())
- continue;
-
- if (!bWroteOpenStyleSection)
- {
- m_pie->write("<styles>\n");
- bWroteOpenStyleSection = true;
- }
-
- PT_AttrPropIndex api = pStyle->getIndexAP();
- _openTag("s","/",true,api);
- }
-
- if (bWroteOpenStyleSection)
- m_pie->write("</styles>\n");
-
- return;
-}
 
 void s_RTF_Listener::_handleDataItems(void)
 {
@@ -513,20 +493,13 @@
                 for (k=0; k<kLimit; k++)
                 {
                         const _rtf_font_info * pk = (const _rtf_font_info *)m_vecFonts.getNthItem(k);
- const char * szFontName = NULL;
- const char * szFamily = NULL;
- int pitch;
- bool bTrueType;
-
- _rtf_compute_font_properties(pk,&szFontName,&szFamily,&pitch,&bTrueType);
-
                         _rtf_nl();
                         _rtf_open_brace();
- _rtf_keyword("f",k); // font index number
- _rtf_keyword(szFamily); // {\fnil,\froman,\fswiss,...}
- _rtf_keyword("fcharset",charsetcode);
- _rtf_keyword("fprq",pitch); // {0==default,1==fixed,2==variable}
- _rtf_keyword((bTrueType) ? "fttruetype" : "ftnil"); // {\fttruetype,\ftnil}
+ _rtf_keyword("f", k); // font index number
+ _rtf_keyword(pk->szFamily); // {\fnil,\froman,\fswiss,...}
+ _rtf_keyword("fcharset",pk->nCharset);
+ _rtf_keyword("fprq",pk->nPitch); // {0==default,1==fixed,2==variable}
+ _rtf_keyword((pk->fTrueType) ? "fttruetype" : "ftnil"); // {\fttruetype,\ftnil}
                         
                         // we do nothing with or use default values for
                         // \falt \panose \fname \fbias \ftnil \fttruetype \fontfile
@@ -535,7 +508,7 @@
                         // the actual font name and a semicolon -- i couldn't see this
                         // described in the specification, but it was in other RTF files
                         // that i saw and really seems to help Word and WordPad....
- _rtf_fontname(szFontName);
+ _rtf_fontname(pk->szName);
                         
                         _rtf_close_brace();
                 }
@@ -564,7 +537,7 @@
                 _rtf_close_brace();
         }
 
- // TODO write the "style sheets"...
+ _write_stylesheets();
         // TODO write the "list table"...
         // TODO write the "rev table"...
 
@@ -576,12 +549,441 @@
         return (m_error == 0);
 }
 
+/*!
+ * Write an rtf keyword if the given property isn't the default
+ * value. Use this only with twips-valued properties.
+ *
+ * !param pStyle A style.
+ * !param szPropName The property to check.
+ * !param szRTFName The RTF keyword to use if the property
+ * doesn't have the default value.
+ */
+void IE_Exp_RTF::_write_prop_ifnotdefault(const PD_Style * pStyle,
+ const XML_Char * szPropName,
+ const char * szRTFName)
+{
+ XML_Char * sz;
+ if (pStyle->getProperty(szPropName, sz)) {
+ _rtf_keyword_ifnotdefault_twips(szRTFName, sz, 0);
+ }
+}
+
+/*!
+ * Write an RTF keyword if the given property is "yes".
+ */
+void IE_Exp_RTF::_write_prop_ifyes(const PD_Style * pStyle,
+ const XML_Char * szPropName,
+ const char * szRTFName)
+{
+ XML_Char * sz;
+ if (pStyle->getProperty(szPropName, sz) && UT_strcmp(sz, "yes") == 0) {
+ _rtf_keyword(szRTFName);
+ }
+}
+
+/*
+ * Used to hold tab information by _write_tabdef.
+ */
+class _t
+{
+public:
+ _t(const char * szTL, const char * szTT, const char * szTK, UT_sint32 tp)
+ {
+ m_szTabLeaderKeyword = szTL;
+ m_szTabTypeKeyword = szTT;
+ m_szTabKindKeyword = szTK;
+ m_iTabPosition = tp;
+ }
+ const char * m_szTabLeaderKeyword;
+ const char * m_szTabTypeKeyword;
+ const char * m_szTabKindKeyword;
+ UT_sint32 m_iTabPosition;
+};
+
+static int compare_tabs(const void* p1, const void* p2)
+{
+ _t ** ppTab1 = (_t **) p1;
+ _t ** ppTab2 = (_t **) p2;
+
+ if ((*ppTab1)->m_iTabPosition < (*ppTab2)->m_iTabPosition)
+ return -1;
+ if ((*ppTab1)->m_iTabPosition > (*ppTab2)->m_iTabPosition)
+ return 1;
+ return 0;
+}
+
+/*!
+ * Write out the <tabdef> paragraph formatting.
+ */
+void IE_Exp_RTF::_write_tabdef(const char * szTabStops)
+{
+ if (szTabStops && *szTabStops)
+ {
+ // write tabstops for this paragraph
+ // TODO the following parser was copied from abi/src/text/fmt/xp/fl_BlockLayout.cpp
+ // TODO we should extract both of them and share the code.
+
+ UT_Vector vecTabs;
+
+ const char* pStart = szTabStops;
+ while (*pStart)
+ {
+ const char * szTT = "tx"; // TabType -- assume text tab (use "tb" for bar tab)
+ const char * szTK = NULL; // TabKind -- assume left tab
+ const char * szTL = NULL; // TabLeader
+ const char* pEnd = pStart;
+ while (*pEnd && (*pEnd != ','))
+ pEnd++;
+ const char* p1 = pStart;
+ while ((p1 < pEnd) && (*p1 != '/'))
+ p1++;
+ if ( (p1 == pEnd) || ((p1+1) == pEnd) )
+ ; // left-tab is default
+ else
+ {
+ switch (p1[1])
+ {
+ default:
+ case 'L': szTK = NULL; break;
+ case 'R': szTK = "tqr"; break;
+ case 'C': szTK = "tqc"; break;
+ case 'D': szTK = "tqdec"; break;
+ case 'B': szTT = "tb"; szTK= NULL; break; // TabKind == bar tab
+ }
+ switch (p1[2])
+ {
+ default:
+ case '0': szTL = NULL; break;
+ case '1': szTL = "tldot"; break;
+ case '2': szTL = "tlhyph"; break;
+ case '3': szTL = "tlul"; break;
+ case '4': szTL = "tleq"; break;
+ }
+ }
+
+ char pszPosition[32];
+ UT_uint32 iPosLen = p1 - pStart;
+ UT_ASSERT(iPosLen < 32);
+ UT_uint32 k;
+ for (k=0; k<iPosLen; k++)
+ pszPosition[k] = pStart[k];
+ pszPosition[k] = 0;
+ // convert position into twips
+ double dbl = UT_convertToPoints(pszPosition);
+ UT_sint32 d = (UT_sint32)(dbl * 20.0);
+
+ _t * p_t = new _t(szTL,szTT,szTK,d);
+ vecTabs.addItem(p_t);
+
+ pStart = pEnd;
+ if (*pStart)
+ {
+ pStart++; // skip past delimiter
+ while (*pStart == UCS_SPACE)
+ pStart++;
+ }
+ }
+
+ // write each tab in order:
+ // <tabdef> ::= ( <tab> | <bartab> )+
+ // <tab> ::= <tabkind>? <tablead>? \tx
+ // <bartab> ::= <tablead>? \tb
+
+ vecTabs.qsort(compare_tabs);
+
+ UT_uint32 k;
+ UT_uint32 kLimit = vecTabs.getItemCount();
+ for (k=0; k<kLimit; k++)
+ {
+ _t * p_t = (_t *)vecTabs.getNthItem(k);
+ // write <tabkind>
+ if (p_t->m_szTabKindKeyword && *p_t->m_szTabKindKeyword)
+ _rtf_keyword(p_t->m_szTabKindKeyword);
+ if (p_t->m_szTabLeaderKeyword && *p_t->m_szTabLeaderKeyword)
+ _rtf_keyword(p_t->m_szTabLeaderKeyword);
+ _rtf_keyword(p_t->m_szTabTypeKeyword,p_t->m_iTabPosition);
+
+ delete p_t;
+ }
+ }
+}
+
+/*!
+ * Write out the <charfmt> paragraph or character formatting. This
+ * does not print opening and closing braces.
+ */
+void IE_Exp_RTF::_write_charfmt(const s_RTF_AttrPropAdapter & apa)
+{
+ const XML_Char * szColor = apa.getProperty("color");
+ UT_sint32 ndxColor = _findColor((char*)szColor);
+ UT_ASSERT(ndxColor != -1);
+
+ if (ndxColor != 0) // black text, the default
+ _rtf_keyword("cf",ndxColor);
+
+ szColor = apa.getProperty("bgcolor");
+
+ if (szColor && UT_stricmp (szColor, "transparent") != 0)
+ {
+ ndxColor = _findColor((char*)szColor);
+ UT_ASSERT(ndxColor != -1);
+ if (ndxColor != 1) // white background, the default
+ {
+ _rtf_keyword("cb",ndxColor);
+ }
+ }
+
+ _rtf_font_info fi(apa);
+ UT_sint32 ndxFont = _findFont(&fi);
+ UT_ASSERT(ndxFont != -1);
+ _rtf_keyword("f",ndxFont); // font index in fonttbl
+
+ const XML_Char * szFontSize = apa.getProperty("font-size");
+ double dbl = UT_convertToPoints(szFontSize);
+ UT_sint32 d = (UT_sint32)(dbl*2.0);
+
+ // if (d != 24) - always write this out
+ _rtf_keyword("fs",d); // font size in half points
+
+ const XML_Char * szFontStyle = apa.getProperty("font-style");
+ if (szFontStyle && *szFontStyle && (UT_strcmp(szFontStyle,"italic")==0))
+ _rtf_keyword("i");
+
+ const XML_Char * szFontWeight = apa.getProperty("font-weight");
+ if (szFontWeight && *szFontWeight && (UT_strcmp(szFontWeight,"bold")==0))
+ _rtf_keyword("b");
+
+ const XML_Char * szFontDecoration = apa.getProperty("text-decoration");
+ if (szFontDecoration && *szFontDecoration)
+ {
+ if (strstr(szFontDecoration,"underline") != 0)
+ _rtf_keyword("ul");
+ if (strstr(szFontDecoration,"overline") != 0)
+ _rtf_keyword("ol");
+ if (strstr(szFontDecoration,"line-through") != 0)
+ _rtf_keyword("strike");
+ if (strstr(szFontDecoration,"topline") != 0)
+ {
+ _rtf_keyword("*");
+ _rtf_keyword("topline");
+ }
+ if (strstr(szFontDecoration,"bottomline") != 0)
+ {
+ _rtf_keyword("*");
+ _rtf_keyword("botline");
+ }
+ }
+
+ const XML_Char * szFontPosition = apa.getProperty("text-position");
+ if (szFontPosition && *szFontPosition)
+ {
+ if (!UT_strcmp(szFontPosition,"superscript"))
+ _rtf_keyword("super");
+ else if (!UT_strcmp(szFontPosition,"subscript"))
+ _rtf_keyword("sub");
+ }
+
+#if 0
+ const XML_Char * szLang = apa.getProperty("lang");
+ // TODO: convert lang to numerical code
+#endif
+
+#ifdef BIDI_ENABLED
+
+ const XML_Char * szDir = apa.getProperty("dir");
+
+ if (szDir)
+ {
+ if (!UT_strcmp (szDir, "ltr"))
+ _rtf_keyword ("ltrch");
+ else
+ _rtf_keyword ("rtlch");
+ }
+
+#endif
+ // TODO do something with our font-stretch and font-variant properties
+ // note: we assume that kerning has been turned off at global scope.
+}
+
+/*!
+ * Write out the formatting group for one style in the RTF header.
+ */
+void IE_Exp_RTF::_write_style_fmt(const PD_Style * pStyle)
+{
+ // brdrdef: not implemented because AbiWord does not have borders
+ // at time of this writing.
+
+ // parfmt
+ _write_prop_ifyes(pStyle, "keep-together", "keep");
+ _write_prop_ifyes(pStyle, "keep-with-next", "keepn");
+
+ XML_Char * sz;
+ if (pStyle->getProperty("text-align", sz)) {
+ if (UT_strcmp(sz, "left") == 0) {
+ // Default, so no need to print anything
+ } else if (UT_strcmp(sz, "right") == 0) {
+ _rtf_keyword("qr");
+ } else if (UT_strcmp(sz, "center") == 0) {
+ _rtf_keyword("qc");
+ } else if (UT_strcmp(sz, "justify") == 0) {
+ _rtf_keyword("qj");
+ } else {
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ }
+ }
+
+ XML_Char * szLineHeight;
+ if (pStyle->getProperty("line-height", szLineHeight)
+ && strcmp(szLineHeight,"1.0") != 0) {
+ double f = UT_convertDimensionless(szLineHeight);
+ if (f != 0.0) {
+ UT_sint32 dSpacing = (UT_sint32)(f * 240.0);
+ _rtf_keyword("sl",dSpacing);
+ _rtf_keyword("slmult",1);
+ }
+ }
+
+ _write_prop_ifnotdefault(pStyle, "text-indent", "fi");
+ _write_prop_ifnotdefault(pStyle, "margin-left", "li");
+ _write_prop_ifnotdefault(pStyle, "margin-right", "ri");
+ _write_prop_ifnotdefault(pStyle, "margin-top", "sb");
+ _write_prop_ifnotdefault(pStyle, "margin-bottom", "sa");
+
+ // apoctl
+
+ // tabdef
+ if (pStyle->getProperty("tabstops", sz)) _write_tabdef(sz);
+
+
+ // shading
+
+ // chrfmt
+ _write_charfmt(s_RTF_AttrPropAdapter_Style(pStyle));
+}
+
+/*!
+ * This is just a pair: style and style number. It is used for
+ * two-way association of PD_Style and RTF style number.
+ */
+struct NumberedStyle
+{
+ const PD_Style * pStyle;
+ UT_uint32 n;
+
+ NumberedStyle(const PD_Style * pStyle, UT_uint32 n) :
+ pStyle(pStyle), n(n) {}
+};
+
+/*!
+ * Clear the style hash.
+ */
+void IE_Exp_RTF::_clearStyles()
+{
+ UT_HASH_PURGEDATA(NumberedStyle *, &m_hashStyles, delete);
+}
+
+/*!
+ * Select styles for export. This inserts all styles to be exported
+ * into the style hash. Also, it makes sure that all fonts used in
+ * styles are present in the font table.
+ */
+void IE_Exp_RTF::_selectStyles()
+{
+ _clearStyles();
+
+ UT_uint32 i;
+ UT_uint32 nStyleNumber = 0;
+ const char * szName;
+ const PD_Style * pStyle;
+ for (i = 0; getDoc()->enumStyles(i, &szName, &pStyle); ++i) {
+ if (pStyle->isUsed() || pStyle->isUserDefined()) {
+ m_hashStyles.insert(szName, new NumberedStyle(pStyle, ++nStyleNumber));
+ _rtf_font_info fi(static_cast<s_RTF_AttrPropAdapter_Style>(pStyle));
+ if (_findFont(&fi) == -1)
+ _addFont(&fi);
+ }
+ }
+}
+
+/*!
+ * Return the style number that was assigned to the given style.
+ * The style must be present in the style hash.
+ */
+UT_uint32 IE_Exp_RTF::_getStyleNumber(const PD_Style * pStyle)
+{
+ return _getStyleNumber(pStyle->getName());
+}
+
+/*!
+ * Return the style number that was assigned to the named style.
+ * The style must be present in the style hash.
+ */
+UT_uint32 IE_Exp_RTF::_getStyleNumber(const XML_Char * szStyle)
+{
+ const NumberedStyle * pns = reinterpret_cast<const NumberedStyle *>(m_hashStyles.pick(szStyle));
+ UT_ASSERT(pns != NULL);
+ return pns->n;
+}
+
+/*!
+ * Write the stylesheets group of the RTF header. Only styles that
+ * are used by the document are written.
+ */
+void IE_Exp_RTF::_write_stylesheets(void)
+{
+ if (getDoc()->getStyleCount() == 0) return;
+
+ _rtf_nl();
+ _rtf_open_brace();
+ _rtf_keyword("stylesheet");
+
+ UT_StringPtrMap::UT_Cursor hc(&m_hashStyles);
+ const NumberedStyle * pns;
+ for (pns = reinterpret_cast<const NumberedStyle *>(hc.first());
+ hc.is_valid();
+ pns = reinterpret_cast<const NumberedStyle *>(hc.next())) {
+ const PD_Style * pStyle = pns->pStyle;
+ _rtf_nl();
+ _rtf_open_brace();
+
+ if (pStyle->isCharStyle()) {
+ _rtf_keyword("*");
+ _rtf_keyword("cs", pns->n);
+ } else {
+ _rtf_keyword("s", pns->n);
+ }
+
+ _write_style_fmt(pStyle);
+
+ const PD_Style * pStyleBasedOn = pStyle->getBasedOn();
+ // TODO: Can this really return NULL?
+ if (pStyleBasedOn != NULL) {
+ _rtf_keyword("sbasedon", _getStyleNumber(pStyleBasedOn));
+ }
+
+ const PD_Style * pStyleNext = pStyle->getFollowedBy();
+ // TODO: Can this really return NULL?
+ if (pStyleNext != NULL) {
+ _rtf_keyword("snext", _getStyleNumber(pStyleNext));
+ }
+
+ _rtf_chardata(pStyle->getName(), strlen(pStyle->getName()));
+ _rtf_close_brace();
+ }
+
+ _rtf_close_brace();
+}
+
 bool IE_Exp_RTF::_write_rtf_trailer(void)
 {
         _rtf_close_brace();
         return (m_error == 0);
 }
 
+/*!
+ * Find a font in the font table. Return the index of the font. If
+ * it is not found, return -1.
+ */
 UT_sint32 IE_Exp_RTF::_findFont(const _rtf_font_info * pfi) const
 {
         UT_ASSERT(pfi);
@@ -592,60 +994,56 @@
         for (k=0; k<kLimit; k++)
         {
                 const _rtf_font_info * pk = (const _rtf_font_info *)m_vecFonts.getNthItem(k);
- if (pk->_is_same(pfi))
+ if (pk->_is_same(*pfi))
                         return k;
         }
 
         return -1;
 }
 
+/*!
+ * Add a font to the font table. The font must not be present
+ * in the font table at the start of the call.
+ */
 void IE_Exp_RTF::_addFont(const _rtf_font_info * pfi)
 {
         UT_ASSERT(pfi && (_findFont(pfi)==-1));
-
- // note: this does not guarantee uniqueness of actual fonts,
- // note: since the three AP's may have other stuff besides
- // note: just font info -- two identical fonts with different
- // note: colors, for example -- will appear as two distinct
- // note: entries -- we don't care.
-
         _rtf_font_info * pNew = new _rtf_font_info(*pfi);
         if (pNew)
                 m_vecFonts.addItem(pNew);
 
         return;
 }
-
-void IE_Exp_RTF::_rtf_compute_font_properties(const _rtf_font_info * pfi,
- const char ** p_sz_font_name,
- const char ** p_sz_rtf_family,
- int * p_rtf_pitch,
- bool * p_rtf_bTrueType) const
-{
- static const char * t_ff[] = { "fnil", "froman", "fswiss", "fmodern", "fscript", "fdecor", "ftech", "fbidi" };
-
- const XML_Char * szFontFamily = PP_evalProperty("font-family",
- pfi->m_pSpanAP,pfi->m_pBlockAP,pfi->m_pSectionAP,
- getDoc(),true);
-
- GR_Font::FontFamilyEnum ff;
- GR_Font::FontPitchEnum fp;
- bool tt;
-
- GR_Font::s_getGenericFontProperties((char*)szFontFamily, &ff, &fp, &tt);
 
- // TODO there is a general confusion in this program between fontname and fontfamily.
- // TODO one is "Courier New" and the other is "Modern". it seems that we interchange
- // TODO these in a few places....
-
- *p_sz_font_name = szFontFamily;
-
- if ((ff >= 0) && (ff < (int)NrElements(t_ff)))
- *p_sz_rtf_family = t_ff[ff];
- else
- *p_sz_rtf_family = t_ff[GR_Font::FF_Unknown];
-
- *p_rtf_pitch = fp;
-
- *p_rtf_bTrueType = tt;
+_rtf_font_info::_rtf_font_info(const s_RTF_AttrPropAdapter & apa)
+{
+ // Not a typo. The AbiWord "font-family" property is what RTF
+ // calls font name. It has values like "Courier New".
+ szName = apa.getProperty("font-family");
+
+ static const char * t_ff[] = { "fnil", "froman", "fswiss", "fmodern", "fscript", "fdecor", "ftech", "fbidi" };
+ GR_Font::FontFamilyEnum ff;
+ GR_Font::FontPitchEnum fp;
+ bool tt;
+ GR_Font::s_getGenericFontProperties((char*)szName, &ff, &fp, &tt);
+
+ if ((ff >= 0) && (ff < (int)NrElements(t_ff)))
+ szFamily = t_ff[ff];
+ else
+ szFamily = t_ff[GR_Font::FF_Unknown];
+ nCharset = XAP_EncodingManager::get_instance()->getWinCharsetCode();
+ nPitch = fp;
+ fTrueType = tt;
+}
+
+/*!
+ * True if the two objects represent the same RTF font.
+ */
+bool _rtf_font_info::_is_same(const _rtf_font_info & fi) const
+{
+ return UT_strcmp(szFamily, fi.szFamily) == 0
+ && nCharset == fi.nCharset
+ && nPitch == fi.nPitch
+ && UT_strcmp(szName, fi.szName) == 0
+ && fTrueType == fi.fTrueType;
 }
Index: impexp/xp/ie_exp_RTF.h
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/ie_exp_RTF.h,v
retrieving revision 1.13
diff -u -r1.13 ie_exp_RTF.h
--- impexp/xp/ie_exp_RTF.h 2001/08/09 20:57:44 1.13
+++ impexp/xp/ie_exp_RTF.h 2001/09/12 22:00:41
@@ -23,12 +23,15 @@
 
 #include "ie_exp.h"
 #include "ut_vector.h"
+#include "ut_hash.h"
 #include "ut_misc.h"
 #include "pl_Listener.h"
 class PD_Document;
+class PD_Style;
 class PP_AttrProp;
 class s_RTF_ListenerWriteDoc;
 class s_RTF_ListenerGetProps;
+class s_RTF_AttrPropAdapter;
 struct _rtf_font_info;
 
 // The exporter/writer for RTF file format (based upon spec version 1.5).
@@ -99,13 +102,21 @@
         void _rtf_nl(void);
         bool _write_rtf_header(void);
         bool _write_rtf_trailer(void);
+
+ void _clearStyles();
+ void _selectStyles();
+ UT_uint32 _getStyleNumber(const PD_Style * pStyle);
+ UT_uint32 _getStyleNumber(const XML_Char * szStyleName);
+
+ void _write_prop_ifnotdefault(const PD_Style * pStyle, const XML_Char * szPropName, const char * szRTFName);
+ void _write_prop_ifyes(const PD_Style * pStyle, const XML_Char * szPropName, const char * szRTFName);
+ void _write_tabdef(const char * szTabStops);
+ void _write_charfmt(const s_RTF_AttrPropAdapter &);
+ void _write_style_fmt(const PD_Style *);
+ void _write_stylesheets(void);
+
         UT_sint32 _findFont(const _rtf_font_info * pfi) const;
         void _addFont(const _rtf_font_info * pfi);
- void _rtf_compute_font_properties(const _rtf_font_info * pfi,
- const char ** p_sz_font_name,
- const char ** p_sz_rtf_family,
- int * p_rtf_pitch,
- bool * pbTrueType) const;
 
  private:
         s_RTF_ListenerWriteDoc * m_pListenerWriteDoc;
@@ -116,39 +127,28 @@
         UT_sint32 m_braceLevel; /* nesting depth of {} braces */
         bool m_bLastWasKeyword; /* just wrote a keyword, so need space before text data */
         bool m_atticFormat; /* whether to use unicode for all characters >0xff or convert to native windows encoding*/
+ UT_StringPtrMap m_hashStyles;
+ /* Hash containing styles to be exported. The key is the
+ AbiWord style name. The value is a NumberedStyle object
+ (see the cpp file). */
 };
 
 /*****************************************************************/
 /*****************************************************************/
 
+/* This struct contains the RTF font info as needed for the
+ font table. */
 struct _rtf_font_info
 {
- _rtf_font_info(const PP_AttrProp * pSpanAP,
- const PP_AttrProp * pBlockAP,
- const PP_AttrProp * pSectionAP)
- : m_pSpanAP(pSpanAP), m_pBlockAP(pBlockAP), m_pSectionAP(pSectionAP)
- {
- }
-
- ~_rtf_font_info(void)
- {
- }
-
- bool _is_same(const PP_AttrProp * pSpanAP,
- const PP_AttrProp * pBlockAP,
- const PP_AttrProp * pSectionAP) const
- {
- return ((pSpanAP==m_pSpanAP) && (pBlockAP==m_pBlockAP) && (pSectionAP==m_pSectionAP));
- }
-
- bool _is_same(const _rtf_font_info * pfi) const
- {
- return _is_same(pfi->m_pSpanAP,pfi->m_pBlockAP,pfi->m_pSectionAP);
- }
-
- const PP_AttrProp * m_pSpanAP;
- const PP_AttrProp * m_pBlockAP;
- const PP_AttrProp * m_pSectionAP;
+ _rtf_font_info(const s_RTF_AttrPropAdapter & apa);
+ bool _is_same(const _rtf_font_info & fi) const;
+
+ /* Neither of the char variables should be freed. */
+ const XML_Char * szFamily;
+ int nCharset;
+ int nPitch;
+ const XML_Char * szName;
+ bool fTrueType;
 };
 
 #endif /* IE_EXP_RTF_H */
Index: impexp/xp/ie_exp_RTF_listenerGetProps.cpp
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/ie_exp_RTF_listenerGetProps.cpp,v
retrieving revision 1.7
diff -u -r1.7 ie_exp_RTF_listenerGetProps.cpp
--- impexp/xp/ie_exp_RTF_listenerGetProps.cpp 2001/05/03 22:08:39 1.7
+++ impexp/xp/ie_exp_RTF_listenerGetProps.cpp 2001/09/12 22:00:41
@@ -26,6 +26,7 @@
 
 #include "ut_string.h"
 #include "ie_exp_RTF_listenerGetProps.h"
+#include "ie_exp_RTF_AttrProp.h"
 #include "pd_Document.h"
 #include "pp_AttrProp.h"
 #include "pp_Property.h"
@@ -274,7 +275,7 @@
         // write it out now. so, we build a vector of the stuff we want
         // to write (and make sure it's unique).
 
- _rtf_font_info fi(pSpanAP,pBlockAP,pSectionAP);
+ _rtf_font_info fi(s_RTF_AttrPropAdapter_AP(pSpanAP,pBlockAP,pSectionAP,m_pDocument));
         UT_sint32 ndxFont = m_pie->_findFont(&fi);
         if (ndxFont == -1)
                 m_pie->_addFont(&fi);
Index: impexp/xp/ie_exp_RTF_listenerWriteDoc.cpp
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/ie_exp_RTF_listenerWriteDoc.cpp,v
retrieving revision 1.48
diff -u -r1.48 ie_exp_RTF_listenerWriteDoc.cpp
--- impexp/xp/ie_exp_RTF_listenerWriteDoc.cpp 2001/07/19 15:56:35 1.48
+++ impexp/xp/ie_exp_RTF_listenerWriteDoc.cpp 2001/09/12 22:00:41
@@ -34,6 +34,7 @@
 #include "ut_png.h"
 #include "ut_bytebuf.h"
 #include "ie_exp_RTF_listenerWriteDoc.h"
+#include "ie_exp_RTF_AttrProp.h"
 #include "pd_Document.h"
 #include "pp_AttrProp.h"
 #include "pp_Property.h"
@@ -90,100 +91,10 @@
         m_pDocument->getAttrProp(m_apiThisBlock,&pBlockAP);
         m_pDocument->getAttrProp(apiSpan,&pSpanAP);
 
- const XML_Char * szColor = PP_evalProperty("color",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- UT_sint32 ndxColor = m_pie->_findColor((char*)szColor);
- UT_ASSERT(ndxColor != -1);
+ m_pie->_write_charfmt(s_RTF_AttrPropAdapter_AP(pSpanAP, pBlockAP, pSectionAP, m_pDocument));
 
- if (ndxColor != 0) // black text, the default
- m_pie->_rtf_keyword("cf",ndxColor);
-
- szColor = PP_evalProperty("bgcolor",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
-
- if (UT_stricmp (szColor, "transparent") != 0)
- {
- ndxColor = m_pie->_findColor((char*)szColor);
- UT_ASSERT(ndxColor != -1);
- if (ndxColor != 1) // white background, the default
- {
- m_pie->_rtf_keyword("cb",ndxColor);
- }
- }
-
- _rtf_font_info fi(pSpanAP,pBlockAP,pSectionAP);
- UT_sint32 ndxFont = m_pie->_findFont(&fi);
- UT_ASSERT(ndxFont != -1);
- m_pie->_rtf_keyword("f",ndxFont); // font index in fonttbl
-
- const XML_Char * szFontSize = PP_evalProperty("font-size",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- double dbl = UT_convertToPoints(szFontSize);
- UT_sint32 d = (UT_sint32)(dbl*2.0);
-
- // if (d != 24) - always write this out
- m_pie->_rtf_keyword("fs",d); // font size in half points
-
- const XML_Char * szFontStyle = PP_evalProperty("font-style",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- if (szFontStyle && *szFontStyle && (UT_strcmp(szFontStyle,"italic")==0))
- m_pie->_rtf_keyword("i");
-
- const XML_Char * szFontWeight = PP_evalProperty("font-weight",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- if (szFontWeight && *szFontWeight && (UT_strcmp(szFontWeight,"bold")==0))
- m_pie->_rtf_keyword("b");
-
- const XML_Char * szFontDecoration = PP_evalProperty("text-decoration",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- if (szFontDecoration && *szFontDecoration)
- {
- if (strstr(szFontDecoration,"underline") != 0)
- m_pie->_rtf_keyword("ul");
- if (strstr(szFontDecoration,"overline") != 0)
- m_pie->_rtf_keyword("ol");
- if (strstr(szFontDecoration,"line-through") != 0)
- m_pie->_rtf_keyword("strike");
- if (strstr(szFontDecoration,"topline") != 0)
- {
- m_pie->_rtf_keyword("*");
- m_pie->_rtf_keyword("topline");
- }
- if (strstr(szFontDecoration,"bottomline") != 0)
- {
- m_pie->_rtf_keyword("*");
- m_pie->_rtf_keyword("botline");
- }
- }
-
- const XML_Char * szFontPosition = PP_evalProperty("text-position",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- if (szFontPosition && *szFontPosition)
- {
- if (!UT_strcmp(szFontPosition,"superscript"))
- m_pie->_rtf_keyword("super");
- else if (!UT_strcmp(szFontPosition,"subscript"))
- m_pie->_rtf_keyword("sub");
- }
-
-#if 0
- const XML_Char * szLang = PP_evalProperty("lang",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
- // TODO: convert lang to numerical code
-#endif
-
-#ifdef BIDI_ENABLED
-
- const XML_Char * szDir = PP_evalProperty("dir",pSpanAP,pBlockAP,pSectionAP,m_pDocument,true);
-
- if (szDir)
- {
- if (!UT_strcmp (szDir, "ltr"))
- m_pie->_rtf_keyword ("ltrch");
- else
- m_pie->_rtf_keyword ("rtlch");
- }
-
-#endif
-
- // TODO do something with our font-stretch and font-variant properties
- // note: we assume that kerning has been turned off at global scope.
-
         m_bInSpan = true;
         m_apiLastSpan = apiSpan;
- return;
 }
 
 void s_RTF_ListenerWriteDoc::_outputData(const UT_UCSChar * data, UT_uint32 length)
@@ -696,34 +607,6 @@
 
 //////////////////////////////////////////////////////////////////
 
-class _t
-{
-public:
- _t(const char * szTL, const char * szTT, const char * szTK, UT_sint32 tp)
- {
- m_szTabLeaderKeyword = szTL;
- m_szTabTypeKeyword = szTT;
- m_szTabKindKeyword = szTK;
- m_iTabPosition = tp;
- }
- const char * m_szTabLeaderKeyword;
- const char * m_szTabTypeKeyword;
- const char * m_szTabKindKeyword;
- UT_sint32 m_iTabPosition;
-};
-
-static int compare_tabs(const void* p1, const void* p2)
-{
- _t ** ppTab1 = (_t **) p1;
- _t ** ppTab2 = (_t **) p2;
-
- if ((*ppTab1)->m_iTabPosition < (*ppTab2)->m_iTabPosition)
- return -1;
- if ((*ppTab1)->m_iTabPosition > (*ppTab2)->m_iTabPosition)
- return 1;
- return 0;
-}
-
 void s_RTF_ListenerWriteDoc::_rtf_open_block(PT_AttrPropIndex api)
 {
         m_apiThisBlock = api;
@@ -786,6 +669,10 @@
         
         m_pie->_rtf_keyword("pard"); // restore all defaults for this paragraph
 
+ XML_Char * szStyle;
+ if (pBlockAP->getAttribute("style", szStyle)) {
+ m_pie->_rtf_keyword("s", m_pie->_getStyleNumber(szStyle));
+ }
 
         ///
         /// OK if there is list info in this paragraph we encase it inside
@@ -1058,96 +945,8 @@
                 m_pie->_rtf_keyword("keep");
         if (UT_strcmp(szKeepWithNext,"yes")==0)
                 m_pie->_rtf_keyword("keepn");
-
- if (szTabStops && *szTabStops)
- {
- // write tabstops for this paragraph
- // TODO the following parser was copied from abi/src/text/fmt/xp/fl_BlockLayout.cpp
- // TODO we should extract both of them and share the code.
-
- UT_Vector vecTabs;
-
- const char* pStart = szTabStops;
- while (*pStart)
- {
- const char * szTT = "tx"; // TabType -- assume text tab (use "tb" for bar tab)
- const char * szTK = NULL; // TabKind -- assume left tab
- const char * szTL = NULL; // TabLeader
- const char* pEnd = pStart;
- while (*pEnd && (*pEnd != ','))
- pEnd++;
- const char* p1 = pStart;
- while ((p1 < pEnd) && (*p1 != '/'))
- p1++;
- if ( (p1 == pEnd) || ((p1+1) == pEnd) )
- ; // left-tab is default
- else
- {
- switch (p1[1])
- {
- default:
- case 'L': szTK = NULL; break;
- case 'R': szTK = "tqr"; break;
- case 'C': szTK = "tqc"; break;
- case 'D': szTK = "tqdec"; break;
- case 'B': szTT = "tb"; szTK= NULL; break; // TabKind == bar tab
- }
- switch (p1[2])
- {
- default:
- case '0': szTL = NULL; break;
- case '1': szTL = "tldot"; break;
- case '2': szTL = "tlhyph"; break;
- case '3': szTL = "tlul"; break;
- case '4': szTL = "tleq"; break;
- }
- }
-
- char pszPosition[32];
- UT_uint32 iPosLen = p1 - pStart;
- UT_ASSERT(iPosLen < 32);
- UT_uint32 k;
- for (k=0; k<iPosLen; k++)
- pszPosition[k] = pStart[k];
- pszPosition[k] = 0;
- // convert position into twips
- double dbl = UT_convertToPoints(pszPosition);
- UT_sint32 d = (UT_sint32)(dbl * 20.0);
-
- _t * p_t = new _t(szTL,szTT,szTK,d);
- vecTabs.addItem(p_t);
 
- pStart = pEnd;
- if (*pStart)
- {
- pStart++; // skip past delimiter
- while (*pStart == UCS_SPACE)
- pStart++;
- }
- }
-
- // write each tab in order:
- // <tabdef> ::= ( <tab> | <bartab> )+
- // <tab> ::= <tabkind>? <tablead>? \tx
- // <bartab> ::= <tablead>? \tb
-
- vecTabs.qsort(compare_tabs);
-
- UT_uint32 k;
- UT_uint32 kLimit = vecTabs.getItemCount();
- for (k=0; k<kLimit; k++)
- {
- _t * p_t = (_t *)vecTabs.getNthItem(k);
- // write <tabkind>
- if (p_t->m_szTabKindKeyword && *p_t->m_szTabKindKeyword)
- m_pie->_rtf_keyword(p_t->m_szTabKindKeyword);
- if (p_t->m_szTabLeaderKeyword && *p_t->m_szTabLeaderKeyword)
- m_pie->_rtf_keyword(p_t->m_szTabLeaderKeyword);
- m_pie->_rtf_keyword(p_t->m_szTabTypeKeyword,p_t->m_iTabPosition);
-
- delete p_t;
- }
- }
+ m_pie->_write_tabdef(szTabStops);
 }
 
 //////////////////////////////////////////////////////////////////





This archive was generated by hypermail 2b25 : Wed Sep 12 2001 - 17:06:53 CDT