Source code of Windows XP (NT5)
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.

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