📄 rtfwrit.cpp
字号:
if(!PutCtrlWord(CWF_VAL, i_fcharset, ptf->bCharSet))
{
goto CleanUp;
}
// We want to skip the \cpgN output if we've already output a \fcharsetN
// tag. This is to accomodate RE1.0, which can't handle some \cpgN tags
// properly. Specifically, when RE1.0 parses the \cpgN tag it does a
// table lookup to obtain a charset value corresponding to the codepage.
// Turns out the codepage/charset table for RE1.0 is incomplete and RE1.0
// maps some codepages to charset 0, trouncing the previously read \fcharsetN
// value.
goto WroteCharSet;
}
if (ptf->sCodePage && !PutCtrlWord (CWF_VAL, i_cpg, ptf->sCodePage))
{
goto CleanUp;
}
WroteCharSet:
#ifdef PWD_JUPITER
// GuyBark:
// Check if the font has a charset that means a font decoration should be
// output with the name. Word 95 uses the decoration. Word 97 will just
// ignore it.
LPSTR pszDecoration = NULL;
// No decoration needed for plain ol' Western ANSI fonts. Don't mess with
// the name if we're taking any special action with it either.
if(ptf->bCharSet && !szTaggedName && !ptf->fNameIsDBCS)
{
int i = 0;
// Word97 uses a decoration of "Turkish, rather than "Tur". So we'll
// use that too. We hit "Tur" first in the decoration array.
// Note: the Office converters check for "Turkish" so that may mean,
// but we're better off emulating Word 97.
// For all the decorations we handle...
while(fontDec[i].pszName)
{
// Is the charset of the font we're outputting the same as the decoration's?
if(ptf->bCharSet == fontDec[i].charset)
{
// Yes! So output the decoration after the name.
pszDecoration = fontDec[i].pszName;
break;
}
// Oh well, try the next decoration.
++i;
}
}
#endif // PWD_JUPITER
if (szTaggedName)
{
// Have a tagged font: write out group with real name followed by tagged name
if(!PutCtrlWord(CWF_AST, i_fname) ||
WritePcData(ptf->szName, ptf->sCodePage, ptf->fNameIsDBCS) ||
!Puts(szEndFontEntry, sizeof(szEndFontEntry) - 1) ||
WritePcData(szTaggedName, ptf->sCodePage, ptf->fNameIsDBCS) ||
!Puts(szEndFontEntry, sizeof(szEndFontEntry) - 1))
{
goto CleanUp;
}
}
else if(WritePcData(ptf->szName, ptf->sCodePage, ptf->fNameIsDBCS) ||
#ifdef PWD_JUPITER
// GuyBark: We may have a decoration to output with the font name.
(pszDecoration && !Puts(pszDecoration, strlen(pszDecoration))) ||
#endif // PWD_JUPITER
!Puts(szEndFontEntry, sizeof(szEndFontEntry) - 1))
// If non-tagged font just write name out
{
goto CleanUp;
}
}
Puts(szEndGroupCRLF, sizeof(szEndGroupCRLF) - 1); // End font table group
CleanUp:
return _ecParseError;
}
/*
* CRTFWrite::WriteColorTable()
*
* @mfunc
* Write out color table
*
* @rdesc
* EC The error code
*/
EC CRTFWrite::WriteColorTable()
{
TRACEBEGIN(TRCSUBSYSRTFW, TRCSCOPEINTERN, "CRTFWrite::WriteColorTable");
LONG Count = _colors.Count();
COLORREF clrf;
LONG iclrf;
// GuyBark Jupiter 35396: Now that we allow autocolor, we must ALWAYS
// output a color table, even if it only has the one ';' entry.
#ifdef PWD_JUPITER
if (!PutCtrlWord(CWF_GRP, i_colortbl) // Start color table group
#else
if (!Count || !PutCtrlWord(CWF_GRP, i_colortbl) // Start color table group
#endif // PWD_JUPITER
|| !PutChar(';')) // with null first entry
{
goto CleanUp;
}
for(iclrf = 0; iclrf < Count; iclrf++)
{
clrf = _colors.GetAt(iclrf);
if (!printF(szColorEntryFmt,
GetRValue(clrf), GetGValue(clrf), GetBValue(clrf)))
goto CleanUp;
}
Puts(szEndGroupCRLF,sizeof(szEndGroupCRLF) -1); // End color table group
CleanUp:
return _ecParseError;
}
/*
* CRTFWrite::WriteCharFormat(pCF)
*
* @mfunc
* Write deltas between CCharFormat <p pCF> and the previous CCharFormat
* given by _CF, and then set _CF = *<p pCF>.
*
* @rdesc
* EC The error code
*
* @devnote
* For optimal output, could write \\plain and use deltas relative to
* \\plain if this results in less output (typically only one change
* is made when CF changes, so less output results when compared to
* previous CF than when compared to \\plain).
*/
EC CRTFWrite::WriteCharFormat(
const CCharFormat * pCF) // @parm Ptr to CCharFormat
{
TRACEBEGIN(TRCSUBSYSRTFW, TRCSCOPEINTERN, "CRTFWrite::WriteCharFormat");
DWORD dwEffects = pCF->dwEffects;
DWORD dwChanges = dwEffects ^ _CF.dwEffects;
LONG i; // Counter
LONG iFormat;
LONG iValue; // Control-word value
LONG i_sz; // Temp ctrl string index
DWORD UType; // Underline type
LONG yOffset = pCF->yOffset;
// GuyBark Jupiter J
// For JupiterJ I've added two new numbered list types. This mean
// I had to change all the i_xx array to Word arrays not bytes.
// AssertSz(cKeywords < 256,
// "CRTFWrite::WriteCharFormat: change BYTE i_xx to WORD");
if (dwChanges & CFE_AUTOCOLOR || // Change in autocolor
pCF->crTextColor != _CF.crTextColor) // or text color
{
iValue = 0; // Default autocolor
if(!(dwEffects & CFE_AUTOCOLOR)) // Make that text color
iValue = LookupColor(pCF->crTextColor) + 1;
if(!PutCtrlWord(CWF_VAL, i_cf, iValue))
goto CleanUp;
}
if (dwChanges & CFE_AUTOBACKCOLOR || // Change in autobackcolor
pCF->crBackColor != _CF.crBackColor) // or backcolor
{
iValue = 0; // Default autobackcolor
if(!(dwEffects & CFE_AUTOBACKCOLOR)) // Make that back color
iValue = LookupColor(pCF->crBackColor) + 1;
if(!PutCtrlWord(CWF_VAL, i_highlight, iValue))
goto CleanUp;
}
if (pCF->lcid != _CF.lcid &&
!PutCtrlWord(CWF_VAL, i_lang, LANGIDFROMLCID((WORD)pCF->lcid)) ||
pCF->sSpacing != _CF.sSpacing &&
!PutCtrlWord(CWF_VAL, i_expndtw, pCF->sSpacing) ||
/* FUTURE (alexgo): This code is incorrect and we don't
yet handle the Style table. We may want to support this
better in a future version.
pCF->sStyle != _CF.sStyle && pCF->sStyle > 0 &&
!PutCtrlWord(CWF_VAL, i_cs, pCF->sStyle) || */
pCF->bAnimation != _CF.bAnimation &&
!PutCtrlWord(CWF_VAL, i_animtext, pCF->bAnimation) ||
/* FUTURE (alexgo): this code doesn't work yet, as we don't
output the revision table. We may want to support this
better in a future version
pCF->bRevAuthor != _CF.bRevAuthor &&
!PutCtrlWord(CWF_VAL, i_revauth, pCF->bRevAuthor) || */
pCF->wKerning != _CF.wKerning &&
!PutCtrlWord(CWF_VAL, i_kerning, pCF->wKerning/10) )
{
goto CleanUp;
}
UType = _CF.bUnderlineType; // Handle all underline
if (UType <= CUNDERLINES && // known and
dwEffects & CFM_UNDERLINE && // active changes
(UType != pCF->bUnderlineType || // Type change while on
dwChanges & CFM_UNDERLINE)) // Turn on
{
dwChanges &= ~CFE_UNDERLINE; // Suppress underline
i = pCF->bUnderlineType;
if(i)
i--;
if(!PutCtrlWord(CWF_STR,
rgiszUnderlines[i])) // action in next for()
goto CleanUp; // Note: \ul0 turns off
} // all underlining
// This must be before next stuff
if(dwChanges & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT))// change in sub/sup
{ // status
i_sz = dwEffects & CFE_SUPERSCRIPT ? i_super
: dwEffects & CFE_SUBSCRIPT ? i_sub
: i_nosupersub;
if(!PutCtrlWord(CWF_STR, i_sz))
goto CleanUp;
}
dwChanges &= ((1 << CEFFECTS) - 1) & ~CFE_LINK; // Output keywords for
for(i = CEFFECTS; // effects that changed
dwChanges && i--; // rgszEffects[] contains
dwChanges >>= 1, dwEffects >>= 1) // effect keywords in
{ // order max CFE_xx to
if(dwChanges & 1) // min CFE-xx
{ // Change from last call
iValue = dwEffects & 1; // If effect is off, write
iFormat = iValue ? CWF_STR : CWF_VAL; // a 0; else no value
if(!PutCtrlWord(iFormat,
rgiszEffects[i], iValue))
goto CleanUp;
}
}
if(yOffset != _CF.yOffset) // Change in base line
{ // position
yOffset /= 10; // Default going to up
i_sz = i_up;
iFormat = CWF_VAL;
if(yOffset < 0) // Make that down
{
i_sz = i_dn;
yOffset = -yOffset;
}
if(!PutCtrlWord(iFormat, i_sz, yOffset))
goto CleanUp;
}
if (pCF->bPitchAndFamily != _CF.bPitchAndFamily || // Change in font
pCF->bCharSet != _CF.bCharSet ||
lstrcmp(pCF->szFaceName, _CF.szFaceName))
{
iValue = LookupFont(pCF);
if(iValue < 0 || !PutCtrlWord(CWF_VAL, i_f, iValue))
goto CleanUp;
#ifdef PWD_JUPITER
// GuyBark: Keep a track of the current font selected.
_pwdCurrentFont = iValue;
#endif // PWD_JUPITER
}
if (pCF->yHeight != _CF.yHeight) // Change in font size
{
iValue = (pCF->yHeight + (pCF->yHeight > 0 ? 5 : -5))/10;
if(!PutCtrlWord(CWF_VAL, i_fs, iValue))
goto CleanUp;
}
_CF = *pCF; // Update previous CCharFormat
CleanUp:
return _ecParseError;
}
/*
* CRTFWrite::WriteParaFormat(prtp)
*
* @mfunc
* Write out attributes specified by the CParaFormat <p pPF> relative
* to para defaults (probably produces smaller output than relative to
* previous para format and let's you redefine tabs -- no RTF kill
* tab command except \\pard)
*
* @rdesc
* EC The error code
*/
EC CRTFWrite::WriteParaFormat(
const CRchTxtPtr * prtp) // @parm Ptr to rich-text ptr at current cp
{
TRACEBEGIN(TRCSUBSYSRTFW, TRCSCOPEINTERN, "CRTFWrite::WriteParaFormat");
Assert(_ped);
//if(!_fRangeHasEOP) // Don't write para info if
// return _ecParseError; // range has no EOPs
const CParaFormat * pPFPrev = _pPF;
const CParaFormat * pPF = _pPF = prtp->GetPF();
if (NULL == pPF)
return _ecParseError;
BOOL fInTable = pPF->InTable();
LONG c; // Temporary count
LONG cTab = pPF->cTabCount;
DWORD dwEffects;
DWORD dwRule = pPF->bLineSpacingRule;
LONG dy = pPF->dyLineSpacing;
LONG i_t, i, j, k;
LONG tabAlign, tabLead, tabPos;
LONG lDocDefaultTab = _ped->GetDefaultTab();
if(!lDocDefaultTab)
lDocDefaultTab = lDefaultTab;
if (cTab == 1 && pPF->rgxTabs[0] == lDocDefaultTab + (LONG)PFT_DEFAULT ||
CheckInTable(FALSE))
{
cTab = 0; // Suppress \tab output
}
AssertSz(cTab >= 0 && cTab <= MAX_TAB_STOPS,
"CRTFW::WriteParaFormat: illegal cTabCount");
// Exchange's IMC keys on the \protect tag when it does
// its reply-ticking for mail being sent to Internet recipients.
// Paragraphs following a \pard and containing a \protect tag are
// reply-ticked, so we must ensure that each \pard in a protected range
// is followed by a \protect tag.
if (_CF.dwEffects & CFE_PROTECTED && !PutCtrlWord(CWF_VAL, i_protect, 0) ||
!PutCtrlWord(CWF_STR, i_pard) || // Reset para attributes
_CF.dwEffects & CFE_PROTECTED && !PutCtrlWord(CWF_STR, i_protect))
{
goto CleanUp;
}
if(fInTable)
{
if(_fRangeHasEOP && !PutCtrlWord(CWF_STR, i_intbl))
goto CleanUp;
}
else if(PutBorders(FALSE))
goto CleanUp;
if(pPF->wShadingStyle)
{
i = pPF->wShadingStyle & 15; // Shading patterns
j = (pPF->wShadingStyle >> 6) & 31; // Shading forecolor
k = pPF->wShadingStyle >> 11; // Shading backcolor
if (i && i <= CSHADINGSTYLES &&
!PutCtrlWord(CWF_STR, rgiszShadingStyles[i - 1]) ||
j && !PutCtrlWord(CWF_VAL, i_cfpat, LookupColor(g_Colors[j-1]) + 1) ||
k && !PutCtrlWord(CWF_VAL, i_cbpat, LookupColor(g_Colors[k-1]) + 1))
{
goto CleanUp;
}
}
if(pPF->wShadingWeight && !PutCtrlWord(CWF_VAL, i_shading, pPF->wShadingWeight))
goto CleanUp;
// Paragraph numbering
_fBullet = _fBulletPending = FALSE;
_nNumber = pPF->UpdateNumber(_nNumber, pPFPrev);
if(pPF->wNumbering) // Write numbering info
{
LONG iFont = _symbolFont;
if(pPF->IsListNumbered())
{
const CCharFormat *pCF;
WCHAR szNumber[CCHMAXNUMTOSTR];
CTxtPtr rpTX(prtp->_rpTX);
CFormatRunPtr rpCF(prtp->_rpCF);
rpCF.AdvanceCp(rpTX.FindEOP(tomForward));
rpCF.AdjustBackward();
pCF = _ped->GetCharFormat(rpCF.GetFormat());
iFont = LookupFont(pCF);
if(iFont < 0)
{
iFont = 0;
TRACEERRORSZ("CWRTFW::WriteParaFormat: illegal bullet font");
}
_nFont = iFont;
// TODO: make the following smarter, i.e., may need to increment
// _nNumber instead of resetting it to 1.
_cpg = GetCodePage(pCF->bCharSet);
i = 0;
// GuyBark JupiterJ: Assume we want everything before sequence value
// if(pPF->wNumbering <= tomListNumberAsUCRoman)
if(pPF->wNumbering < tomListNumberAsSequence)
i = pPF->wNumbering - tomListNumberAsArabic;
WORD wStyle = pPF->wNumberingStyle & 0xF00;
WCHAR ch = (wStyle == PFNS_PARENS || wStyle == PFNS_PAREN) ? ')'
: (wStyle == PFNS_PERIOD) ? '.' : 0;
if(wStyle != PFNS_NONUMBER) // Unless number suppressed
{ // write \pntext group
pPF->NumToStr(szNumber, _nNumber);
if (!printF(szBeginNumberGroup, iFont) ||
WritePcData(szNumber, _cpg, FALSE) ||
!printF(szEndNumberGroup))
{
goto CleanUp;
}
}
if (!printF(szBeginNumberFmt,
wStyle == PFNS_NONUMBER ? "cont" : "body",
iFont, pPF->wNumberingTab,
pPF->wNumberingStart) ||
!PutCtrlWord(CWF_STR, rgiszNumberStyle[i]) ||
wStyle == PFNS_PARENS && !printF(szpntxtb) ||
ch && !printF(szpntxta, ch) ||
!printF(szEndGroupCRLF))
{
goto CleanUp;
}
}
else
{
if (!printF(szBulletGroup, iFont) ||
!printF(szBulletFmt, iFont, pPF->wNumberingTab))
{
goto CleanUp;
}
}
_fBullet = TRUE;
}
// Put out para indents. RTF first indent = -PF.dxOffset
// RTF left indent = PF.dxStartIndent + PF.dxOffset
if(IsHeadingStyle(pPF->sStyle) && !PutCtrlWord(CWF_VAL, i_s, -pPF->sStyle-1))
goto CleanUp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -