Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1605 lines
44 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module CFPF.C -- -- RichEdit CCharFormat and CParaFormat Classes |
  5. *
  6. * Created: <nl>
  7. * 9/1995 -- Murray Sargent <nl>
  8. *
  9. * @devnote
  10. * The this ptr for all methods points to an internal format class, i.e.,
  11. * either a CCharFormat or a CParaFormat, which uses the cbSize field as
  12. * a reference count. The pCF or pPF argument points at an external
  13. * CCharFormat or CParaFormat class, that is, pCF->cbSize and pPF->cbSize
  14. * give the size of their structure. The code still assumes that both
  15. * internal and external forms are derived from the CHARFORMAT(2) and
  16. * PARAFORMAT(2) API structures, so some redesign would be necessary to
  17. * obtain a more space-efficient internal form.
  18. *
  19. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  20. */
  21. #include "_common.h"
  22. #include "_array.h" // for fumemmov()
  23. #include "_rtfconv.h" // for IsCharSetValid()
  24. #include "_font.h" // for GetFontNameIndex(), GetFontName()
  25. ASSERTDATA
  26. // Table of formatting info for Normal and Heading styles
  27. const STYLEFORMAT g_Style[] = // {dwEffects; yHeight}
  28. { // Measurements in points
  29. {CFE_BOLD, 14}, // Heading 1
  30. {CFE_BOLD + CFE_ITALIC, 12}, // Heading 2
  31. {0, 12}, // Heading 3
  32. {CFE_BOLD, 12}, // Heading 4
  33. {0, 11}, // Heading 5
  34. {CFE_ITALIC, 11}, // Heading 6
  35. {0, 0}, // Heading 7
  36. {CFE_ITALIC, 0}, // Heading 8
  37. {CFE_BOLD + CFE_ITALIC, 9} // Heading 9
  38. };
  39. BOOL IsValidTwip(LONG dl)
  40. {
  41. static const LONG dlMax = 0x00FFFFFF;
  42. static const LONG dlMin = -0x00FFFFFF;
  43. if (dl > dlMax || dl < dlMin)
  44. return FALSE;
  45. return TRUE;
  46. }
  47. //------------------------- CCharFormat Class -----------------------------------
  48. /*
  49. * CCharFormat::Apply(pCF, dwMask, dwMask2)
  50. *
  51. * @mfunc
  52. * Apply *<p pCF> to this CCharFormat as specified by nonzero bits in
  53. * dwMask and dwMask2
  54. *
  55. * @devnote
  56. * Autocolor is dealt with through a neat little hack made possible
  57. * by the choice CFE_AUTOCOLOR = CFM_COLOR (see richedit.h). Hence
  58. * if <p pCF>->dwMask specifies color, it automatically resets autocolor
  59. * provided (<p pCF>->dwEffects & CFE_AUTOCOLOR) is zero.
  60. *
  61. * *<p pCF> is an external CCharFormat, i.e., it's either a CHARFORMAT
  62. * or a CHARFORMAT2 with the appropriate size given by cbSize. But
  63. * this CCharFormat is internal and cbSize is used as a reference count.
  64. */
  65. HRESULT CCharFormat::Apply (
  66. const CCharFormat *pCF, //@parm CCharFormat to apply to this CF
  67. DWORD dwMask, //@parm Mask corresponding to CHARFORMAT2
  68. DWORD dwMask2) //@parm Mask for additional internal parms
  69. {
  70. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Apply");
  71. DWORD dwEffectMask = dwMask & CFM_EFFECTS2;
  72. bool fNewCharset = false;
  73. // Reset effect bits to be modified and OR in supplied values
  74. _dwEffects &= ~dwEffectMask;
  75. _dwEffects |= pCF->_dwEffects & dwEffectMask;
  76. // Ditto for additional effects given by dwMask2
  77. dwEffectMask = dwMask2 & 0xBBFC0000; // Don't allow autocolors, sub/sups
  78. _dwEffects &= ~dwEffectMask;
  79. _dwEffects |= pCF->_dwEffects & dwEffectMask;
  80. // If CFM_BOLD is specified, it overrides the font weight
  81. if(dwMask & CFM_BOLD)
  82. _wWeight = (pCF->_dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  83. // Handle CFM_COLOR since it's overloaded with CFE_AUTOCOLOR
  84. if(dwMask & CFM_COLOR)
  85. _crTextColor = pCF->_crTextColor;
  86. if(dwMask & ~CFM_EFFECTS) // Early out if only dwEffects
  87. { // is modified. Note that
  88. if(dwMask & CFM_SIZE) // CFM_EFFECTS includes CFM_COLOR
  89. {
  90. // If dwMask2 CFM2_USABLEFONT bit is set, pCF->_yHeight (from
  91. // EM_SETFONTSIZE wparam) is signed increment in points.
  92. _yHeight = dwMask2 & CFM2_USABLEFONT
  93. ? GetUsableFontHeight(_yHeight, pCF->_yHeight)
  94. : pCF->_yHeight;
  95. }
  96. if(dwMask & CFM_OFFSET)
  97. _yOffset = pCF->_yOffset;
  98. if((dwMask & CFM_CHARSET) && IsCharSetValid(pCF->_bCharSet) &&
  99. // Caller guarantees no check needed
  100. (dwMask2 & (CFM2_NOCHARSETCHECK | CFM2_MATCHFONT) ||
  101. // Caller is itemizer. Change to ANSI_CHARSET only if current is BiDi,
  102. // dont change if current is DBCS/FE charset or symbol.
  103. (dwMask2 & CFM2_SCRIPT &&
  104. (!pCF->_bCharSet && IsBiDiCharSet(_bCharSet) ||
  105. pCF->_bCharSet && !IsFECharSet(_bCharSet) && !IsSymbolOrOEM(_bCharSet) && !(_dwEffects & CFE_RUNISDBCS))) ||
  106. // Caller is not itemizer. Allow consistent direction
  107. (!(dwMask2 & CFM2_SCRIPT) &&
  108. (!(IsRTLCharSet(_bCharSet) ^ IsRTLCharSet(pCF->_bCharSet)) ||
  109. IsSymbolOrOEM(pCF->_bCharSet)))))
  110. {
  111. fNewCharset = TRUE;
  112. _bCharSet = pCF->_bCharSet;
  113. }
  114. if ((dwMask2 & (CFM2_MATCHFONT | CFM2_ADJUSTFONTSIZE)) == (CFM2_MATCHFONT | CFM2_ADJUSTFONTSIZE) &&
  115. _bCharSet != pCF->_bCharSet && (dwMask & CFM_SIZE))
  116. {
  117. // Check if we need to adjust the font size
  118. _yHeight = W32->GetPreferredFontHeight(
  119. (dwMask2 & CFM2_UIFONT) != 0,
  120. pCF->_bCharSet,
  121. _bCharSet,
  122. _yHeight);
  123. }
  124. if(dwMask & CFM_FACE)
  125. {
  126. _bPitchAndFamily = pCF->_bPitchAndFamily;
  127. _iFont = pCF->_iFont;
  128. WCHAR wch = GetFontName((LONG)_iFont)[0];
  129. if (!fNewCharset && wch == L'\0')
  130. {
  131. // API to choose default font
  132. INT uCpg = GetLocaleCodePage();
  133. SHORT iDefFont;
  134. BYTE yDefHeight;
  135. BYTE bDefPitchAndFamily;
  136. // Get default font name and charset
  137. bool fr = W32->GetPreferredFontInfo(
  138. uCpg, FALSE, iDefFont,
  139. (BYTE&)yDefHeight, bDefPitchAndFamily );
  140. if (fr)
  141. {
  142. _bCharSet = GetCharSet(uCpg);
  143. _iFont = iDefFont;
  144. if(!(dwMask & CFM_SIZE) || _yHeight < yDefHeight * 20) // Setup default height if needed.
  145. _yHeight = yDefHeight * 20;
  146. _bPitchAndFamily = bDefPitchAndFamily;
  147. }
  148. }
  149. else if (GetCharFlags(wch) & fFE && !IsFECharSet(_bCharSet))
  150. {
  151. // make sure that we dont end up having DBCS facename with Non-FE charset
  152. DWORD dwFontSig;
  153. if (GetFontSignatureFromFace(_iFont, &dwFontSig))
  154. {
  155. dwFontSig &= (fFE >> 8); // Only interest in FE charset
  156. if (dwFontSig)
  157. _bCharSet = GetFirstAvailCharSet(dwFontSig);
  158. }
  159. }
  160. }
  161. if (!(dwMask2 & CFM2_CHARFORMAT) &&
  162. (dwMask & ~CFM_ALL)) // CHARFORMAT2 extensions
  163. {
  164. if((dwMask & (CFM_WEIGHT | CFM_BOLD)) == CFM_WEIGHT)
  165. {
  166. _wWeight = pCF->_wWeight;
  167. _dwEffects |= CFE_BOLD; // Set above-average
  168. if(_wWeight < 551) // weights to bold
  169. _dwEffects &= ~CFE_BOLD;
  170. }
  171. if(dwMask & CFM_BACKCOLOR)
  172. _crBackColor = pCF->_crBackColor;
  173. if(dwMask & CFM_LCID)
  174. _lcid = pCF->_lcid;
  175. if(dwMask & CFM_SPACING)
  176. _sSpacing = pCF->_sSpacing;
  177. if(dwMask & CFM_KERNING)
  178. _wKerning = pCF->_wKerning;
  179. if(dwMask & CFM_STYLE)
  180. _sStyle = pCF->_sStyle;
  181. if(dwMask & CFM_UNDERLINETYPE)
  182. {
  183. _bUnderlineType = pCF->_bUnderlineType;
  184. if(!(dwMask & CFM_UNDERLINE)) // If CFE_UNDERLINE
  185. { // isn't defined,
  186. _dwEffects &= ~CFE_UNDERLINE; // set it according to
  187. if(_bUnderlineType) // bUnderlineType
  188. _dwEffects |= CFE_UNDERLINE;
  189. }
  190. }
  191. if((dwMask & CFM_ANIMATION) && pCF->_bAnimation <= 18)
  192. _bAnimation = pCF->_bAnimation;
  193. if(dwMask & CFM_REVAUTHOR)
  194. _bRevAuthor = pCF->_bRevAuthor;
  195. }
  196. }
  197. if(dwMask2 & CFM2_SCRIPT)
  198. _wScript = pCF->_wScript;
  199. return NOERROR;
  200. }
  201. /*
  202. * CCharFormat::ApplyDefaultStyle(Style)
  203. *
  204. * @mfunc
  205. * Set default style properties in this CCharFormat
  206. */
  207. void CCharFormat::ApplyDefaultStyle (
  208. LONG Style) //@parm Style to use
  209. {
  210. Assert(IsKnownStyle(Style));
  211. if(IsHeadingStyle(Style))
  212. {
  213. LONG i = -Style + STYLE_HEADING_1;
  214. _dwEffects = (_dwEffects & 0xFFFFFF00) | g_Style[i].bEffects;
  215. _wWeight = (_dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  216. if(g_Style[i].bHeight)
  217. _yHeight = g_Style[i].bHeight * 20;
  218. DWORD dwFontSig;
  219. LONG iFont = _iFont; // Save _iFont in case Arial doesn't
  220. _iFont = IFONT_ARIAL; // support _bCharSet
  221. GetFontSignatureFromFace(_iFont, &dwFontSig);
  222. if(GetFontSig(_bCharSet) & dwFontSig)
  223. _bPitchAndFamily = FF_SWISS;// Arial supports _bCharSet
  224. else
  225. _iFont = iFont; // Restore iFont
  226. }
  227. }
  228. /*
  229. * CCharFormat::Compare(pCF)
  230. *
  231. * @mfunc
  232. * Compare this CCharFormat to *<p pCF>
  233. *
  234. * @rdesc
  235. * TRUE if they are the same not including _cRefs
  236. */
  237. BOOL CCharFormat::Compare (
  238. const CCharFormat *pCF) const //@parm CCharFormat to compare this
  239. { // CCharFormat to
  240. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Compare");
  241. return !CompareMemory(this, pCF, sizeof(CCharFormat));
  242. }
  243. /*
  244. * CCharFormat::Delta(pCF, fCHARFORMAT)
  245. *
  246. * @mfunc
  247. * Calculate dwMask for differences between this CCharformat and
  248. * *<p pCF>
  249. *
  250. * @rdesc
  251. * return dwMask of differences (1 bit means a difference)
  252. */
  253. DWORD CCharFormat::Delta (
  254. CCharFormat *pCF, //@parm CCharFormat to compare this one to
  255. BOOL fCHARFORMAT) const //@parm Only compare CHARFORMAT members
  256. {
  257. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Delta");
  258. // Collect bits for properties
  259. LONG dw = _dwEffects ^ pCF->_dwEffects; // that change. Note: auto
  260. // color is handled since
  261. if(_yHeight != pCF->_yHeight) // CFM_COLOR = CFE_AUTOCOLOR
  262. dw |= CFM_SIZE;
  263. if(_yOffset != pCF->_yOffset)
  264. dw |= CFM_OFFSET;
  265. if(_crTextColor != pCF->_crTextColor)
  266. dw |= CFM_COLOR;
  267. if(_bCharSet != pCF->_bCharSet)
  268. dw |= CFM_CHARSET;
  269. if(_iFont != pCF->_iFont)
  270. dw |= CFM_FACE;
  271. if(fCHARFORMAT)
  272. return dw; // Done with CHARFORMAT stuff
  273. if(_crBackColor != pCF->_crBackColor) // CHARFORMAT2 stuff
  274. dw |= CFM_BACKCOLOR;
  275. if(_wKerning != pCF->_wKerning)
  276. dw |= CFM_KERNING;
  277. if(_lcid != pCF->_lcid)
  278. dw |= CFM_LCID;
  279. if(_wWeight != pCF->_wWeight)
  280. dw |= CFM_WEIGHT;
  281. if(_sSpacing != pCF->_sSpacing)
  282. dw |= CFM_SPACING;
  283. if(_sStyle != pCF->_sStyle)
  284. dw |= CFM_STYLE;
  285. if(_bUnderlineType != pCF->_bUnderlineType)
  286. dw |= CFM_UNDERLINETYPE;
  287. if(_bAnimation != pCF->_bAnimation)
  288. dw |= CFM_ANIMATION;
  289. if(_bRevAuthor != pCF->_bRevAuthor)
  290. dw |= CFM_REVAUTHOR;
  291. return dw;
  292. }
  293. /*
  294. * CCharFormat::fSetStyle(dwMask)
  295. *
  296. * @mfunc
  297. * return TRUE iff pCF specifies that the style should be set. See
  298. * code for list of conditions for this to be true
  299. *
  300. * @rdesc
  301. * TRUE iff pCF specifies that the style _sStyle should be set
  302. */
  303. BOOL CCharFormat::fSetStyle(DWORD dwMask, DWORD dwMask2) const
  304. {
  305. return dwMask != CFM_ALL2 &&
  306. dwMask & CFM_STYLE &&
  307. !(dwMask2 & CFM2_CHARFORMAT) &&
  308. IsKnownStyle(_sStyle);
  309. }
  310. /*
  311. * CCharFormat::Get(pCF, CodePage)
  312. *
  313. * @mfunc
  314. * Copy this CCharFormat to the CHARFORMAT or CHARFORMAT2 *<p pCF>
  315. */
  316. void CCharFormat::Get (
  317. CHARFORMAT2 *pCF2, //@parm CHARFORMAT to copy this CCharFormat to
  318. UINT CodePage) const
  319. {
  320. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Get");
  321. pCF2->dwMask = CFM_ALL; // Use CHARFORMAT
  322. pCF2->dwEffects = _dwEffects;
  323. pCF2->yHeight = _yHeight;
  324. pCF2->yOffset = _yOffset;
  325. pCF2->crTextColor = _crTextColor;
  326. pCF2->bCharSet = GetGdiCharSet(_bCharSet);
  327. pCF2->bPitchAndFamily = _bPitchAndFamily;
  328. UINT cb = pCF2->cbSize;
  329. const WCHAR *pch = GetFontName((LONG)_iFont);
  330. AssertSz((CodePage != 1200) ^ IsValidCharFormatW(pCF2),
  331. "CCharFormat::Get: wrong codepage for CHARFORMAT");
  332. if(CodePage != 1200)
  333. {
  334. if(_dwEffects & CFE_FACENAMEISDBCS)
  335. {
  336. // The face name is actually DBCS stuffed into the unicode
  337. // buffer, so simply un-stuff this DBCS into the ANSI string
  338. char *pachDst = (char *)pCF2->szFaceName;
  339. while(*pch)
  340. *pachDst++ = *pch++;
  341. *pachDst = 0;
  342. }
  343. else
  344. {
  345. MbcsFromUnicode((char *)pCF2->szFaceName, LF_FACESIZE,
  346. pch, -1, CodePage, UN_NOOBJECTS);
  347. }
  348. }
  349. else
  350. wcscpy(pCF2->szFaceName, pch);
  351. if (cb == sizeof(CHARFORMATW) || cb == sizeof(CHARFORMATA)) // We're done
  352. return;
  353. char *pvoid = (char *)&pCF2->wWeight;
  354. if(pCF2->cbSize == sizeof(CHARFORMAT2A))
  355. pvoid -= sizeof(CHARFORMAT2W) - sizeof(CHARFORMAT2A);
  356. else
  357. Assert(pCF2->cbSize == sizeof(CHARFORMAT2));// Better be a CHARFORMAT2
  358. pCF2->dwMask = CFM_ALL2;
  359. CopyMemory(pvoid, &_wWeight, 3*sizeof(DWORD));
  360. CopyMemory(pvoid + 4*sizeof(DWORD), &_sStyle, 2*sizeof(DWORD));
  361. *(DWORD *)(pvoid + 3*sizeof(DWORD)) = 0;
  362. }
  363. /*
  364. * CCharFormat::InitDefault(hfont)
  365. *
  366. * @mfunc
  367. * Initialize this CCharFormat with information coming from the font
  368. * <p hfont>
  369. *
  370. * @rdesc
  371. * HRESULT = (if success) ? NOERROR : E_FAIL
  372. */
  373. HRESULT CCharFormat::InitDefault (
  374. HFONT hfont) //@parm Handle to font info to use
  375. {
  376. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::InitDefault");
  377. LOGFONT lf;
  378. BOOL fUseStockFont = hfont == NULL;
  379. ZeroMemory(this, sizeof(CCharFormat));
  380. // If hfont isn't defined, get LOGFONT for default font
  381. if(!hfont)
  382. hfont = W32->GetSystemFont();
  383. // Get LOGFONT for passed hfont
  384. if(!W32->GetObject(hfont, sizeof(LOGFONT), &lf))
  385. return E_FAIL;
  386. _yHeight = (lf.lfHeight * LY_PER_INCH) / W32->GetYPerInchScreenDC();
  387. if(_yHeight <= 0)
  388. _yHeight = -_yHeight;
  389. else if (fUseStockFont) // This is Cell Height for System Font case
  390. _yHeight -= (W32->GetSysFontLeading() * LY_PER_INCH) / W32->GetYPerInchScreenDC();
  391. else
  392. {
  393. // This is Cell Height, need to get the character height by subtracting
  394. // the tm.tmInternalLeading.
  395. CLock lock;
  396. HDC hdc = W32->GetScreenDC();
  397. HFONT hOldFont = SelectFont(hdc, hfont);
  398. TEXTMETRIC tm;
  399. if(hOldFont)
  400. {
  401. if(GetTextMetrics(hdc, &tm))
  402. _yHeight -= (tm.tmInternalLeading * LY_PER_INCH) / W32->GetYPerInchScreenDC();
  403. SelectFont(hdc, hOldFont);
  404. }
  405. }
  406. #ifndef MACPORTStyle
  407. _dwEffects = (CFM_EFFECTS | CFE_AUTOBACKCOLOR) & ~(CFE_PROTECTED | CFE_LINK);
  408. #else
  409. _dwEffects = (CFM_EFFECTS | CFE_AUTOBACKCOLOR | CFE_OUTLINE | CFE_SHADOW)
  410. & ~(CFE_PROTECTED | CFE_LINK);
  411. if(!(lf.lfWeight & FW_OUTLINE))
  412. _dwEffects &= ~CFE_OUTLINE;
  413. if (!(lf.lfWeight & FW_SHADOW))
  414. _dwEffects &= ~CFE_SHADOW;
  415. #endif
  416. if(lf.lfWeight < FW_BOLD)
  417. _dwEffects &= ~CFE_BOLD;
  418. if(!lf.lfItalic)
  419. _dwEffects &= ~CFE_ITALIC;
  420. if(!lf.lfUnderline)
  421. _dwEffects &= ~CFE_UNDERLINE;
  422. if(!lf.lfStrikeOut)
  423. _dwEffects &= ~CFE_STRIKEOUT;
  424. _wWeight = (WORD)lf.lfWeight;
  425. _lcid = GetSystemDefaultLCID();
  426. _bCharSet = lf.lfCharSet;
  427. _bPitchAndFamily= lf.lfPitchAndFamily;
  428. _iFont = GetFontNameIndex(lf.lfFaceName);
  429. _bUnderlineType = CFU_UNDERLINE; // Default solid underlines
  430. // Are gated by CFE_UNDERLINE
  431. // Qualify the charformat produced by incoming hfont before exit.
  432. // We did this to make sure that the charformat we derived from hfont is usable
  433. // since caller can send us bad font like given facename can't handle given charset.
  434. if (!fUseStockFont)
  435. {
  436. DWORD dwFontSig;
  437. if (GetFontSignatureFromFace(_iFont, &dwFontSig) &&
  438. !(GetFontSig(_bCharSet) & dwFontSig))
  439. _bCharSet = GetFirstAvailCharSet(dwFontSig);
  440. }
  441. return NOERROR;
  442. }
  443. /*
  444. * CCharFormat::Set(pCF, CodePage)
  445. *
  446. * @mfunc
  447. * Copy the CHARFORMAT or CHARFORMAT2 *<p pCF> to this CCharFormat
  448. */
  449. void CCharFormat::Set (
  450. const CHARFORMAT2 *pCF2, //@parm CHARFORMAT to copy to this CCharFormat
  451. UINT CodePage)
  452. {
  453. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormat::Set");
  454. _dwEffects = pCF2->dwEffects;
  455. _bCharSet = pCF2->bCharSet;
  456. _bPitchAndFamily = pCF2->bPitchAndFamily;
  457. if(pCF2->dwMask & CFM_FACE)
  458. {
  459. AssertSz((CodePage != 1200) ^ IsValidCharFormatW(pCF2),
  460. "CCharFormat::Set: wrong codepage for CHARFORMAT");
  461. if(CodePage != 1200)
  462. {
  463. WCHAR sz[LF_FACESIZE + 1];
  464. UnicodeFromMbcs(sz, LF_FACESIZE, (char *)pCF2->szFaceName, LF_FACESIZE,
  465. CodePage);
  466. _iFont = GetFontNameIndex(sz);
  467. }
  468. else
  469. _iFont = GetFontNameIndex(pCF2->szFaceName);
  470. }
  471. _yHeight = Get16BitTwips(pCF2->yHeight);
  472. _yOffset = Get16BitTwips(pCF2->yOffset);
  473. _crTextColor = pCF2->crTextColor;
  474. UINT cb = pCF2->cbSize;
  475. if(cb == sizeof(CHARFORMATW) || cb == sizeof(CHARFORMATA))
  476. {
  477. _dwEffects |= CFE_AUTOBACKCOLOR;
  478. _bUnderlineType = CFU_UNDERLINE;
  479. ZeroMemory((LPBYTE)&_wWeight,
  480. sizeof(CCharFormat) - offsetof(CCharFormat, _wWeight));
  481. return;
  482. }
  483. char *pvoid = (char *)&pCF2->wWeight;
  484. if(pCF2->cbSize == sizeof(CHARFORMAT2A))
  485. pvoid -= sizeof(CHARFORMAT2W) - sizeof(CHARFORMAT2A);
  486. else
  487. Assert(pCF2->cbSize == sizeof(CHARFORMAT2));// Better be a CHARFORMAT2
  488. CopyMemory(&_wWeight, pvoid, 3*sizeof(DWORD));
  489. CopyMemory(&_sStyle, pvoid + 4*sizeof(DWORD), 2*sizeof(DWORD));
  490. }
  491. //------------------------- CParaFormat Class -----------------------------------
  492. /*
  493. * CParaFormat::AddTab(tbPos, tbAln, tbLdr)
  494. *
  495. * @mfunc
  496. * Add tabstop at position <p tbPos>, alignment type <p tbAln>, and
  497. * leader style <p tbLdr>
  498. *
  499. * @rdesc
  500. * (success) ? NOERROR : S_FALSE
  501. *
  502. * @devnote
  503. * Tab struct that overlays LONG in internal _rgxTabs is
  504. *
  505. * DWORD tabPos : 24;
  506. * DWORD tabType : 4;
  507. * DWORD tabLeader : 4;
  508. */
  509. HRESULT CParaFormat::AddTab (
  510. LONG tbPos, //@parm New tab position
  511. LONG tbAln, //@parm New tab alignment type
  512. LONG tbLdr, //@parm New tab leader style
  513. BOOL fInTable, //@parm True if simulating cells
  514. LONG * prgxTabs) //@parm Where the tabs are
  515. {
  516. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::AddTab");
  517. if (!fInTable &&
  518. ((DWORD)tbAln > tomAlignBar || // Validate arguments
  519. (DWORD)tbLdr > tomEquals || // Comparing DWORDs causes
  520. (DWORD)tbPos > 0xffffff || !tbPos)) // negative values to be
  521. { // treated as invalid
  522. return E_INVALIDARG;
  523. }
  524. LONG iTab;
  525. LONG tbValue = tbPos + (tbAln << 24) + (tbLdr << 28);
  526. for(iTab = 0; iTab < _bTabCount && // Determine where to
  527. tbPos > GetTabPos(prgxTabs[iTab]); // insert new tabstop
  528. iTab++) ;
  529. if(iTab >= MAX_TAB_STOPS)
  530. return S_FALSE;
  531. LONG tbPosCurrent = GetTabPos(prgxTabs[iTab]);
  532. if(iTab == _bTabCount || tbPosCurrent != tbPos)
  533. {
  534. if(_bTabCount >= MAX_TAB_STOPS)
  535. return S_FALSE;
  536. MoveMemory(&prgxTabs[iTab + 1], // Shift array down
  537. &prgxTabs[iTab], // (unless iTab = Count)
  538. (_bTabCount - iTab)*sizeof(LONG));
  539. _bTabCount++; // Increment tab count
  540. }
  541. prgxTabs[iTab] = tbValue;
  542. return NOERROR;
  543. }
  544. /*
  545. * CParaFormat::Apply(pPF)
  546. *
  547. * @mfunc
  548. * Apply *<p pPF> to this CParaFormat as specified by nonzero bits in
  549. * <p pPF>->dwMask
  550. */
  551. HRESULT CParaFormat::Apply (
  552. const CParaFormat *pPF, //@parm CParaFormat to apply to this PF
  553. DWORD dwMask) //@parm mask to use
  554. {
  555. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Apply");
  556. const DWORD dwMaskApply = dwMask;
  557. BOOL fPF = dwMask & PFM_PARAFORMAT;
  558. WORD wEffectMask;
  559. if(dwMaskApply & PFM_NUMBERING)
  560. _wNumbering = pPF->_wNumbering;
  561. if(dwMaskApply & PFM_OFFSET)
  562. {
  563. if (!IsValidTwip(pPF->_dxOffset))
  564. return E_INVALIDARG;
  565. _dxOffset = pPF->_dxOffset;
  566. }
  567. if(dwMaskApply & PFM_STARTINDENT)
  568. {
  569. if (!IsValidTwip(pPF->_dxStartIndent))
  570. return E_INVALIDARG;
  571. _dxStartIndent = pPF->_dxStartIndent;
  572. }
  573. else if(dwMaskApply & PFM_OFFSETINDENT)
  574. {
  575. if (!IsValidTwip(pPF->_dxStartIndent))
  576. return E_INVALIDARG;
  577. // bug fix #5761
  578. LONG dx = max(0, _dxStartIndent + pPF->_dxStartIndent);
  579. // Disallow shifts that move start of first or subsequent lines left of left margin.
  580. // Normally we just make indent zero in paraformat check below,
  581. // but in the case of bullet we want some space left.
  582. if(!_wNumbering || dx + _dxOffset >= 0)
  583. _dxStartIndent = dx;
  584. }
  585. if(dwMaskApply & PFM_RIGHTINDENT)
  586. {
  587. if (!IsValidTwip(pPF->_dxRightIndent))
  588. return E_INVALIDARG;
  589. _dxRightIndent = pPF->_dxRightIndent;
  590. }
  591. if(dwMaskApply & PFM_ALIGNMENT)
  592. {
  593. if(!fPF && !IN_RANGE(PFA_LEFT, pPF->_bAlignment, PFA_SNAP_GRID))
  594. {
  595. TRACEERRORSZ("CParaFormat::Apply: invalid Alignment ignored");
  596. return E_INVALIDARG;
  597. }
  598. if(pPF->_bAlignment <= PFA_SNAP_GRID)
  599. _bAlignment = pPF->_bAlignment;
  600. }
  601. // Save whether this is a table now.
  602. BOOL fInTablePrev = InTable();
  603. if((dwMaskApply & PFM_TABSTOPS) && !fInTablePrev)
  604. {
  605. _bTabCount = (BYTE)min(pPF->_bTabCount, MAX_TAB_STOPS);
  606. _bTabCount = (BYTE)max(_bTabCount, 0);
  607. _iTabs = pPF->_iTabs;
  608. AssertSz(!_bTabCount || _iTabs >= 0,
  609. "CParaFormat::Apply: illegal _iTabs value");
  610. }
  611. // AymanA: 11/7/96 Moved the wEffects set before the possible return NOERROR.
  612. wEffectMask = (WORD)(dwMaskApply >> 16); // Reset effect bits to be
  613. _wEffects &= ~wEffectMask; // modified and OR in
  614. _wEffects |= pPF->_wEffects & wEffectMask; // supplied values
  615. if(InTable())
  616. _wEffects &= ~PFE_RTLPARA; // Tables use paras for rows
  617. else if(fInTablePrev)
  618. {
  619. // This was a table now it isn't. We must dump the tab information
  620. // because it is totally bogus.
  621. _iTabs = -1;
  622. _bTabCount = 0;
  623. }
  624. if ((dwMaskApply & PFM_RTLPARA) && !(dwMaskApply & PFM_ALIGNMENT) &&
  625. _bAlignment != PFA_CENTER)
  626. {
  627. _bAlignment = IsRtlPara() ? PFA_RIGHT : PFA_LEFT;
  628. }
  629. // PARAFORMAT check
  630. if(fPF)
  631. {
  632. if(dwMaskApply & (PFM_STARTINDENT | PFM_OFFSET))
  633. {
  634. if(_dxStartIndent < 0) // Don't let indent go
  635. _dxStartIndent = 0; // negative
  636. if(_dxStartIndent + _dxOffset < 0) // Don't let indent +
  637. _dxOffset = -_dxStartIndent; // offset go negative
  638. }
  639. return NOERROR; // Nothing more for
  640. } // PARAFORMAT
  641. // PARAFORMAT2 extensions
  642. if(dwMaskApply & PFM_SPACEBEFORE)
  643. {
  644. _dySpaceBefore = 0;
  645. if (pPF->_dySpaceBefore > 0)
  646. _dySpaceBefore = pPF->_dySpaceBefore;
  647. }
  648. if(dwMaskApply & PFM_SPACEAFTER)
  649. {
  650. _dySpaceAfter = 0;
  651. if (pPF->_dySpaceAfter > 0)
  652. _dySpaceAfter = pPF->_dySpaceAfter;
  653. }
  654. if(dwMaskApply & PFM_LINESPACING)
  655. {
  656. _dyLineSpacing = pPF->_dyLineSpacing;
  657. _bLineSpacingRule = pPF->_bLineSpacingRule;
  658. }
  659. if(dwMaskApply & PFM_OUTLINELEVEL)
  660. _bOutlineLevel = pPF->_bOutlineLevel;
  661. if(dwMaskApply & PFM_STYLE)
  662. HandleStyle(pPF->_sStyle);
  663. Assert((_bOutlineLevel & 1) ^ IsHeadingStyle(_sStyle));
  664. if(dwMaskApply & PFM_SHADING)
  665. {
  666. _wShadingWeight = pPF->_wShadingWeight;
  667. _wShadingStyle = pPF->_wShadingStyle;
  668. }
  669. if(dwMaskApply & PFM_NUMBERINGSTART)
  670. _wNumberingStart = pPF->_wNumberingStart;
  671. if(dwMaskApply & PFM_NUMBERINGSTYLE)
  672. _wNumberingStyle = pPF->_wNumberingStyle;
  673. if(dwMaskApply & PFM_NUMBERINGTAB)
  674. _wNumberingTab = pPF->_wNumberingTab;
  675. if(dwMaskApply & PFM_BORDER)
  676. {
  677. _dwBorderColor = pPF->_dwBorderColor;
  678. _wBorders = pPF->_wBorders;
  679. _wBorderSpace = pPF->_wBorderSpace;
  680. _wBorderWidth = pPF->_wBorderWidth;
  681. }
  682. #ifdef DEBUG
  683. ValidateTabs();
  684. #endif // DEBUG
  685. return NOERROR;
  686. }
  687. /*
  688. * CParaFormat::ApplyDefaultStyle(Style)
  689. *
  690. * @mfunc
  691. * Copy default properties for Style
  692. */
  693. void CParaFormat::ApplyDefaultStyle (
  694. LONG Style) //@parm Style to apply
  695. {
  696. Assert(IsKnownStyle(Style));
  697. if(IsHeadingStyle(Style)) // Set Style's dySpaceBefore,
  698. { // dySpaceAfter (in twips)
  699. _dySpaceBefore = 12*20; // (same for all headings)
  700. _dySpaceAfter = 3*20;
  701. _wNumbering = 0; // No numbering
  702. }
  703. }
  704. /*
  705. * CParaFormat::DeleteTab(tbPos)
  706. *
  707. * @mfunc
  708. * Delete tabstop at position <p tbPos>
  709. *
  710. * @rdesc
  711. * (success) ? NOERROR : S_FALSE
  712. */
  713. HRESULT CParaFormat::DeleteTab (
  714. LONG tbPos, //@parm Tab position to delete
  715. LONG * prgxTabs) //@parm Tab array to use
  716. {
  717. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::DeleteTab");
  718. if(tbPos <= 0)
  719. return E_INVALIDARG;
  720. LONG Count = _bTabCount;
  721. for(LONG iTab = 0; iTab < Count; iTab++) // Find tabstop for position
  722. {
  723. if(GetTabPos(prgxTabs[iTab]) == tbPos)
  724. {
  725. MoveMemory(&prgxTabs[iTab], // Shift array down
  726. &prgxTabs[iTab + 1], // (unless iTab is last tab)
  727. (Count - iTab - 1)*sizeof(LONG));
  728. _bTabCount--; // Decrement tab count and
  729. return NOERROR; // signal no error
  730. }
  731. }
  732. return S_FALSE;
  733. }
  734. /*
  735. * CParaFormat::Delta(pPF)
  736. *
  737. * @mfunc
  738. * return mask of differences between this CParaFormat and *<p pPF>.
  739. * 1-bits indicate corresponding parameters differ; 0 indicates they
  740. * are the same
  741. *
  742. * @rdesc
  743. * mask of differences between this CParaFormat and *<p pPF>
  744. */
  745. DWORD CParaFormat::Delta (
  746. CParaFormat *pPF, //@parm CParaFormat to compare this
  747. BOOL fPARAFORMAT) const // CParaFormat to
  748. {
  749. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Delta");
  750. LONG dwT = 0; // No differences yet
  751. if(_wNumbering != pPF->_wNumbering)
  752. dwT |= PFM_NUMBERING; // _wNumbering values differ
  753. if(_dxStartIndent != pPF->_dxStartIndent)
  754. dwT |= PFM_STARTINDENT; // ...
  755. if(_dxRightIndent != pPF->_dxRightIndent)
  756. dwT |= PFM_RIGHTINDENT;
  757. if(_dxOffset != pPF->_dxOffset)
  758. dwT |= PFM_OFFSET;
  759. if(_bAlignment != pPF->_bAlignment)
  760. dwT |= PFM_ALIGNMENT;
  761. AssertSz(pPF->_bTabCount >= 0 && pPF->_bTabCount <= MAX_TAB_STOPS,
  762. "RTR::GetParaFormat(): illegal tab count");
  763. if (_bTabCount != pPF->_bTabCount)
  764. dwT |= PFM_TABSTOPS;
  765. else if (_bTabCount > 0)
  766. {
  767. const LONG *pTabs1 = GetTabs();
  768. const LONG *pTabs2 = pPF->GetTabs();
  769. if (pTabs1 != pTabs2 &&
  770. (pTabs1 == 0 || pTabs2 == 0 || CompareMemory(pTabs1, pTabs2, _bTabCount * sizeof(LONG))))
  771. dwT |= PFM_TABSTOPS;
  772. }
  773. dwT |= (_wEffects ^ pPF->_wEffects) << 16;
  774. if(!fPARAFORMAT)
  775. {
  776. if(_dySpaceBefore != pPF->_dySpaceBefore)
  777. dwT |= PFM_SPACEBEFORE;
  778. if(_dySpaceAfter != pPF->_dySpaceAfter)
  779. dwT |= PFM_SPACEAFTER;
  780. if (_dyLineSpacing != pPF->_dyLineSpacing ||
  781. _bLineSpacingRule!= pPF->_bLineSpacingRule)
  782. {
  783. dwT |= PFM_LINESPACING;
  784. }
  785. if(_sStyle != pPF->_sStyle)
  786. dwT |= PFM_STYLE;
  787. if (_wShadingWeight != pPF->_wShadingWeight ||
  788. _wShadingStyle != pPF->_wShadingStyle)
  789. {
  790. dwT |= PFM_SHADING;
  791. }
  792. if(_wNumberingStart != pPF->_wNumberingStart)
  793. dwT |= PFM_NUMBERINGSTART;
  794. if(_wNumberingStyle != pPF->_wNumberingStyle)
  795. dwT |= PFM_NUMBERINGSTYLE;
  796. if(_wNumberingTab != pPF->_wNumberingTab)
  797. dwT |= PFM_NUMBERINGTAB;
  798. if (_wBorders != pPF->_wBorders ||
  799. _wBorderWidth != pPF->_wBorderWidth ||
  800. _wBorderSpace != pPF->_wBorderSpace ||
  801. _dwBorderColor != pPF->_dwBorderColor)
  802. {
  803. dwT |= PFM_BORDER;
  804. }
  805. }
  806. return dwT;
  807. }
  808. #define PFM_IGNORE (PFM_OUTLINELEVEL | PFM_COLLAPSED | PFM_PARAFORMAT | PFM_BOX)
  809. /*
  810. * CParaFormat::fSetStyle()
  811. *
  812. * @mfunc
  813. * Return TRUE iff this PF specifies that the style should be set.
  814. * See code for list of conditions for this to be true
  815. *
  816. * @rdesc
  817. * TRUE iff pCF specifies that the style _sStyle should be set
  818. */
  819. BOOL CParaFormat::fSetStyle(DWORD dwMask) const
  820. {
  821. return (dwMask & ~PFM_IGNORE) != PFM_ALL2 &&
  822. dwMask & PFM_STYLE &&
  823. !(dwMask & PFM_PARAFORMAT) &&
  824. IsKnownStyle(_sStyle);
  825. }
  826. /*
  827. * CParaFormat::Get(pPF)
  828. *
  829. * @mfunc
  830. * Copy this CParaFormat to *<p pPF>
  831. */
  832. void CParaFormat::Get (
  833. PARAFORMAT2 *pPF2) const //@parm PARAFORMAT2 to copy this CParaFormat to
  834. {
  835. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Get");
  836. LONG cb = pPF2->cbSize;
  837. pPF2->dwMask = PFM_ALL2; // Default PARAFORMAT2
  838. if(cb != sizeof(PARAFORMAT2)) // It isn't
  839. {
  840. pPF2->dwMask = PFM_ALL; // Make it PARAFORMAT
  841. Assert(cb == sizeof(PARAFORMAT)); // It better be a PARAFORMAT
  842. }
  843. CopyMemory(&pPF2->wNumbering, &_wNumbering, (char *)&_bAlignment - (char *)&_wNumbering);
  844. pPF2->wAlignment = _bAlignment;
  845. pPF2->cTabCount = _bTabCount;
  846. LONG cb1 = _bTabCount*sizeof(LONG);
  847. if(_bTabCount)
  848. {
  849. AssertSz(_iTabs >= 0,
  850. "CParaFormat::Get: illegal _iTabs value");
  851. CopyMemory(pPF2->rgxTabs, GetTabsCache()->Deref(_iTabs), cb1);
  852. }
  853. ZeroMemory(pPF2->rgxTabs + _bTabCount, MAX_TAB_STOPS*sizeof(LONG) - cb1);
  854. CopyMemory(&pPF2->dySpaceBefore, &_dySpaceBefore,
  855. cb - offsetof(PARAFORMAT2, dySpaceBefore));
  856. }
  857. /*
  858. * CParaFormat::GetTab (iTab, ptbPos, ptbAln, ptbLdr)
  859. *
  860. * @mfunc
  861. * Get tab parameters for the <p iTab> th tab, that is, set *<p ptbPos>,
  862. * *<p ptbAln>, and *<p ptbLdr> equal to the <p iTab> th tab's
  863. * displacement, alignment type, and leader style, respectively. The
  864. * displacement is given in twips.
  865. *
  866. * @rdesc
  867. * HRESULT = (no <p iTab> tab) ? E_INVALIDARG : NOERROR
  868. */
  869. HRESULT CParaFormat::GetTab (
  870. long iTab, //@parm Index of tab to retrieve info for
  871. long * ptbPos, //@parm Out parm to receive tab displacement
  872. long * ptbAln, //@parm Out parm to receive tab alignment type
  873. long * ptbLdr, //@parm Out parm to receive tab leader style
  874. const LONG *prgxTabs) const //@parm Tab array
  875. {
  876. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEEXTERN, "CParaFormat::GetTab");
  877. AssertSz(ptbPos && ptbAln && ptbLdr,
  878. "CParaFormat::GetTab: illegal arguments");
  879. if(iTab < 0) // Get tab previous to, at,
  880. { // or subsequent to the
  881. if(iTab < tomTabBack) // position *ptbPos
  882. return E_INVALIDARG;
  883. LONG i;
  884. LONG tbPos = *ptbPos;
  885. LONG tbPosi;
  886. *ptbPos = 0; // Default tab not found
  887. for(i = 0; i < _bTabCount && // Find *ptbPos
  888. tbPos > GetTabPos(prgxTabs[i]);
  889. i++) ;
  890. tbPosi = GetTabPos(prgxTabs[i]); // tbPos <= tbPosi
  891. if(iTab == tomTabBack) // Get tab info for tab
  892. i--; // previous to tbPos
  893. else if(iTab == tomTabNext) // Get tab info for tab
  894. { // following tbPos
  895. if(tbPos == tbPosi)
  896. i++;
  897. }
  898. else if(tbPos != tbPosi) // tomTabHere
  899. return S_FALSE;
  900. iTab = i;
  901. }
  902. if((DWORD)iTab >= (DWORD)_bTabCount) // DWORD cast also
  903. return E_INVALIDARG; // catches values < 0
  904. iTab = prgxTabs[iTab];
  905. *ptbPos = GetTabPos(iTab);
  906. *ptbAln = GetTabAlign(iTab);
  907. *ptbLdr = GetTabLdr(iTab);
  908. return NOERROR;
  909. }
  910. /*
  911. * CParaFormat::GetTabs ()
  912. *
  913. * @mfunc
  914. * Get ptr to tab array. Use GetTabPos(), GetTabAlign(), and
  915. * GetTabLdr() to access the tab position, alignment, and leader
  916. * type, respectively.
  917. *
  918. * @rdesc
  919. * Ptr to tab array.
  920. */
  921. const LONG * CParaFormat::GetTabs () const
  922. {
  923. return GetTabsCache()->Deref(_iTabs);
  924. }
  925. /*
  926. * CParaFormat::HandleStyle(Style)
  927. *
  928. * @func
  929. * If Style is a promote/demote command, i.e., if abs((char)Style)
  930. * <= # heading styles - 1, add (char)Style to sStyle (if heading)
  931. * and to bOutlineLevel (subject to defined max and min values);
  932. * else sStyle = Style.
  933. *
  934. * @rdesc
  935. * return TRUE iff sStyle or bOutlineLevel changed
  936. *
  937. * @devnote
  938. * Heading styles are -2 (heading 1) through -10 (heading 9), which
  939. * with TOM and WOM. Heading outline levels are 0, 2,..., 16,
  940. * corresponding to headings 1 through 9 (NHSTYLES), respectively,
  941. * while text that follows has outline levels 1, 3,..., 17. This value
  942. * is used for indentation. Collapsed text has the PFE_COLLAPSED bit set.
  943. */
  944. BOOL CParaFormat::HandleStyle(
  945. LONG Style) //@parm Style, promote/demote code, or collapse-level code
  946. {
  947. if(IsStyleCommand(Style)) // Set collapse level
  948. {
  949. WORD wEffectsSave = _wEffects;
  950. Style = (char)Style; // Sign extend low byte
  951. if(IN_RANGE(1, Style, NHSTYLES))
  952. {
  953. _wEffects &= ~PFE_COLLAPSED;
  954. if((_bOutlineLevel & 1) || _bOutlineLevel > 2*(Style - 1))
  955. _wEffects |= PFE_COLLAPSED; // Collapse nonheadings and
  956. } // higher numbered headings
  957. else if(Style == -1)
  958. _wEffects &= ~PFE_COLLAPSED; // Expand all
  959. return _wEffects != wEffectsSave; // Return whether something
  960. } // changed
  961. // Ordinary Style specification
  962. BYTE bLevel = _bOutlineLevel;
  963. _bOutlineLevel |= 1; // Default not a heading
  964. if(IsHeadingStyle(Style)) // Headings have levels
  965. { // 0, 2,..., 16, while the
  966. _bOutlineLevel = -2*(Style // text that follows has
  967. - STYLE_HEADING_1); // 1, 3,..., 17.
  968. }
  969. if(_sStyle == Style && bLevel == _bOutlineLevel)
  970. return FALSE; // No change
  971. _sStyle = (SHORT)Style;
  972. return TRUE;
  973. }
  974. /*
  975. * CParaFormat::InitDefault(wDefEffects)
  976. *
  977. * @mfunc
  978. * Initialize this CParaFormat with default paragraph formatting
  979. *
  980. * @rdesc
  981. * HRESULT = (if success) ? NOERROR : E_FAIL
  982. */
  983. HRESULT CParaFormat::InitDefault(
  984. WORD wDefEffects)
  985. {
  986. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::InitDefault");
  987. ZeroMemory(this, sizeof(CParaFormat));
  988. _bAlignment = PFA_LEFT;
  989. _sStyle = STYLE_NORMAL; // Default style
  990. _wEffects = wDefEffects;
  991. _bOutlineLevel = 1; // Default highest text outline
  992. _iTabs = -1; // level
  993. #if lDefaultTab <= 0
  994. #error "default tab (lDefaultTab) must be > 0"
  995. #endif
  996. return NOERROR;
  997. }
  998. /*
  999. * CParaFormat::NumToStr(pch, n)
  1000. *
  1001. * @mfunc
  1002. * Convert the list number n to a string taking into consideration
  1003. * CParaFormat::wNumbering, wNumberingStart, and wNumberingStyle
  1004. *
  1005. * @rdesc
  1006. * cch of string converted
  1007. */
  1008. LONG CParaFormat::NumToStr(
  1009. TCHAR * pch, //@parm Target string
  1010. LONG n, //@parm Number + 1 to convert
  1011. DWORD grf) const //@parm Collection of flags
  1012. {
  1013. if(IsNumberSuppressed())
  1014. {
  1015. *pch = 0;
  1016. return 0; // Number/bullet suppressed
  1017. }
  1018. if(!n) // Bullet of some kind
  1019. { // CParaFormat::wNumbering
  1020. *pch++ = (_wNumbering > ' ') // values > ' ' are Unicode
  1021. ? _wNumbering : 0x00B7; // bullets. Else use bullet
  1022. return 1; // in symbol font
  1023. }
  1024. // Numbering of some kind
  1025. // i ii iii iv v vi vii viii ix
  1026. const BYTE RomanCode[] = {1, 5, 0x15, 9, 2, 6, 0x16, 0x56, 0xd};
  1027. const char RomanLetter[] = "ivxlcdmno";
  1028. BOOL fRtlPara = IsRtlPara() && !(grf & fRtfWrite);
  1029. LONG RomanOffset = 0;
  1030. LONG cch = 0; // No chars yet
  1031. WCHAR ch = fRtlPara && (grf & fIndicDigits) ? 0x0660 : '0';
  1032. // Default char code offset
  1033. LONG d = 1; // Divisor
  1034. LONG r = 10; // Default radix
  1035. LONG quot, rem; // ldiv result
  1036. LONG Style = (_wNumberingStyle << 8) & 0xF0000;
  1037. n--; // Convert to number offset
  1038. if(Style == tomListParentheses || // Numbering like: (x)
  1039. fRtlPara && Style == 0) // or 1) in bidi text.
  1040. {
  1041. cch = 1; // Store leading lparen
  1042. *pch++ = '(';
  1043. }
  1044. else if (Style == tomListPeriod && fRtlPara)
  1045. {
  1046. cch = 1;
  1047. *pch++ = '.';
  1048. Style = tomListPlain;
  1049. }
  1050. if(_wNumbering == tomListNumberAsSequence)
  1051. ch = _wNumberingStart; // Needs generalizations, e.g.,
  1052. // appropriate radix
  1053. else
  1054. {
  1055. n += _wNumberingStart;
  1056. if(IN_RANGE(tomListNumberAsLCLetter, _wNumbering, tomListNumberAsUCLetter))
  1057. {
  1058. ch = (_wNumbering == tomListNumberAsLCLetter) ? 'a' : 'A';
  1059. if(_wNumberingStart >= 1)
  1060. n--;
  1061. r = 26; // LC or UC alphabetic number
  1062. } // Radix 26
  1063. }
  1064. while(d < n)
  1065. {
  1066. d *= r; // d = smallest power of r > n
  1067. RomanOffset += 2;
  1068. }
  1069. if(n && d > n)
  1070. {
  1071. d /= r;
  1072. RomanOffset -= 2;
  1073. }
  1074. while(d)
  1075. {
  1076. quot = n / d;
  1077. rem = n % d;
  1078. if(IN_RANGE(tomListNumberAsLCRoman, _wNumbering, tomListNumberAsUCRoman))
  1079. {
  1080. if(quot)
  1081. {
  1082. n = RomanCode[quot - 1];
  1083. while(n)
  1084. {
  1085. ch = RomanLetter[(n & 3) + RomanOffset - 1];
  1086. if(_wNumbering == tomListNumberAsUCRoman)
  1087. ch &= 0x5F;
  1088. *pch++ = ch;
  1089. n >>= 2;
  1090. cch++;
  1091. }
  1092. }
  1093. RomanOffset -= 2;
  1094. }
  1095. else
  1096. {
  1097. n = quot + ch;
  1098. if(r == 26 && d > 1) // If alphabetic higher-order
  1099. n--; // digit, base it on 'a' or 'A'
  1100. *pch++ = (WORD)n; // Store digit
  1101. cch++;
  1102. }
  1103. n = rem; // Setup remainder
  1104. d /= r;
  1105. }
  1106. if (Style != tomListPlain && // Trailing text
  1107. (!fRtlPara || Style))
  1108. { // We only do rparen or period
  1109. *pch++ = (Style == tomListPeriod) ? '.' : ')';
  1110. cch++;
  1111. }
  1112. *pch = 0; // Null terminate for RTF writer
  1113. return cch;
  1114. }
  1115. /*
  1116. * CParaFormat::Set(pPF)
  1117. *
  1118. * @mfunc
  1119. * Copy PARAFORMAT or PARAFORMAT2 *<p pPF> to this CParaFormat
  1120. */
  1121. void CParaFormat::Set (
  1122. const PARAFORMAT2 *pPF2) //@parm PARAFORMAT to copy to this CParaFormat
  1123. {
  1124. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::Set");
  1125. CopyMemory(&_wNumbering, &pPF2->wNumbering,
  1126. (char *)&_bAlignment - (char *)&_wNumbering);
  1127. _bAlignment = (BYTE)pPF2->wAlignment;
  1128. _iTabs = -1;
  1129. _bTabCount = 0;
  1130. if((pPF2->dwMask & PFM_TABSTOPS) && pPF2->cTabCount)
  1131. {
  1132. _bTabCount = (BYTE)min(MAX_TAB_STOPS, (BYTE)pPF2->cTabCount);
  1133. _iTabs = GetTabsCache()->Cache(pPF2->rgxTabs, _bTabCount);
  1134. }
  1135. if(pPF2->dwMask & ~(PFM_ALL | PFM_PARAFORMAT))
  1136. {
  1137. CopyMemory(&_dySpaceBefore, &pPF2->dySpaceBefore,
  1138. sizeof(CParaFormat) - offsetof(CParaFormat, _dySpaceBefore));
  1139. }
  1140. #ifdef DEBUG
  1141. ValidateTabs();
  1142. #endif // DEBUG
  1143. }
  1144. /*
  1145. * CParaFormat::UpdateNumber(n, pPF)
  1146. *
  1147. * @mfunc
  1148. * Return new value of number for paragraph described by this PF
  1149. * following a paragraph described by pPF
  1150. *
  1151. * @rdesc
  1152. * New number for paragraph described by this PF
  1153. */
  1154. LONG CParaFormat::UpdateNumber (
  1155. LONG n, //@parm Current value of number
  1156. const CParaFormat *pPF) const //@parm Previous CParaFormat
  1157. {
  1158. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormat::UpdateNumber");
  1159. if(!IsListNumbered())
  1160. return 0; // No numbering
  1161. if(IsNumberSuppressed())
  1162. return n; // Number is suppressed, so no change
  1163. if (!pPF || _wNumbering != pPF->_wNumbering ||
  1164. (_wNumberingStyle != pPF->_wNumberingStyle && !pPF->IsNumberSuppressed()) ||
  1165. _wNumberingStart != pPF->_wNumberingStart)
  1166. { // Numbering type or style
  1167. return 1; // changed, so start over
  1168. }
  1169. return n + 1; // Same kind of numbering,
  1170. }
  1171. #ifdef DEBUG
  1172. /*
  1173. * CParaFormat::ValidateTabs()
  1174. *
  1175. * @mfunc
  1176. * Makes sure that a set of tabs would make sense for a non-table
  1177. * paragraph. Is called in places where we have set the tabs.
  1178. *
  1179. * @rdesc
  1180. * None.
  1181. */
  1182. void CParaFormat::ValidateTabs()
  1183. {
  1184. if (_wEffects & PFE_TABLE)
  1185. {
  1186. // It would be nice to assert something reasonable here. However, the
  1187. // rtf reader insists on setting things inconsistenly and I don't
  1188. // have time at the moment to figure out why. (a-rsail)
  1189. // AssertSz((_bTabCount != 0),
  1190. // "CParaFormat::ValidateTabs: table with invalid tab count ");
  1191. return;
  1192. }
  1193. // Non-table case.
  1194. // It would be nice to assert on the consistency between these _bTabCount and _iTabs
  1195. // but rtf reader has troubles with this.
  1196. // AssertSz(((_bTabCount != 0) && (-1 != _iTabs)) || ((-1 == _iTabs) && (0 == _bTabCount)),
  1197. // "CParaFormat::ValidateTabs: tab count and default tab index inconsistent");
  1198. if (-1 == _iTabs)
  1199. {
  1200. // No tabs to validate so we are done.
  1201. return;
  1202. }
  1203. const LONG *prgtabs = GetTabs();
  1204. AssertSz(prgtabs != NULL, "CParaFormat::ValidateTabs: missing tab table");
  1205. for (int i = 0; i < _bTabCount; i++)
  1206. {
  1207. AssertSz(GetTabAlign(prgtabs[i]) <= tomAlignBar,
  1208. "CParaFormat::ValidateTabs: Invalid tab being set");
  1209. }
  1210. }
  1211. #endif // DEBUG
  1212. //------------------------- Helper Functions -----------------------------------
  1213. // Defines and fixed font size details for increasing/decreasing font size
  1214. #define PWD_FONTSIZEPOINTMIN 1
  1215. // The following corresponds to the max signed 2-byte TWIP value, (32760)
  1216. #define PWD_FONTSIZEPOINTMAX 1638
  1217. typedef struct tagfsFixup
  1218. {
  1219. BYTE EndValue;
  1220. BYTE Delta;
  1221. }
  1222. FSFIXUP;
  1223. const FSFIXUP fsFixups[] =
  1224. {
  1225. 12, 1,
  1226. 28, 2,
  1227. 36, 0,
  1228. 48, 0,
  1229. 72, 0,
  1230. 80, 0,
  1231. 0, 10 // EndValue = 0 case is treated as "infinite"
  1232. };
  1233. #define PWD_FONTSIZEMAXFIXUPS (sizeof(fsFixups)/sizeof(fsFixups[0]))
  1234. /*
  1235. * GetUsableFontHeight(ySrcHeight, lPointChange)
  1236. *
  1237. * @func
  1238. * Return a font size for setting text or insertion point attributes
  1239. *
  1240. * @rdesc
  1241. * New TWIPS height
  1242. *
  1243. * @devnote
  1244. * Copied from WinCE RichEdit code (written by V-GUYB)
  1245. */
  1246. LONG GetUsableFontHeight(
  1247. LONG ySrcHeight, //@parm Current font size in twips
  1248. LONG lPointChange) //@parm Increase in pt size, (-ve if shrinking)
  1249. {
  1250. LONG EndValue;
  1251. LONG Delta;
  1252. int i;
  1253. LONG yRetHeight;
  1254. // Input height in twips here, (TWentIeths of a Point).
  1255. // Note, a Point is a 1/72th of an inch. To make these
  1256. // calculations clearer, use point sizes here. Input height
  1257. // in twips is always divisible by 20 (NOTE (MS3): maybe with
  1258. // a truncation, since RTF uses half-point units).
  1259. yRetHeight = (ySrcHeight / 20) + lPointChange;
  1260. // Fix new font size to match sizes used by Word95
  1261. for(i = 0; i < PWD_FONTSIZEMAXFIXUPS; ++i)
  1262. {
  1263. EndValue = fsFixups[i].EndValue;
  1264. Delta = fsFixups[i].Delta;
  1265. // Does new height lie in this range of point sizes?
  1266. if(yRetHeight <= EndValue || !EndValue)
  1267. {
  1268. // If new height = EndValue, then it doesn't need adjusting
  1269. if(yRetHeight != EndValue)
  1270. {
  1271. // Adjust new height to fit this range of point sizes. If
  1272. // Delta = 1, all point sizes in this range stay as they are.
  1273. if(!Delta)
  1274. {
  1275. // Everything in this range is rounded to the EndValue
  1276. yRetHeight = fsFixups[(lPointChange > 0 ?
  1277. i : max(i - 1, 0))].EndValue;
  1278. }
  1279. else if(Delta != 1)
  1280. {
  1281. // Round new height to next delta in this range
  1282. yRetHeight = ((yRetHeight +
  1283. (lPointChange > 0 ? Delta - 1 : 0))
  1284. / Delta) * Delta;
  1285. }
  1286. }
  1287. break;
  1288. }
  1289. }
  1290. // Limit the new text size. Note, if we fix the text size
  1291. // now, then we won't take any special action if we change
  1292. // the text size later in the other direction. For example,
  1293. // we shrink chars with size 1 and 2. They both change to
  1294. // size 1. Then we grow them both to 2. So they are the
  1295. // same size now, even though they weren't before. This
  1296. // matches Word95 behavior.
  1297. yRetHeight = max(yRetHeight, PWD_FONTSIZEPOINTMIN);
  1298. yRetHeight = min(yRetHeight, PWD_FONTSIZEPOINTMAX);
  1299. return yRetHeight*20; // Return value in twips
  1300. }
  1301. /*
  1302. * IsValidCharFormatW(pCF)
  1303. *
  1304. * @func
  1305. * Return TRUE iff the structure *<p pCF> has the correct size to be
  1306. * a CHARFORMAT or a CHARFORMAT2
  1307. *
  1308. * @rdesc
  1309. * Return TRUE if *<p pCF> is a valid CHARFORMAT(2)
  1310. */
  1311. BOOL IsValidCharFormatW (
  1312. const CHARFORMAT * pCF) //@parm CHARFORMAT to validate
  1313. {
  1314. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidCharFormat");
  1315. return pCF && (pCF->cbSize == sizeof(CHARFORMATW) ||
  1316. pCF->cbSize == sizeof(CHARFORMAT2W));
  1317. }
  1318. /*
  1319. * IsValidCharFormatA(pCFA)
  1320. *
  1321. * @func
  1322. * Return TRUE iff the structure *<p pCF> has the correct size to be
  1323. * a CHARFORMATA or a CHARFORMAT2A
  1324. *
  1325. * @rdesc
  1326. * Return TRUE if *<p pCF> is a valid CHARFORMAT(2)A
  1327. */
  1328. BOOL IsValidCharFormatA (
  1329. const CHARFORMATA * pCFA) //@parm CHARFORMATA to validate
  1330. {
  1331. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidCharFormatA");
  1332. return pCFA && (pCFA->cbSize == sizeof(CHARFORMATA) ||
  1333. pCFA->cbSize == sizeof(CHARFORMAT2A));
  1334. }
  1335. /*
  1336. * IsValidParaFormat(pPF)
  1337. *
  1338. * @func
  1339. * Return TRUE iff the structure *<p pPF> has the correct size to be
  1340. * a PARAFORMAT or a PARAFORMAT2
  1341. *
  1342. * @rdesc
  1343. * Return TRUE if *<p pPF> is a valid PARAFORMAT(2)
  1344. */
  1345. BOOL IsValidParaFormat (
  1346. const PARAFORMAT * pPF) //@parm PARAFORMAT to validate
  1347. {
  1348. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "IsValidParaFormat");
  1349. if (pPF && (pPF->cbSize == sizeof(PARAFORMAT) ||
  1350. pPF->cbSize == sizeof(PARAFORMAT2)))
  1351. {
  1352. return TRUE;
  1353. }
  1354. TRACEERRORSZ("!!!!!!!!!!! bogus PARAFORMAT from client !!!!!!!!!!!!!");
  1355. return FALSE;
  1356. }
  1357. /*
  1358. * Get16BitTwips(dy)
  1359. *
  1360. * @func
  1361. * Return dy if |dy| < 32768; else return 32767, i.e., max value
  1362. * that fits into a SHORT
  1363. *
  1364. * @rdesc
  1365. * dy if abs(cy) < 32768; else 32767
  1366. */
  1367. SHORT Get16BitTwips(LONG dy)
  1368. {
  1369. return abs(dy) < 32768 ? (SHORT)dy : 32767;
  1370. }