|
|
/*
* @doc INTERNAL * * @module CFPF.C -- -- RichEdit CCharFormat and CParaFormat Classes | * * Created: <nl> * 9/1995 -- Murray Sargent <nl> * * @devnote * The this ptr for all methods points to an internal format class, i.e., * either a CCharFormat or a CParaFormat, which uses the cbSize field as * a reference count. The pCF or pPF argument points at an external * CCharFormat or CParaFormat class, that is, pCF->cbSize and pPF->cbSize * give the size of their structure. The code still assumes that both * internal and external forms are derived from the CHARFORMAT(2) and * PARAFORMAT(2) API structures, so some redesign would be necessary to * obtain a more space-efficient internal form. * * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved. */
#include "_common.h"
#include "_array.h" // for fumemmov()
#include "_rtfconv.h" // for IsCharSetValid()
#include "_font.h" // for GetFontNameIndex(), GetFontName()
ASSERTDATA
// Table of formatting info for Normal and Heading styles
const STYLEFORMAT g_Style[] = // {dwEffects; yHeight}
{ // Measurements in points
{CFE_BOLD, 14}, // Heading 1
{CFE_BOLD + CFE_ITALIC, 12}, // Heading 2
{0, 12}, // Heading 3
{CFE_BOLD, 12}, // Heading 4
{0, 11}, // Heading 5
{CFE_ITALIC, 11}, // Heading 6
{0, 0}, // Heading 7
{CFE_ITALIC, 0}, // Heading 8
{CFE_BOLD + CFE_ITALIC, 9} // Heading 9
};
BOOL IsValidTwip(LONG dl) { static const LONG dlMax = 0x00FFFFFF; static const LONG dlMin = -0x00FFFFFF; if (dl > dlMax || dl < dlMin) return FALSE; return TRUE; }
//------------------------- CCharFormat Class -----------------------------------
/*
* CCharFormat::Apply(pCF, dwMask, dwMask2) * * @mfunc * Apply *<p pCF> to this CCharFormat as specified by nonzero bits in * dwMask and dwMask2 * * @rdesc * HRESULT = NOERROR * * @devnote * Autocolor is dealt with through a neat little hack made possible * by the choice CFE_AUTOCOLOR = CFM_COLOR (see richedit.h). Hence * if <p pCF>->dwMask specifies color, it automatically resets autocolor * provided (<p pCF>->dwEffects & CFE_AUTOCOLOR) is zero. * * *<p pCF> is an external CCharFormat, i.e., it's either a CHARFORMAT * or a CHARFORMAT2 with the appropriate size given by cbSize. But * this CCharFormat is internal and cbSize is used as a reference count. */ HRESULT CCharFormat::Apply ( const CCharFormat *pCF, //@parm CCharFormat to apply to this CF
DWORD dwMask, //@parm Mask corresponding to CHARFORMAT2
DWORD dwMask2) //@parm Mask for additional internal parms
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Apply");
DWORD dwEffectMask = dwMask & CFM_EFFECTS2; bool fNewCharset = false;
// Reset effect bits to be modified and OR in supplied values
_dwEffects &= ~dwEffectMask; _dwEffects |= pCF->_dwEffects & dwEffectMask;
// Ditto for additional effects given by dwMask2
dwEffectMask = dwMask2 & 0xBBFC0000; // Don't allow autocolors, sub/sups
_dwEffects &= ~dwEffectMask; _dwEffects |= pCF->_dwEffects & dwEffectMask;
// Setup Temp. display attributes idx
if (dwMask2 & CFM2_USETMPDISPATTR) _sTmpDisplayAttrIdx = pCF->_sTmpDisplayAttrIdx;
// If CFM_BOLD is specified, it overrides the font weight
if(dwMask & CFM_BOLD) _wWeight = (pCF->_dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
// Handle CFM_COLOR since it's overloaded with CFE_AUTOCOLOR
if(dwMask & CFM_COLOR) _crTextColor = pCF->_crTextColor;
if(dwMask & ~CFM_EFFECTS) // Early out if only dwEffects
{ // is modified. Note that
if(dwMask & CFM_SIZE) // CFM_EFFECTS includes CFM_COLOR
{ // If dwMask2 CFM2_USABLEFONT bit is set, pCF->_yHeight (from
// EM_SETFONTSIZE wparam) is signed increment in points.
_yHeight = dwMask2 & CFM2_USABLEFONT ? GetUsableFontHeight(_yHeight, pCF->_yHeight) : pCF->_yHeight; }
if(dwMask & CFM_OFFSET) _yOffset = pCF->_yOffset;
if((dwMask & CFM_CHARSET) &&
// Caller guarantees no check needed
(dwMask2 & (CFM2_NOCHARSETCHECK | CFM2_MATCHFONT) ||
// Caller is itemizer. Change to ANSI_CHARSET only if current is BiDi,
// dont change if current is DBCS/FE charset or symbol.
(dwMask2 & CFM2_SCRIPT && (!pCF->_iCharRep && IsBiDiCharRep(_iCharRep) || pCF->_iCharRep && _iCharRep < NCHARSETS && !IsFECharRep(_iCharRep) && !IsSymbolOrOEMCharRep(_iCharRep) && !(_dwEffects & CFE_RUNISDBCS))) ||
// Caller is not itemizer. Allow consistent direction
(!(dwMask2 & CFM2_SCRIPT) && (!(IsRTLCharRep(_iCharRep) ^ IsRTLCharRep(pCF->_iCharRep)) || IsSymbolOrOEMCharRep(pCF->_iCharRep))))) { fNewCharset = TRUE; _iCharRep = pCF->_iCharRep; } if ((dwMask2 & (CFM2_MATCHFONT | CFM2_ADJUSTFONTSIZE)) == (CFM2_MATCHFONT | CFM2_ADJUSTFONTSIZE) && _iCharRep != pCF->_iCharRep && (dwMask & CFM_SIZE)) { // Check if we need to adjust the font size
_yHeight = W32->GetPreferredFontHeight( (dwMask2 & CFM2_UIFONT) != 0, pCF->_iCharRep, _iCharRep, _yHeight); }
if(dwMask & CFM_FACE) { _bPitchAndFamily = pCF->_bPitchAndFamily; _iFont = pCF->_iFont; const WCHAR *pch = GetFontName((LONG)_iFont); WCHAR ch = pch[0]; if (!fNewCharset && ch == L'\0') { // API to choose default font
BYTE bDefPitchAndFamily; SHORT iDefFont; int iCharRep = GetLocaleCharRep(); BYTE yDefHeight;
// Get default font name and charset
bool fr = W32->GetPreferredFontInfo( iCharRep, FALSE, iDefFont, (BYTE&)yDefHeight, bDefPitchAndFamily ); if (fr) { _iCharRep = iCharRep; _iFont = iDefFont; if(!(dwMask & CFM_SIZE) || _yHeight < yDefHeight * 20) // Setup default height if needed.
_yHeight = yDefHeight * 20;
_bPitchAndFamily = bDefPitchAndFamily; } } else if(GetCharFlags(pch, 2) & FFE && !IsFECharRep(_iCharRep)) { // make sure that we dont end up having DBCS facename with Non-FE charset
QWORD qwFontSig; if (GetFontSignatureFromFace(_iFont, &qwFontSig)) { qwFontSig &= FFE ; // Only interest in FE charset
if (qwFontSig) _iCharRep = GetFirstAvailCharRep(qwFontSig); } } #ifdef DEBUG
_pchFaceName = GetFontName((LONG)_iFont); #endif
}
if(!(dwMask2 & CFM2_CHARFORMAT) && (dwMask & ~CFM_ALL)) // CHARFORMAT2 extensions
{ if((dwMask & (CFM_WEIGHT | CFM_BOLD)) == CFM_WEIGHT) { _wWeight = pCF->_wWeight; _dwEffects |= CFE_BOLD; // Set above-average
if(_wWeight < 551) // weights to bold
_dwEffects &= ~CFE_BOLD; }
if(dwMask & CFM_BACKCOLOR) _crBackColor = pCF->_crBackColor;
if(dwMask & CFM_LCID) { _lcid = pCF->_lcid; if(!(dwMask & CFM_CHARSET) && !IsFECharRep(_iCharRep) && PRIMARYLANGID(_lcid)) _iCharRep = CharRepFromLID(_lcid); }
if(dwMask & CFM_SPACING) _sSpacing = pCF->_sSpacing;
if(dwMask & CFM_KERNING) _wKerning = pCF->_wKerning;
if(dwMask & CFM_STYLE) _sStyle = pCF->_sStyle;
if(dwMask & CFM_UNDERLINETYPE) { _bUnderlineType = pCF->_bUnderlineType; if(!(dwMask & CFM_UNDERLINE)) // If CFE_UNDERLINE
{ // isn't defined,
_dwEffects &= ~CFE_UNDERLINE; // set it according to
if(_bUnderlineType) // bUnderlineType
_dwEffects |= CFE_UNDERLINE; } else _bUnderlineColor = pCF->_bUnderlineColor; }
if((dwMask & CFM_ANIMATION) && pCF->_bAnimation <= 18) _bAnimation = pCF->_bAnimation;
if(dwMask & CFM_REVAUTHOR) _bRevAuthor = pCF->_bRevAuthor; } }
// RichEdit currently doesn't do a good job of assigning LangIDs to text,
// primarily assigning them only on initialization, when the keyboard
// changes, and when LangIDs are read in from RTF. The following weak
// LangID recognizer uses the facts that most languages are associated
// with a single CharRep and that the keyboard provides a good hint as
// to which language. The else if could be expanded to include more
// CharReps than Arabic, Hebrew, and Ansi, e.g., CJK. More generally,
// LangID recognition requires natural language processing beyond the
// choice of the writing system, which is given in RichEdit by _iCharRep.
if(CharRepFromLID(_lcid) != _iCharRep) { LONG lcid = (WORD)W32->GetPreferredKbd(_iCharRep); if(lcid) _lcid = lcid; // Use keyboard lang for _iCharRep
else if(_iCharRep == ANSI_INDEX) // No ANSI_CHARSET keyboard
_lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
else if(IsBiDiCharRep(_iCharRep)) // Use default langs for BiDi
_lcid = MAKELANGID(_iCharRep == HEBREW_INDEX ? LANG_HEBREW : LANG_ARABIC, SUBLANG_DEFAULT); }
if(dwMask2 & CFM2_SCRIPT) _wScript = pCF->_wScript;
return NOERROR; }
/*
* CCharFormat::ApplyDefaultStyle(Style) * * @mfunc * Set default style properties in this CCharFormat */ void CCharFormat::ApplyDefaultStyle ( LONG Style) //@parm Style to use
{ Assert(IsKnownStyle(Style));
if(IsHeadingStyle(Style)) { LONG i = -Style + STYLE_HEADING_1; _dwEffects = (_dwEffects & 0xFFFFFF00) | g_Style[i].bEffects; _wWeight = (_dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
if(g_Style[i].bHeight) _yHeight = g_Style[i].bHeight * 20;
QWORD qwFontSig; LONG iFont = _iFont; // Save _iFont in case Arial doesn't
_iFont = IFONT_ARIAL; // support _bCharSet
GetFontSignatureFromFace(_iFont, &qwFontSig); if(FontSigFromCharRep(_iCharRep) & qwFontSig) _bPitchAndFamily = FF_SWISS;// Arial supports _iCharRep
else _iFont = iFont; // Restore iFont
#ifdef DEBUG
_pchFaceName = GetFontName((LONG)_iFont); #endif
} }
BOOL CCharFormat::CanKernWith(const CCharFormat *pCF) const { const DWORD dwMask = CFE_ITALIC;
return this == pCF || (!((_dwEffects ^ pCF->_dwEffects) & dwMask) && _iFont == pCF->_iFont && _yHeight == pCF->_yHeight && _wWeight == pCF->_wWeight); }
/*
* CCharFormat::Compare(pCF) * * @mfunc * Compare this CCharFormat to *<p pCF> * * @rdesc * TRUE if they are the same not including _cRefs */ BOOL CCharFormat::Compare ( const CCharFormat *pCF) const //@parm CCharFormat to compare this
{ // CCharFormat to
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Compare");
return !CompareMemory(this, pCF, sizeof(CCharFormat)); }
/*
* CCharFormat::Delta(pCF, fCHARFORMAT) * * @mfunc * Calculate dwMask for differences between this CCharformat and * *<p pCF> * * @rdesc * return dwMask of differences (1 bit means a difference) */ DWORD CCharFormat::Delta ( CCharFormat *pCF, //@parm CCharFormat to compare this one to
BOOL fCHARFORMAT) const //@parm Only compare CHARFORMAT members
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Delta"); // Collect bits for properties
LONG dw = _dwEffects ^ pCF->_dwEffects; // that change. Note: auto
// color is handled since
if(_yHeight != pCF->_yHeight) // CFM_COLOR = CFE_AUTOCOLOR
dw |= CFM_SIZE;
if(_yOffset != pCF->_yOffset) dw |= CFM_OFFSET;
if(_crTextColor != pCF->_crTextColor) dw |= CFM_COLOR;
if(_iCharRep != pCF->_iCharRep) dw |= CFM_CHARSET;
if(_iFont != pCF->_iFont) dw |= CFM_FACE;
if(fCHARFORMAT) return dw; // Done with CHARFORMAT stuff
if(_crBackColor != pCF->_crBackColor) // CHARFORMAT2 stuff
dw |= CFM_BACKCOLOR;
if(_wKerning != pCF->_wKerning) dw |= CFM_KERNING;
if(_lcid != pCF->_lcid) dw |= CFM_LCID;
if(_wWeight != pCF->_wWeight) dw |= CFM_WEIGHT;
if(_sSpacing != pCF->_sSpacing) dw |= CFM_SPACING;
if(_sStyle != pCF->_sStyle) dw |= CFM_STYLE;
if(_bUnderlineType != pCF->_bUnderlineType) dw |= CFM_UNDERLINETYPE;
if(_bAnimation != pCF->_bAnimation) dw |= CFM_ANIMATION;
if(_bRevAuthor != pCF->_bRevAuthor) dw |= CFM_REVAUTHOR;
return dw; }
/*
* CCharFormat::fSetStyle(dwMask) * * @mfunc * return TRUE iff pCF specifies that the style should be set. See * code for list of conditions for this to be true * * @rdesc * TRUE iff pCF specifies that the style _sStyle should be set */ BOOL CCharFormat::fSetStyle(DWORD dwMask, DWORD dwMask2) const { return dwMask != CFM_ALL2 && dwMask & CFM_STYLE && !(dwMask2 & CFM2_CHARFORMAT) && IsKnownStyle(_sStyle); }
/*
* CCharFormat::Get(pCF, CodePage) * * @mfunc * Copy this CCharFormat to the CHARFORMAT or CHARFORMAT2 *<p pCF> */ void CCharFormat::Get ( CHARFORMAT2 *pCF2, //@parm CHARFORMAT to copy this CCharFormat to
UINT CodePage) const { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Get");
pCF2->dwMask = CFM_ALL; // Use CHARFORMAT
pCF2->dwEffects = _dwEffects; pCF2->yHeight = _yHeight; pCF2->yOffset = _yOffset; pCF2->crTextColor = _crTextColor; pCF2->bCharSet = CharSetFromCharRep(_iCharRep); pCF2->bPitchAndFamily = _bPitchAndFamily;
UINT cb = pCF2->cbSize; const WCHAR *pch = GetFontName((LONG)_iFont);
AssertSz((CodePage != 1200) ^ IsValidCharFormatW(pCF2), "CCharFormat::Get: wrong codepage for CHARFORMAT"); if(CodePage != 1200) { if(_dwEffects & CFE_FACENAMEISDBCS) { // The face name is actually DBCS stuffed into the unicode
// buffer, so simply un-stuff this DBCS into the ANSI string
char *pachDst = (char *)pCF2->szFaceName;
while(*pch) *pachDst++ = *pch++;
*pachDst = 0; } else { MbcsFromUnicode((char *)pCF2->szFaceName, LF_FACESIZE, pch, -1, CodePage, UN_NOOBJECTS); } } else wcscpy(pCF2->szFaceName, pch); if (cb == sizeof(CHARFORMATW) || cb == sizeof(CHARFORMATA)) // We're done
return;
char *pvoid = (char *)&pCF2->wWeight; if(pCF2->cbSize == sizeof(CHARFORMAT2A)) pvoid -= sizeof(CHARFORMAT2W) - sizeof(CHARFORMAT2A); else Assert(pCF2->cbSize == sizeof(CHARFORMAT2));// Better be a CHARFORMAT2
pCF2->dwMask = CFM_ALL2; CopyMemory(pvoid, &_wWeight, 3*sizeof(DWORD)); CopyMemory(pvoid + 4*sizeof(DWORD), &_sStyle, 2*sizeof(DWORD)); *(DWORD *)(pvoid + 3*sizeof(DWORD)) = 0; }
/*
* CCharFormat::InitDefault(hfont) * * @mfunc * Initialize this CCharFormat with information coming from the font * <p hfont> * * @rdesc * HRESULT = (if success) ? NOERROR : E_FAIL */ HRESULT CCharFormat::InitDefault ( HFONT hfont) //@parm Handle to font info to use
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::InitDefault");
LOGFONT lf; BOOL fUseStockFont = hfont == NULL;
ZeroMemory(this, sizeof(CCharFormat));
// If hfont isn't defined, get LOGFONT for default font
if(!hfont) hfont = W32->GetSystemFont();
// Get LOGFONT for passed hfont
if(!W32->GetObject(hfont, sizeof(LOGFONT), &lf)) return E_FAIL;
_yHeight = (lf.lfHeight * LY_PER_INCH) / W32->GetYPerInchScreenDC(); if(_yHeight <= 0) _yHeight = -_yHeight; else if (fUseStockFont) // This is Cell Height for System Font case
_yHeight -= (W32->GetSysFontLeading() * LY_PER_INCH) / W32->GetYPerInchScreenDC(); else { // This is Cell Height, need to get the character height by subtracting
// the tm.tmInternalLeading.
CLock lock; HDC hdc = W32->GetScreenDC(); HFONT hOldFont = SelectFont(hdc, hfont); TEXTMETRIC tm;
if(hOldFont) { if(GetTextMetrics(hdc, &tm)) _yHeight -= (tm.tmInternalLeading * LY_PER_INCH) / W32->GetYPerInchScreenDC();
SelectFont(hdc, hOldFont); } }
_dwEffects = (CFM_EFFECTS | CFE_AUTOBACKCOLOR) & ~(CFE_PROTECTED | CFE_LINK);
if(lf.lfWeight < FW_BOLD) _dwEffects &= ~CFE_BOLD;
if(!lf.lfItalic) _dwEffects &= ~CFE_ITALIC;
if(!lf.lfUnderline) _dwEffects &= ~CFE_UNDERLINE;
if(!lf.lfStrikeOut) _dwEffects &= ~CFE_STRIKEOUT;
_wWeight = (WORD)lf.lfWeight; _lcid = GetSystemDefaultLCID(); _iCharRep = CharRepFromCharSet(lf.lfCharSet); _bPitchAndFamily= lf.lfPitchAndFamily; _iFont = GetFontNameIndex(lf.lfFaceName); _bUnderlineType = CFU_UNDERLINE; // Default solid underlines
// Are gated by CFE_UNDERLINE
// Qualify the charformat produced by incoming hfont before exit.
// We did this to make sure that the charformat we derived from hfont is usable
// since caller can send us bad font like given facename can't handle given charset.
if (!fUseStockFont) { QWORD qwFontSig; if (GetFontSignatureFromFace(_iFont, &qwFontSig) && !(FontSigFromCharRep(_iCharRep) & qwFontSig)) _iCharRep = GetFirstAvailCharRep(qwFontSig); _bQuality = lf.lfQuality; }
// Initialize to no temp. display attr.
_sTmpDisplayAttrIdx = -1;
#ifdef DEBUG
_pchFaceName = GetFontName((LONG)_iFont); #endif
return NOERROR; }
/*
* CCharFormat::Set(pCF, CodePage) * * @mfunc * Copy the CHARFORMAT or CHARFORMAT2 *<p pCF> to this CCharFormat */ void CCharFormat::Set ( const CHARFORMAT2 *pCF2, //@parm CHARFORMAT to copy to this CCharFormat
UINT CodePage) { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Set"); _dwEffects = pCF2->dwEffects; _iCharRep = CharRepFromCharSet(pCF2->bCharSet); _bPitchAndFamily = pCF2->bPitchAndFamily; if(pCF2->dwMask & CFM_FACE) { AssertSz((CodePage != 1200) ^ IsValidCharFormatW(pCF2), "CCharFormat::Set: wrong codepage for CHARFORMAT");
if(CodePage != 1200) { WCHAR sz[LF_FACESIZE + 1]; UnicodeFromMbcs(sz, LF_FACESIZE, (char *)pCF2->szFaceName, LF_FACESIZE, CodePage); _iFont = GetFontNameIndex(sz); } else _iFont = GetFontNameIndex(pCF2->szFaceName); } _yHeight = Get16BitTwips(pCF2->yHeight); _yOffset = Get16BitTwips(pCF2->yOffset); _crTextColor = pCF2->crTextColor;
UINT cb = pCF2->cbSize; if(cb == sizeof(CHARFORMATW) || cb == sizeof(CHARFORMATA)) { _dwEffects |= CFE_AUTOBACKCOLOR; _bUnderlineType = CFU_UNDERLINE; ZeroMemory((LPBYTE)&_wWeight, sizeof(CCharFormat) - offsetof(CCharFormat, _wWeight)); #ifdef DEBUG
_pchFaceName = GetFontName((LONG)_iFont); #endif
return; }
char *pvoid = (char *)&pCF2->wWeight; if(pCF2->cbSize == sizeof(CHARFORMAT2A)) pvoid -= sizeof(CHARFORMAT2W) - sizeof(CHARFORMAT2A); else Assert(pCF2->cbSize == sizeof(CHARFORMAT2));// Better be a CHARFORMAT2
CopyMemory(&_wWeight, pvoid, 3*sizeof(DWORD)); CopyMemory(&_sStyle, pvoid + 4*sizeof(DWORD), 2*sizeof(DWORD));
#ifdef DEBUG
_pchFaceName = GetFontName((LONG)_iFont); #endif
}
//------------------------- CParaFormat Class -----------------------------------
/*
* CParaFormat::AddTab(tbPos, tbAln, tbLdr, prgxTabs) * * @mfunc * Add tabstop at position <p tbPos>, alignment type <p tbAln>, and * leader style <p tbLdr> * * @rdesc * (success) ? NOERROR : S_FALSE * * @devnote * Tab struct that overlays LONG in internal _rgxTabs is * * DWORD tabPos : 24; * DWORD tabType : 4; * DWORD tabLeader : 4; */ HRESULT CParaFormat::AddTab ( LONG tbPos, //@parm New tab position
LONG tbAln, //@parm New tab alignment type
LONG tbLdr, //@parm New tab leader style
LONG * prgxTabs) //@parm Where the tabs are
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::AddTab");
if (IsTableRowDelimiter() || (DWORD)tbAln > tomAlignBar || // Validate arguments
(DWORD)tbLdr > tomEquals || // Comparing DWORDs causes
(DWORD)tbPos > 0xffffff || !tbPos) // negative values to be
{ // treated as invalid
return E_INVALIDARG; }
LONG iTab; LONG tbValue = tbPos + (tbAln << 24) + (tbLdr << 28);
for(iTab = 0; iTab < _bTabCount && // Determine where to
tbPos > GetTabPos(prgxTabs[iTab]); // insert new tabstop
iTab++) ;
if(iTab >= MAX_TAB_STOPS) return S_FALSE;
LONG tbPosCurrent = GetTabPos(prgxTabs[iTab]); if(iTab == _bTabCount || tbPosCurrent != tbPos) { if(_bTabCount >= MAX_TAB_STOPS) return S_FALSE;
MoveMemory(&prgxTabs[iTab + 1], // Shift array down
&prgxTabs[iTab], // (unless iTab = Count)
(_bTabCount - iTab)*sizeof(LONG));
_bTabCount++; // Increment tab count
} prgxTabs[iTab] = tbValue; return NOERROR; }
/*
* CParaFormat::Apply(pPF, dwMask, dwMask2) * * @mfunc * Apply *<p pPF> to this CParaFormat as specified by nonzero bits in * <p pPF>->dwMask * * @rdesc * HRESULT = E_INVALIDARG or NOERROR */ HRESULT CParaFormat::Apply ( const CParaFormat *pPF, //@parm CParaFormat to apply to this PF
DWORD dwMask, //@parm mask to use
DWORD dwMask2) //@parm Mask for additional internal parms
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Apply");
const DWORD dwMaskApply = dwMask; BOOL fPF = dwMask2 & PFM2_PARAFORMAT; WORD wEffectMask;
if(dwMaskApply & PFM_NUMBERING) _wNumbering = pPF->_wNumbering;
if(dwMaskApply & PFM_OFFSET) { if (!IsValidTwip(pPF->_dxOffset)) return E_INVALIDARG; _dxOffset = pPF->_dxOffset; }
if(dwMaskApply & PFM_STARTINDENT) { if (!IsValidTwip(pPF->_dxStartIndent)) return E_INVALIDARG;
_dxStartIndent = pPF->_dxStartIndent; } else if(dwMaskApply & PFM_OFFSETINDENT) { if (!IsValidTwip(pPF->_dxStartIndent)) return E_INVALIDARG;
// bug fix #5761
LONG dx = max(0, _dxStartIndent + pPF->_dxStartIndent);
// Disallow shifts that move start of first or subsequent lines left of left margin.
// Normally we just make indent zero in paraformat check below,
// but in the case of bullet we want some space left.
if(!_wNumbering || dx + _dxOffset >= 0) _dxStartIndent = dx; }
if(dwMaskApply & PFM_RIGHTINDENT) { if (!IsValidTwip(pPF->_dxRightIndent)) return E_INVALIDARG;
_dxRightIndent = pPF->_dxRightIndent; }
if(dwMaskApply & PFM_ALIGNMENT) { if(!fPF && !IN_RANGE(PFA_LEFT, pPF->_bAlignment, PFA_SNAP_GRID)) { TRACEERRORSZ("CParaFormat::Apply: invalid Alignment ignored"); return E_INVALIDARG; } if(pPF->_bAlignment <= PFA_SNAP_GRID) _bAlignment = pPF->_bAlignment; }
// Reset effect bits to be modified and OR in supplied values
wEffectMask = (WORD)((dwMaskApply >> 16) | (dwMask2 & PFM2_TABLEROWSHIFTED)); _wEffects &= ~wEffectMask; _wEffects |= pPF->_wEffects & wEffectMask;
if(dwMaskApply & PFM_TABSTOPS) { LONG cmax = IsTableRowDelimiter() ? MAX_TABLE_CELLS : MAX_TAB_STOPS; _bTabCount = (BYTE)min(pPF->_bTabCount, cmax); _bTabCount = (BYTE)max(_bTabCount, 0); _iTabs = pPF->_iTabs; AssertSz(!_bTabCount || _iTabs >= 0, "CParaFormat::Apply: illegal _iTabs value"); }
if ((dwMaskApply & PFM_RTLPARA) && !(dwMaskApply & PFM_ALIGNMENT) && _bAlignment != PFA_CENTER) { _bAlignment = IsRtlPara() ? PFA_RIGHT : PFA_LEFT; }
// PARAFORMAT check
if(fPF) { if(dwMaskApply & (PFM_STARTINDENT | PFM_OFFSET)) { if(_dxStartIndent < 0) // Don't let indent go
_dxStartIndent = 0; // negative
if(_dxStartIndent + _dxOffset < 0) // Don't let indent +
_dxOffset = -_dxStartIndent; // offset go negative
} return NOERROR; // Nothing more for
} // PARAFORMAT
// PARAFORMAT2 extensions
if(dwMaskApply & PFM_SPACEBEFORE) { _dySpaceBefore = 0;
if (pPF->_dySpaceBefore > 0) _dySpaceBefore = pPF->_dySpaceBefore; }
if(dwMaskApply & PFM_SPACEAFTER) { _dySpaceAfter = 0;
if (pPF->_dySpaceAfter > 0) _dySpaceAfter = pPF->_dySpaceAfter; }
if(dwMaskApply & PFM_LINESPACING) { _dyLineSpacing = pPF->_dyLineSpacing; _bLineSpacingRule = pPF->_bLineSpacingRule; }
if(dwMaskApply & PFM_OUTLINELEVEL) _bOutlineLevel = pPF->_bOutlineLevel;
if(dwMaskApply & PFM_STYLE) HandleStyle(pPF->_sStyle);
Assert((_bOutlineLevel & 1) ^ IsHeadingStyle(_sStyle));
if(dwMaskApply & PFM_SHADING) { _wShadingWeight = pPF->_wShadingWeight; _wShadingStyle = pPF->_wShadingStyle; }
if(dwMaskApply & PFM_NUMBERINGSTART) _wNumberingStart = pPF->_wNumberingStart;
if(dwMaskApply & PFM_NUMBERINGSTYLE) _wNumberingStyle = pPF->_wNumberingStyle;
if(dwMaskApply & PFM_NUMBERINGTAB) _wNumberingTab = pPF->_wNumberingTab;
if(dwMaskApply & PFM_BORDER) { _dwBorderColor = pPF->_dwBorderColor; _wBorders = pPF->_wBorders; _wBorderSpace = pPF->_wBorderSpace; _wBorderWidth = pPF->_wBorderWidth; }
if(dwMaskApply & PFM_TABLE) _bTableLevel = pPF->_bTableLevel;
#ifdef DEBUG
ValidateTabs(); AssertSz((!(_wEffects & PFE_TABLE) || _bTableLevel) && _bTableLevel >= 0, "CParaFormat::Apply: invalid table level"); #endif // DEBUG
return NOERROR; }
/*
* CParaFormat::ApplyDefaultStyle(Style) * * @mfunc * Copy default properties for Style */ void CParaFormat::ApplyDefaultStyle ( LONG Style) //@parm Style to apply
{ Assert(IsKnownStyle(Style));
if(IsHeadingStyle(Style)) // Set Style's dySpaceBefore,
{ // dySpaceAfter (in twips)
_dySpaceBefore = 12*20; // (same for all headings)
_dySpaceAfter = 3*20; _wNumbering = 0; // No numbering
} }
/*
* CParaFormat::DeleteTab(tbPos) * * @mfunc * Delete tabstop at position <p tbPos> * * @rdesc * (success) ? NOERROR : S_FALSE */ HRESULT CParaFormat::DeleteTab ( LONG tbPos, //@parm Tab position to delete
LONG * prgxTabs) //@parm Tab array to use
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::DeleteTab");
if(tbPos <= 0 || IsTableRowDelimiter()) return E_INVALIDARG;
LONG Count = _bTabCount; for(LONG iTab = 0; iTab < Count; iTab++) // Find tabstop for position
{ if(GetTabPos(prgxTabs[iTab]) == tbPos) { MoveMemory(&prgxTabs[iTab], // Shift array down
&prgxTabs[iTab + 1], // (unless iTab is last tab)
(Count - iTab - 1)*sizeof(LONG)); _bTabCount--; // Decrement tab count and
return NOERROR; // signal no error
} } return S_FALSE; }
/*
* CParaFormat::Delta(pPF, fPARAFORMAT) * * @mfunc * return mask of differences between this CParaFormat and *<p pPF>. * 1-bits indicate corresponding parameters differ; 0 indicates they * are the same * * @rdesc * mask of differences between this CParaFormat and *<p pPF> */ DWORD CParaFormat::Delta ( CParaFormat *pPF, //@parm CParaFormat to compare this
BOOL fPARAFORMAT) const // CParaFormat to
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Delta");
LONG dwT = 0; // No differences yet
if(_wNumbering != pPF->_wNumbering) dwT |= PFM_NUMBERING; // _wNumbering values differ
if(_dxStartIndent != pPF->_dxStartIndent) dwT |= PFM_STARTINDENT; // ...
if(_dxRightIndent != pPF->_dxRightIndent) dwT |= PFM_RIGHTINDENT;
if(_dxOffset != pPF->_dxOffset) dwT |= PFM_OFFSET;
if(_bAlignment != pPF->_bAlignment) dwT |= PFM_ALIGNMENT;
AssertSz(pPF->_bTabCount >= 0 && pPF->_bTabCount <= (pPF->IsTableRowDelimiter() ? MAX_TABLE_CELLS : MAX_TAB_STOPS), "RTR::GetParaFormat(): illegal tab count");
if (_bTabCount != pPF->_bTabCount) dwT |= PFM_TABSTOPS; else if (_bTabCount > 0) { const LONG *pTabs1 = GetTabs(); const LONG *pTabs2 = pPF->GetTabs(); LONG cb = _bTabCount * sizeof(LONG);
if(IsTableRowDelimiter()) cb *= CELL_EXTRA + 1; if (pTabs1 != pTabs2 && (pTabs1 == 0 || pTabs2 == 0 || CompareMemory(pTabs1, pTabs2, cb))) dwT |= PFM_TABSTOPS; }
dwT |= (_wEffects ^ pPF->_wEffects) << 16;
if(!fPARAFORMAT) { if(_dySpaceBefore != pPF->_dySpaceBefore) dwT |= PFM_SPACEBEFORE;
if(_dySpaceAfter != pPF->_dySpaceAfter) dwT |= PFM_SPACEAFTER;
if (_dyLineSpacing != pPF->_dyLineSpacing || _bLineSpacingRule!= pPF->_bLineSpacingRule) { dwT |= PFM_LINESPACING; }
if(_sStyle != pPF->_sStyle) dwT |= PFM_STYLE;
if (_wShadingWeight != pPF->_wShadingWeight || _wShadingStyle != pPF->_wShadingStyle) { dwT |= PFM_SHADING; }
if(_wNumberingStart != pPF->_wNumberingStart) dwT |= PFM_NUMBERINGSTART;
if(_wNumberingStyle != pPF->_wNumberingStyle) dwT |= PFM_NUMBERINGSTYLE;
if(_wNumberingTab != pPF->_wNumberingTab) dwT |= PFM_NUMBERINGTAB;
if (_wBorders != pPF->_wBorders || _wBorderWidth != pPF->_wBorderWidth || _wBorderSpace != pPF->_wBorderSpace || _dwBorderColor != pPF->_dwBorderColor) { dwT |= PFM_BORDER; } if(_bTableLevel != pPF->_bTableLevel) dwT |= PFM_TABLEROWDELIMITER; }
return dwT; }
#define PFM_IGNORE (PFM_OUTLINELEVEL | PFM_COLLAPSED | PFM_BOX | PFM_TABLE | PFM_TABLEROWDELIMITER)
/*
* CParaFormat::fSetStyle(dwMask, dwMask2) * * @mfunc * Return TRUE iff this PF specifies that the style should be set. * See code for list of conditions for this to be true * * @rdesc * TRUE iff pCF specifies that the style _sStyle should be set */ BOOL CParaFormat::fSetStyle( DWORD dwMask, //@parm mask to use
DWORD dwMask2) const //@parm Mask for additional internal parms
{ return (dwMask & ~PFM_IGNORE) != (PFM_ALL2 & ~(PFM_TABLE | PFM_TABLEROWDELIMITER)) && !(dwMask2 & (PFM2_PARAFORMAT | PFM2_ALLOWTRDCHANGE)) && dwMask & PFM_STYLE && IsKnownStyle(_sStyle); }
/*
* CParaFormat::Get(pPF2) * * @mfunc * Copy this CParaFormat to *<p pPF> */ void CParaFormat::Get ( PARAFORMAT2 *pPF2) const //@parm PARAFORMAT2 to copy this CParaFormat to
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Get");
LONG cb = pPF2->cbSize;
pPF2->dwMask = PFM_ALL2; // Default PARAFORMAT2
if(cb != sizeof(PARAFORMAT2)) // It isn't
{ pPF2->dwMask = PFM_ALL; // Make it PARAFORMAT
Assert(cb == sizeof(PARAFORMAT)); // It better be a PARAFORMAT
} CopyMemory(&pPF2->wNumbering, &_wNumbering, (char *)&_bAlignment - (char *)&_wNumbering); pPF2->wAlignment = _bAlignment; pPF2->cTabCount = _bTabCount;
LONG cb1 = _bTabCount*sizeof(LONG); if(_bTabCount) { // Need API for handling table cells. For now, just don't overwrite
// pPF2->rgxTabs[].
cb1 = min(cb1, (LONG)MAX_TAB_STOPS*sizeof(LONG)); AssertSz(_iTabs >= 0, "CParaFormat::Get: illegal _iTabs value"); CopyMemory(pPF2->rgxTabs, GetTabsCache()->Deref(_iTabs), cb1); } ZeroMemory(pPF2->rgxTabs + _bTabCount, MAX_TAB_STOPS*sizeof(LONG) - cb1); CopyMemory(&pPF2->dySpaceBefore, &_dySpaceBefore, cb - offsetof(PARAFORMAT2, dySpaceBefore)); }
/*
* CParaFormat::GetRTLRowLength() * * @mfunc * Get the length of the current row if this CParaFormat is a table * row delimiter with a PFE_RTLPara effect. * * @rdesc * Length of current row if PFE_TABLEROWDELIMITER and PFE_RTLPARA are * on; else 0 */ LONG CParaFormat::GetRTLRowLength() const { if ((_wEffects & (PFE_TABLEROWDELIMITER | PFE_RTLPARA)) != (PFE_TABLEROWDELIMITER | PFE_RTLPARA)) { return 0; // Not an RTL row
}
const CELLPARMS * prgCellParms = GetCellParms();
for(LONG i = 0, dulRTLRow = 0; i < _bTabCount; i++) dulRTLRow += GetCellWidth(prgCellParms[i].uCell);
return dulRTLRow; }
/*
* CParaFormat::GetTab (iTab, ptbPos, ptbAln, ptbLdr, prgxTabs) * * @mfunc * Get tab parameters for the <p iTab> th tab, that is, set *<p ptbPos>, * *<p ptbAln>, and *<p ptbLdr> equal to the <p iTab> th tab's * displacement, alignment type, and leader style, respectively. The * displacement is given in twips. * * @rdesc * HRESULT = (no <p iTab> tab) ? E_INVALIDARG : NOERROR */ HRESULT CParaFormat::GetTab ( long iTab, //@parm Index of tab to retrieve info for
long * ptbPos, //@parm Out parm to receive tab displacement
long * ptbAln, //@parm Out parm to receive tab alignment type
long * ptbLdr, //@parm Out parm to receive tab leader style
const LONG *prgxTabs) const //@parm Tab array
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEEXTERN, "CParaFormat::GetTab");
AssertSz(ptbPos && ptbAln && ptbLdr, "CParaFormat::GetTab: illegal arguments");
if(IsTableRowDelimiter()) return E_INVALIDARG;
if(iTab < 0) // Get tab previous to, at,
{ // or subsequent to the
if(iTab < tomTabBack) // position *ptbPos
return E_INVALIDARG;
LONG i; LONG tbPos = *ptbPos; LONG tbPosi;
*ptbPos = 0; // Default tab not found
for(i = 0; i < _bTabCount && // Find *ptbPos
tbPos > GetTabPos(prgxTabs[i]); i++) ;
tbPosi = GetTabPos(prgxTabs[i]); // tbPos <= tbPosi
if(iTab == tomTabBack) // Get tab info for tab
i--; // previous to tbPos
else if(iTab == tomTabNext) // Get tab info for tab
{ // following tbPos
if(tbPos == tbPosi) i++; } else if(tbPos != tbPosi) // tomTabHere
return S_FALSE;
iTab = i; } if((DWORD)iTab >= (DWORD)_bTabCount) // DWORD cast also
return E_INVALIDARG; // catches values < 0
iTab = prgxTabs[iTab]; *ptbPos = GetTabPos(iTab); *ptbAln = GetTabAlign(iTab); *ptbLdr = GetTabLdr(iTab); return NOERROR; }
/*
* CParaFormat::GetTabs () * * @mfunc * Get ptr to tab array. Use GetTabPos(), GetTabAlign(), and * GetTabLdr() to access the tab position, alignment, and leader * type, respectively. * * @rdesc * Ptr to tab array. */ const LONG * CParaFormat::GetTabs () const { return GetTabsCache()->Deref(_iTabs); }
/*
* CParaFormat::HandleStyle(Style) * * @func * If Style is a promote/demote command, i.e., if abs((char)Style) * <= # heading styles - 1, add (char)Style to sStyle (if heading) * and to bOutlineLevel (subject to defined max and min values); * else sStyle = Style. * * @rdesc * return TRUE iff sStyle or bOutlineLevel changed * * @devnote * Heading styles are -2 (heading 1) through -10 (heading 9), which * with TOM and WOM. Heading outline levels are 0, 2,..., 16, * corresponding to headings 1 through 9 (NHSTYLES), respectively, * while text that follows has outline levels 1, 3,..., 17. This value * is used for indentation. Collapsed text has the PFE_COLLAPSED bit set. */ BOOL CParaFormat::HandleStyle( LONG Style) //@parm Style, promote/demote code, or collapse-level code
{ if(IsStyleCommand(Style)) // Set collapse level
{ WORD wEffectsSave = _wEffects;
Style = (char)Style; // Sign extend low byte
if(IN_RANGE(1, Style, NHSTYLES)) { _wEffects &= ~PFE_COLLAPSED; if((_bOutlineLevel & 1) || _bOutlineLevel > 2*(Style - 1)) _wEffects |= PFE_COLLAPSED; // Collapse nonheadings and
} // higher numbered headings
else if(Style == -1) _wEffects &= ~PFE_COLLAPSED; // Expand all
return _wEffects != wEffectsSave; // Return whether something
} // changed
// Ordinary Style specification
BYTE bLevel = _bOutlineLevel; _bOutlineLevel |= 1; // Default not a heading
if(IsHeadingStyle(Style)) // Headings have levels
{ // 0, 2,..., 16, while the
_bOutlineLevel = -2*(Style // text that follows has
- STYLE_HEADING_1); // 1, 3,..., 17.
} if(_sStyle == Style && bLevel == _bOutlineLevel) return FALSE; // No change
_sStyle = (SHORT)Style; return TRUE; }
/*
* CParaFormat::InitDefault(wDefEffects) * * @mfunc * Initialize this CParaFormat with default paragraph formatting * * @rdesc * HRESULT = (if success) ? NOERROR : E_FAIL */ HRESULT CParaFormat::InitDefault( WORD wDefEffects) { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::InitDefault"); ZeroMemory(this, sizeof(CParaFormat)); _bAlignment = PFA_LEFT; _sStyle = STYLE_NORMAL; // Default style
_wEffects = wDefEffects; _bOutlineLevel = 1; // Default highest text outline
_iTabs = -1; // level
#if lDefaultTab <= 0
#error "default tab (lDefaultTab) must be > 0"
#endif
return NOERROR; }
/*
* CParaFormat::NumToStr(pch, n) * * @mfunc * Convert the list number n to a string taking into consideration * CParaFormat::wNumbering, wNumberingStart, and wNumberingStyle * * @rdesc * cch of string converted */ LONG CParaFormat::NumToStr( TCHAR * pch, //@parm Target string
LONG n, //@parm Number + 1 to convert
DWORD grf) const //@parm Collection of flags
{ if(IsNumberSuppressed()) { *pch = 0; return 0; // Number/bullet suppressed
}
if(!n) // Bullet of some kind
{ // CParaFormat::wNumbering
*pch++ = (_wNumbering > ' ') // values > ' ' are Unicode
? _wNumbering : 0x00B7; // bullets. Else use bullet
return 1; // in symbol font
}
// Numbering of some kind
// i ii iii iv v vi vii viii ix
const BYTE RomanCode[] = {1, 5, 0x15, 9, 2, 6, 0x16, 0x56, 0xd}; const char RomanLetter[] = "ivxlcdmno"; BOOL fRtlPara = IsRtlPara() && !(grf & fRtfWrite); LONG RomanOffset = 0; LONG cch = 0; // No chars yet
WCHAR ch = fRtlPara && (grf & fIndicDigits) ? 0x0660 : '0'; // Default char code offset
LONG d = 1; // Divisor
LONG r = 10; // Default radix
LONG quot, rem; // ldiv result
LONG Style = (_wNumberingStyle << 8) & 0xF0000;
n--; // Convert to number offset
if(Style == tomListParentheses || // Numbering like: (x)
fRtlPara && Style == 0) // or 1) in bidi text.
{ cch = 1; // Store leading lparen
*pch++ = '('; } else if (Style == tomListPeriod && fRtlPara) { cch = 1; *pch++ = '.'; Style = tomListPlain; }
if(_wNumbering == tomListNumberAsSequence) ch = _wNumberingStart; // Needs generalizations, e.g.,
// appropriate radix
else { n += _wNumberingStart; if(IN_RANGE(tomListNumberAsLCLetter, _wNumbering, tomListNumberAsUCLetter)) { ch = (_wNumbering == tomListNumberAsLCLetter) ? 'a' : 'A'; if(_wNumberingStart >= 1) n--; r = 26; // LC or UC alphabetic number
} // Radix 26
}
while(d < n) { d *= r; // d = smallest power of r > n
RomanOffset += 2; } if(n && d > n) { d /= r; RomanOffset -= 2; }
while(d) { quot = n / d; rem = n % d; if(IN_RANGE(tomListNumberAsLCRoman, _wNumbering, tomListNumberAsUCRoman)) { if(quot) { n = RomanCode[quot - 1]; while(n) { ch = RomanLetter[(n & 3) + RomanOffset - 1]; if(_wNumbering == tomListNumberAsUCRoman) ch &= 0x5F; *pch++ = ch; n >>= 2; cch++; } } RomanOffset -= 2; } else { n = quot + ch; if(r == 26 && d > 1) // If alphabetic higher-order
n--; // digit, base it on 'a' or 'A'
*pch++ = (WORD)n; // Store digit
cch++; } n = rem; // Setup remainder
d /= r; } if (Style != tomListPlain && // Trailing text
(!fRtlPara || Style)) { // We only do rparen or period
*pch++ = (Style == tomListPeriod) ? '.' : ')';
cch++; } *pch = 0; // Null terminate for RTF writer
return cch; }
/*
* CParaFormat::Set(pPF2) * * @mfunc * Copy PARAFORMAT or PARAFORMAT2 *<p pPF> to this CParaFormat */ void CParaFormat::Set ( const PARAFORMAT2 *pPF2) //@parm PARAFORMAT to copy to this CParaFormat
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Set");
CopyMemory(&_wNumbering, &pPF2->wNumbering, (char *)&_bAlignment - (char *)&_wNumbering); _bAlignment = (BYTE)pPF2->wAlignment;
_iTabs = -1; _bTabCount = 0; _wEffects &= ~PFE_TABLEROWDELIMITER;
if((pPF2->dwMask & PFM_TABSTOPS) && pPF2->cTabCount) { LONG cTab = min(pPF2->cTabCount, MAX_TAB_STOPS); if (pPF2->dwMask & PFM_TABLEROWDELIMITER && pPF2->wEffects & PFE_TABLEROWDELIMITER) { // TODO: create an API for setting cell info
} else { _bTabCount = cTab; _iTabs = GetTabsCache()->Cache(pPF2->rgxTabs, cTab); } }
if(pPF2->dwMask & ~PFM_ALL) { Assert(pPF2->cbSize == sizeof(PARAFORMAT2));
CopyMemory(&_dySpaceBefore, &pPF2->dySpaceBefore, sizeof(PARAFORMAT2) - offsetof(PARAFORMAT2, dySpaceBefore)); }
#ifdef DEBUG
ValidateTabs(); #endif // DEBUG
}
/*
* CParaFormat::UpdateNumber(n, pPF) * * @mfunc * Return new value of number for paragraph described by this PF * following a paragraph described by pPF * * @rdesc * New number for paragraph described by this PF */ LONG CParaFormat::UpdateNumber ( LONG n, //@parm Current value of number
const CParaFormat *pPF) const //@parm Previous CParaFormat
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::UpdateNumber");
if(!IsListNumbered()) return 0; // No numbering
if(IsNumberSuppressed()) return n; // Number is suppressed, so no change
if (!pPF || (pPF->_wEffects & PFE_TABLEROWDELIMITER) || _wNumbering != pPF->_wNumbering || (_wNumberingStyle & PFNS_NEWNUMBER) || (_wNumberingStyle != pPF->_wNumberingStyle && !pPF->IsNumberSuppressed()) || _wNumberingStart != pPF->_wNumberingStart) { // Numbering type or style
return 1; // changed, so start over
} return n + 1; // Same kind of numbering,
}
#ifdef DEBUG
/*
* CParaFormat::ValidateTabs() * * @mfunc * Makes sure that a set of tabs would make sense for a non-table * paragraph. Is called in places where we have set the tabs. * * @rdesc * None. */ void CParaFormat::ValidateTabs() { if (_wEffects & PFE_TABLE) { // It would be nice to assert something reasonable here. However, the
// rtf reader insists on setting things inconsistenly and I don't
// have time at the moment to figure out why. (a-rsail)
// AssertSz((_bTabCount != 0),
// "CParaFormat::ValidateTabs: table with invalid tab count ");
return; }
// Non-table case.
// It would be nice to assert on the consistency between these _bTabCount and _iTabs
// but rtf reader has troubles with this.
// AssertSz(((_bTabCount != 0) && (-1 != _iTabs)) || ((-1 == _iTabs) && (0 == _bTabCount)),
// "CParaFormat::ValidateTabs: tab count and default tab index inconsistent");
if (-1 == _iTabs) { // No tabs to validate so we are done.
return; }
const LONG *prgtabs = GetTabs();
AssertSz(prgtabs != NULL, "CParaFormat::ValidateTabs: missing tab table");
for (int i = 0; i < _bTabCount; i++) { AssertSz(GetTabAlign(prgtabs[i]) <= tomAlignBar, "CParaFormat::ValidateTabs: Invalid tab being set"); } } #endif // DEBUG
/*
* CELLPARMS::ICellFromUCell(prgCell, dul, cCell) * * @mfunc * Return iCell such that SUM(CellWidths[iCell]) == dul. Return -1 if * no dul is found in prgCell * * @rdesc * iCell such that SUM(CellWidths[iCell]) == dul */ LONG CELLPARMS::ICellFromUCell( LONG dul, //@parm Logical x offset of cell right border
LONG cCell) const //@parm Count of cells in array
{ const CELLPARMS *prgCell = this; LONG x = 0;
for(LONG i = 0; i < cCell; i++) { x += GetCellWidth(prgCell[i].uCell); if(x == dul) return i; } return -1; }
//------------------------- Helper Functions -----------------------------------
// Defines and fixed font size details for increasing/decreasing font size
#define PWD_FONTSIZEPOINTMIN 1
// The following corresponds to the max signed 2-byte TWIP value, (32760)
#define PWD_FONTSIZEPOINTMAX 1638
typedef struct tagfsFixup { BYTE EndValue; BYTE Delta; } FSFIXUP;
const FSFIXUP fsFixups[] = { 12, 1, 28, 2, 36, 0, 48, 0, 72, 0, 80, 0, 0, 10 // EndValue = 0 case is treated as "infinite"
};
#define PWD_FONTSIZEMAXFIXUPS (sizeof(fsFixups)/sizeof(fsFixups[0]))
/*
* GetUsableFontHeight(ySrcHeight, lPointChange) * * @func * Return a font size for setting text or insertion point attributes * * @rdesc * New TWIPS height * * @devnote * Copied from WinCE RichEdit code (written by V-GUYB) */ LONG GetUsableFontHeight( LONG ySrcHeight, //@parm Current font size in twips
LONG lPointChange) //@parm Increase in pt size, (-ve if shrinking)
{ LONG EndValue; LONG Delta; int i; LONG yRetHeight;
// Input height in twips here, (TWentIeths of a Point).
// Note, a Point is a 1/72th of an inch. To make these
// calculations clearer, use point sizes here. Input height
// in twips is always divisible by 20 (NOTE (MS3): maybe with
// a truncation, since RTF uses half-point units).
yRetHeight = (ySrcHeight / 20) + lPointChange;
// Fix new font size to match sizes used by Word95
for(i = 0; i < PWD_FONTSIZEMAXFIXUPS; ++i) { EndValue = fsFixups[i].EndValue; Delta = fsFixups[i].Delta;
// Does new height lie in this range of point sizes?
if(yRetHeight <= EndValue || !EndValue) { // If new height = EndValue, then it doesn't need adjusting
if(yRetHeight != EndValue) { // Adjust new height to fit this range of point sizes. If
// Delta = 1, all point sizes in this range stay as they are.
if(!Delta) { // Everything in this range is rounded to the EndValue
yRetHeight = fsFixups[(lPointChange > 0 ? i : max(i - 1, 0))].EndValue; } else if(Delta != 1) { // Round new height to next delta in this range
yRetHeight = ((yRetHeight + (lPointChange > 0 ? Delta - 1 : 0)) / Delta) * Delta; } } break; } }
// Limit the new text size. Note, if we fix the text size
// now, then we won't take any special action if we change
// the text size later in the other direction. For example,
// we shrink chars with size 1 and 2. They both change to
// size 1. Then we grow them both to 2. So they are the
// same size now, even though they weren't before. This
// matches Word95 behavior.
yRetHeight = max(yRetHeight, PWD_FONTSIZEPOINTMIN); yRetHeight = min(yRetHeight, PWD_FONTSIZEPOINTMAX);
return yRetHeight*20; // Return value in twips
}
/*
* IsValidCharFormatW(pCF) * * @func * Return TRUE iff the structure *<p pCF> has the correct size to be * a CHARFORMAT or a CHARFORMAT2 * * @rdesc * Return TRUE if *<p pCF> is a valid CHARFORMAT(2) */ BOOL IsValidCharFormatW ( const CHARFORMAT * pCF) //@parm CHARFORMAT to validate
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidCharFormat");
return pCF && (pCF->cbSize == sizeof(CHARFORMATW) || pCF->cbSize == sizeof(CHARFORMAT2W)); }
/*
* IsValidCharFormatA(pCFA) * * @func * Return TRUE iff the structure *<p pCF> has the correct size to be * a CHARFORMATA or a CHARFORMAT2A * * @rdesc * Return TRUE if *<p pCF> is a valid CHARFORMAT(2)A */ BOOL IsValidCharFormatA ( const CHARFORMATA * pCFA) //@parm CHARFORMATA to validate
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidCharFormatA");
return pCFA && (pCFA->cbSize == sizeof(CHARFORMATA) || pCFA->cbSize == sizeof(CHARFORMAT2A)); }
/*
* IsValidParaFormat(pPF) * * @func * Return TRUE iff the structure *<p pPF> has the correct size to be * a PARAFORMAT or a PARAFORMAT2 * * @rdesc * Return TRUE if *<p pPF> is a valid PARAFORMAT(2) */ BOOL IsValidParaFormat ( const PARAFORMAT * pPF) //@parm PARAFORMAT to validate
{ TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidParaFormat");
if (pPF && (pPF->cbSize == sizeof(PARAFORMAT) || pPF->cbSize == sizeof(PARAFORMAT2))) { return TRUE; } TRACEERRORSZ("!!!!!!!!!!! bogus PARAFORMAT from client !!!!!!!!!!!!!"); return FALSE; }
/*
* Get16BitTwips(dy) * * @func * Return dy if |dy| < 32768; else return 32767, i.e., max value * that fits into a SHORT * * @rdesc * dy if abs(cy) < 32768; else 32767 */ SHORT Get16BitTwips(LONG dy) { return abs(dy) < 32768 ? (SHORT)dy : 32767; }
|