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.

1416 lines
40 KiB

  1. #include "lsmem.h"
  2. #include "limits.h"
  3. #include "ruby.h"
  4. #include "objhelp.h"
  5. #include "lscbk.h"
  6. #include "lsdevres.h"
  7. #include "pdobj.h"
  8. #include "objdim.h"
  9. #include "plssubl.h"
  10. #include "plsdnode.h"
  11. #include "pilsobj.h"
  12. #include "lscrsubl.h"
  13. #include "lssubset.h"
  14. #include "lsdnset.h"
  15. #include "zqfromza.h"
  16. #include "lsdocinf.h"
  17. #include "fmti.h"
  18. #include "posichnk.h"
  19. #include "locchnk.h"
  20. #include "lsdnfin.h"
  21. #include "brko.h"
  22. #include "lspap.h"
  23. #include "plspap.h"
  24. #include "lsqsubl.h"
  25. #include "dispi.h"
  26. #include "lsdssubl.h"
  27. #include "lsems.h"
  28. #include "dispmisc.h"
  29. #include "lstfset.h"
  30. #include "lsqout.h"
  31. #include "lsqin.h"
  32. #include "sobjhelp.h"
  33. #include "brkkind.h"
  34. #define RUBY_MAIN_ESC_CNT 1
  35. #define RUBY_RUBY_ESC_CNT 1
  36. struct ilsobj
  37. {
  38. POLS pols;
  39. LSCBK lscbk;
  40. PLSC plsc;
  41. LSDEVRES lsdevres;
  42. RUBYSYNTAX rubysyntax;
  43. LSESC lsescMain;
  44. LSESC lsescRuby;
  45. RUBYCBK rcbk; /* Callbacks to client application */
  46. };
  47. typedef struct SUBLINEDNODES
  48. {
  49. PLSDNODE plsdnStart;
  50. PLSDNODE plsdnEnd;
  51. } SUBLINEDNODES, *PSUBLINEDNODES;
  52. struct dobj
  53. {
  54. SOBJHELP sobjhelp; /* common area for simple objects */
  55. PILSOBJ pilsobj; /* ILS object */
  56. PLSDNODE plsdn; /* DNODE for this object */
  57. LSCP cpStart; /* Starting LS cp for object */
  58. LSTFLOW lstflow; /* text flow for the Ruby object */
  59. PLSRUN plsrunFirstRubyChar;/* plsrun for first Ruby line char */
  60. PLSRUN plsrunLastRubyChar; /* plsrun for last Ruby line char */
  61. LSCP cpStartRuby; /* first cp of the ruby line */
  62. LSCP cpStartMain; /* first cp of the main line */
  63. PLSSUBL plssublMain; /* Handle to first subline */
  64. OBJDIM objdimMain; /* Objdim of first subline */
  65. PLSSUBL plssublRuby; /* Handle to second line */
  66. OBJDIM objdimRuby; /* Objdim of second line */
  67. long dvpMainOffset; /* Offset of main line's baseline */
  68. /* from baseline ofRuby object. */
  69. long dvpRubyOffset; /* Offset of Ruby line's baseline */
  70. /* from baseline of Ruby object. */
  71. long dvrRubyOffset; /* Offset of Ruby line's baseline */
  72. /* from baseline of Ruby object in reference units. */
  73. enum rubycharjust rubycharjust; /* Type of centering */
  74. long durSplWidthMod; /* special Ruby width mod if special behavior
  75. * when Ruby is on the end of the line */
  76. BOOL fFirstOnLine:1; /* TRUE = object is first on line */
  77. BOOL fSpecialLineStartEnd:1;/* Special Begin of Line or End of */
  78. /* Line behavior. */
  79. BOOL fModAfterCalled:1; /* Whether mod width after has been called */
  80. long durDiff; /* Amount of overhang of ruby line if */
  81. /* ruby line is longer, otherwise amount */
  82. /* of underhang if main text is longer. */
  83. long durModBefore; /* Mod width distance before */
  84. long dupOffsetMain; /* Offset from start of object of main line. */
  85. long dupOffsetRuby; /* Offset from start of object of ruby line. */
  86. SUBLINEDNODES sublnlsdnMain; /* Start end dnodes of main line */
  87. SUBLINEDNODES sublnlsdnRuby; /* Start end dnodes of ruby line */
  88. };
  89. /* F R E E D O B J */
  90. /*----------------------------------------------------------------------------
  91. %%Function: RubyFreeDobj
  92. %%Contact: antons
  93. Free all resources associated with this Ruby dobj.
  94. ----------------------------------------------------------------------------*/
  95. static LSERR RubyFreeDobj (PDOBJ pdobj)
  96. {
  97. LSERR lserr1 = lserrNone;
  98. LSERR lserr2 = lserrNone;
  99. PILSOBJ pilsobj = pdobj->pilsobj;
  100. if (pdobj->plssublMain != NULL)
  101. {
  102. lserr1 = LsDestroySubline(pdobj->plssublMain);
  103. }
  104. if (pdobj->plssublRuby != NULL)
  105. {
  106. lserr2 = LsDestroySubline(pdobj->plssublRuby);
  107. }
  108. pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pdobj);
  109. if (lserr1 != lserrNone)
  110. {
  111. return lserr1;
  112. }
  113. else
  114. {
  115. return lserr2;
  116. }
  117. }
  118. /* R U B Y F M T F A I L E D */
  119. /*----------------------------------------------------------------------------
  120. %%Function: RubyFmtFailed
  121. %%Contact: antons
  122. Could not create Ruby DOBJ due to error.
  123. IN: pdobj of partially created Ruby; NULL if pdobj was not yet allocated;
  124. IN: lserr from the last error
  125. ----------------------------------------------------------------------------*/
  126. static LSERR RubyFmtFailed (PDOBJ pdobj, LSERR lserr)
  127. {
  128. if (pdobj != NULL) RubyFreeDobj (pdobj); /* Works with parially-filled DOBJ */
  129. return lserr;
  130. }
  131. /* G E T R U N S F O R S U B L I N E */
  132. /*----------------------------------------------------------------------------
  133. %%Function: GetRunsForSubline
  134. %%Contact: ricksa
  135. This gets all the runs for a particular subline.
  136. ----------------------------------------------------------------------------*/
  137. static LSERR GetRunsForSubline(
  138. PILSOBJ pilsobj, /* (IN): object ILS */
  139. PLSSUBL plssubl, /* (IN): subline to get the runs from */
  140. DWORD *pcdwRuns, /* (OUT): count of runs for subline */
  141. PLSRUN **ppplsrun) /* (OUT): array of plsruns for subline */
  142. {
  143. DWORD cdwRuns;
  144. LSERR lserr = LssbGetNumberDnodesInSubline(plssubl, &cdwRuns);
  145. *ppplsrun = NULL; /* No runs or in case of error */
  146. if (lserr != lserrNone) return lserr;
  147. if (cdwRuns != 0)
  148. {
  149. *ppplsrun = (PLSRUN *) pilsobj->lscbk.pfnNewPtr(pilsobj->pols,
  150. sizeof(PLSRUN) * cdwRuns);
  151. if (*ppplsrun == NULL) return lserrOutOfMemory;
  152. lserr = LssbGetPlsrunsFromSubline(plssubl, cdwRuns, *ppplsrun);
  153. if (lserr != lserrNone)
  154. {
  155. pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, *ppplsrun);
  156. *ppplsrun = NULL;
  157. return lserr;
  158. }
  159. }
  160. *pcdwRuns = cdwRuns;
  161. return lserrNone;
  162. }
  163. /* D I S T R I B U T E T O L I N E */
  164. /*----------------------------------------------------------------------------
  165. %%Function: DistributeToLine
  166. %%Contact: ricksa
  167. Distribute space to line & get new size of line.
  168. ----------------------------------------------------------------------------*/
  169. static LSERR DistributeToLine(
  170. PLSC plsc, /* (IN): LS context */
  171. SUBLINEDNODES *psublnlsdn, /* (IN): start/end dnode for subline */
  172. long durToDistribute, /* (IN): amount to distribute*/
  173. PLSSUBL plssubl, /* (IN): subline for distribution */
  174. POBJDIM pobjdim) /* (OUT): new size of line dimesions */
  175. {
  176. LSERR lserr = LsdnDistribute(plsc, psublnlsdn->plsdnStart,
  177. psublnlsdn->plsdnEnd, durToDistribute);
  178. LSTFLOW lstflowUnused;
  179. if (lserrNone == lserr)
  180. {
  181. /* recalculate objdim for line */
  182. lserr = LssbGetObjDimSubline(plssubl, &lstflowUnused, pobjdim);
  183. }
  184. return lserr;
  185. }
  186. /* D O R U B Y S P A C E D I S T R I B U T I O N */
  187. /*----------------------------------------------------------------------------
  188. %%Function: DoRubySpaceDistribution
  189. %%Contact: ricksa
  190. Do the ruby space distribution to handle overhangs.
  191. ----------------------------------------------------------------------------*/
  192. static LSERR DoRubySpaceDistribution(
  193. PDOBJ pdobj)
  194. {
  195. long durDiff = 0;
  196. long dur = pdobj->objdimMain.dur - pdobj->objdimRuby.dur;
  197. long durAbs = dur;
  198. PLSSUBL plssubl;
  199. LSDCP dcp;
  200. PILSOBJ pilsobj = pdobj->pilsobj;
  201. LSERR lserr = lserrNone;
  202. SUBLINEDNODES *psublnlsdn;
  203. POBJDIM pobjdim;
  204. BOOL fSpecialJust;
  205. long durToDistribute;
  206. if ((0 == pdobj->objdimMain.dur)
  207. || (0 == pdobj->objdimRuby.dur)
  208. || (0 == dur))
  209. {
  210. /* Can't distribute space on a shorter line so we are done. */
  211. return lserrNone;
  212. }
  213. if (dur > 0)
  214. {
  215. /* Main line is longer - distibute in Ruby pronunciation line */
  216. /*
  217. * According to the JIS spec, special alignment only occurs when the
  218. * Ruby text is longer than the main text. Therefore, if the main
  219. * line is longer we turn of the special aligment flag here.
  220. */
  221. pdobj->fSpecialLineStartEnd = FALSE;
  222. plssubl = pdobj->plssublRuby;
  223. psublnlsdn = &pdobj->sublnlsdnRuby;
  224. pobjdim = &pdobj->objdimRuby;
  225. }
  226. else
  227. {
  228. /* Ruby pronunciation line is longer - distibute in main line */
  229. plssubl = pdobj->plssublMain;
  230. psublnlsdn = &pdobj->sublnlsdnMain;
  231. pobjdim = &pdobj->objdimMain;
  232. durAbs = -dur;
  233. }
  234. fSpecialJust = FALSE;
  235. // fSpecialJust =
  236. // pdobj->fSpecialLineStartEnd && pdobj->fFirstOnLine;
  237. if (!fSpecialJust)
  238. {
  239. switch (pdobj->rubycharjust)
  240. {
  241. case rcj121:
  242. lserr = LssbGetVisibleDcpInSubline(plssubl, &dcp);
  243. Assert (dcp > 0);
  244. if (lserr != lserrNone)
  245. {
  246. break;
  247. }
  248. dcp *= 2;
  249. if (durAbs >= (long) dcp)
  250. {
  251. durDiff = durAbs / dcp;
  252. /* Note: distribution amount is amount excluding
  253. * beginning and end.
  254. */
  255. lserr = DistributeToLine(pilsobj->plsc, psublnlsdn,
  256. durAbs - 2 * durDiff, plssubl, pobjdim);
  257. if (dur < 0)
  258. {
  259. durDiff = - durDiff;
  260. }
  261. break;
  262. }
  263. /*
  264. * Intention fall through in the case where the overhang will
  265. * be less than one pixel.
  266. */
  267. case rcj010:
  268. AssertSz(0 == durDiff,
  269. "DoRubySpaceDistribution rcj010 unexpected value for durDiff");
  270. lserr = LssbGetVisibleDcpInSubline(plssubl, &dcp);
  271. Assert (dcp > 0);
  272. if (lserr != lserrNone)
  273. {
  274. break;
  275. }
  276. if (dcp != 1)
  277. {
  278. lserr = DistributeToLine(pilsobj->plsc, psublnlsdn,
  279. durAbs, plssubl, pobjdim);
  280. break;
  281. }
  282. /*
  283. * Intentional fall through to center case.
  284. * Only one character in line so we just center it.
  285. */
  286. case rcjCenter:
  287. durDiff = dur / 2;
  288. break;
  289. case rcjLeft:
  290. durDiff = 0;
  291. break;
  292. case rcjRight:
  293. durDiff = dur;
  294. break;
  295. default:
  296. AssertSz(FALSE,
  297. "DoRubySpaceDistribution - invalid adjustment value");
  298. }
  299. }
  300. else
  301. {
  302. /* First on line & special justification used. */
  303. LSERR lserr = LssbGetVisibleDcpInSubline(plssubl, &dcp);
  304. Assert (dcp > 0);
  305. if (lserrNone == lserr)
  306. {
  307. if (durAbs >= (long) dcp)
  308. {
  309. durDiff = durAbs / dcp;
  310. }
  311. durToDistribute = durAbs - durDiff;
  312. if (dur < 0)
  313. {
  314. durDiff = -durDiff;
  315. }
  316. lserr = DistributeToLine(pilsobj->plsc, psublnlsdn,
  317. durToDistribute, plssubl, pobjdim);
  318. }
  319. }
  320. pdobj->durDiff = durDiff;
  321. return lserr;
  322. }
  323. /* G E T M A I N P O I N T */
  324. /*----------------------------------------------------------------------------
  325. %%Function: GetMainPoint
  326. %%Contact: ricksa
  327. This gets the point for the baseline of the main line of text in
  328. the Ruby object.
  329. ----------------------------------------------------------------------------*/
  330. static LSERR GetMainPoint(
  331. PDOBJ pdobj, /*(IN): dobj for Ruby */
  332. const POINT *pptBase, /*(IN): point for baseline. */
  333. LSTFLOW lstflow, /*(IN): lstflow at baseline of object */
  334. POINT *pptLine) /*(OUT): point for baseline of main text */
  335. {
  336. POINTUV pointuv;
  337. pointuv.u = pdobj->dupOffsetMain;
  338. pointuv.v = pdobj->dvpMainOffset;
  339. return LsPointXYFromPointUV(pptBase, lstflow, &pointuv, pptLine);
  340. }
  341. /* G E T M A I N P O I N T */
  342. /*----------------------------------------------------------------------------
  343. %%Function: GetMainPoint
  344. %%Contact: ricksa
  345. This gets the point for the baseline of the main line of text in
  346. the Ruby object.
  347. ----------------------------------------------------------------------------*/
  348. static LSERR GetRubyPoint(
  349. PDOBJ pdobj, /*(IN): dobj for Ruby */
  350. const POINT *pptBase, /*(IN): point for baseline. */
  351. LSTFLOW lstflow, /*(IN): lstflow at baseline of object */
  352. POINT *pptLine) /*(OUT): point for baseline of ruby text */
  353. {
  354. POINTUV pointuv;
  355. pointuv.u = pdobj->dupOffsetRuby;
  356. pointuv.v = pdobj->dvpRubyOffset;
  357. return LsPointXYFromPointUV(pptBase, lstflow, &pointuv, pptLine);
  358. }
  359. /* M O D W I D T H H A N D L E R */
  360. /*----------------------------------------------------------------------------
  361. %%Function: ModWidthHandler
  362. %%Contact: ricksa
  363. This gets the adjustment for the Ruby object and the text character
  364. and then adjusts the Ruby object's size based on the response from
  365. the client.
  366. ----------------------------------------------------------------------------*/
  367. static LSERR ModWidthHandler(
  368. PDOBJ pdobj, /* (IN): dobj for Ruby */
  369. enum rubycharloc rubyloc, /* (IN): whether char is before or after */
  370. PLSRUN plsrun, /* (IN): run for character */
  371. WCHAR wch, /* (IN): character before or after Ruby object */
  372. MWCLS mwcls, /* (IN): mod width class for for character */
  373. PCHEIGHTS pcheightsRef, /* (IN): height of character */
  374. PLSRUN plsrunRubyObject, /* (IN): plsrun for the ruby object */
  375. PLSRUN plsrunRubyText, /* (IN): plsrun for ruby text */
  376. long durOverhang, /* (IN): maximum amount of overhang */
  377. long *pdurAdjText, /* (OUT): amount to change text object size */
  378. long *pdurRubyMod) /* (OUT): amount to change ruby object */
  379. {
  380. LSERR lserr;
  381. PILSOBJ pilsobj = pdobj->pilsobj;
  382. LSEMS lsems;
  383. long durModRuby = 0;
  384. long durMaxOverhang = 0;
  385. /*
  386. * Ruby can overhang only if it is longer and if preceeding/succeeding
  387. * character is of lesser or equal height than the bottom of the Ruby
  388. * pronunciation line.
  389. */
  390. if ((durOverhang < 0)
  391. && (pcheightsRef->dvAscent <=
  392. (pdobj->dvrRubyOffset - pdobj->objdimRuby.heightsRef.dvDescent)))
  393. {
  394. /* Ruby line overhangs - get max to overhang */
  395. lserr = pilsobj->lscbk.pfnGetEms(pilsobj->pols, plsrunRubyText,
  396. pdobj->lstflow, &lsems);
  397. if (lserr != lserrNone)
  398. {
  399. return lserr;
  400. }
  401. durMaxOverhang = lsems.em;
  402. durOverhang = -durOverhang;
  403. if (durMaxOverhang > durOverhang)
  404. {
  405. /* limit maximum overhang to max overhang for ruby line */
  406. durMaxOverhang = durOverhang;
  407. }
  408. }
  409. lserr = pilsobj->rcbk.pfnFetchRubyWidthAdjust(pilsobj->pols,
  410. pdobj->cpStart, plsrun, wch, mwcls, plsrunRubyObject,
  411. rubyloc, durMaxOverhang, pdurAdjText, &durModRuby);
  412. if (lserrNone == lserr)
  413. {
  414. if (durModRuby != 0)
  415. {
  416. /* size of ruby object needs to change */
  417. pdobj->sobjhelp.objdimAll.dur += durModRuby;
  418. lserr = LsdnResetObjDim(pilsobj->plsc, pdobj->plsdn,
  419. &pdobj->sobjhelp.objdimAll);
  420. }
  421. *pdurRubyMod = durModRuby;
  422. }
  423. return lserr;
  424. }
  425. /* M A S S A G E F O R R I G H T A D J U S T */
  426. /*----------------------------------------------------------------------------
  427. %%Function: MassageForRightAdjust
  428. %%Contact: ricksa
  429. Massage object so that right aligned lines will end on exactly
  430. the same pixel.
  431. ----------------------------------------------------------------------------*/
  432. static LSERR MassageForRightAdjust(
  433. PDOBJ pdobj) /* dobj for Ruby */
  434. {
  435. LSERR lserr;
  436. long dupRuby;
  437. long dupMain;
  438. long dupDiff;
  439. LSTFLOW lstflowIgnored;
  440. /* Get the length of the two lines */
  441. lserr = LssbGetDupSubline(pdobj->plssublMain, &lstflowIgnored, &dupMain);
  442. if (lserr != lserrNone) return lserr;
  443. lserr = LssbGetDupSubline(pdobj->plssublRuby, &lstflowIgnored, &dupRuby);
  444. if (lserr != lserrNone) return lserr;
  445. /* Get difference between two lines */
  446. dupDiff = dupMain - dupRuby;
  447. if (dupDiff >= 0)
  448. {
  449. /* Main line longest */
  450. pdobj->dupOffsetRuby = pdobj->dupOffsetMain + dupDiff;
  451. }
  452. else
  453. {
  454. /* Ruby line longest - reverse sign of dupDiff to add */
  455. pdobj->dupOffsetMain = pdobj->dupOffsetRuby - dupDiff;
  456. }
  457. return lserrNone;
  458. }
  459. /* R U B I C R E A T E I L S O B J */
  460. /*----------------------------------------------------------------------------
  461. %%Function: RubyCreateILSObj
  462. %%Contact: ricksa
  463. CreateILSObj
  464. Create the ILS object for all Ruby objects.
  465. ----------------------------------------------------------------------------*/
  466. LSERR WINAPI RubyCreateILSObj(
  467. POLS pols, /* (IN): client application context */
  468. PLSC plsc, /* (IN): LS context */
  469. PCLSCBK pclscbk, /* (IN): callbacks to client application */
  470. DWORD idObj, /* (IN): id of the object */
  471. PILSOBJ *ppilsobj) /* (OUT): object ilsobj */
  472. {
  473. PILSOBJ pilsobj;
  474. LSERR lserr;
  475. RUBYINIT rubyinit;
  476. rubyinit.dwVersion = RUBY_VERSION;
  477. /* Get initialization data */
  478. lserr = pclscbk->pfnGetObjectHandlerInfo(pols, idObj, &rubyinit);
  479. if (lserr != lserrNone)
  480. {
  481. return lserr;
  482. }
  483. pilsobj = pclscbk->pfnNewPtr(pols, sizeof(*pilsobj));
  484. if (NULL == pilsobj)
  485. {
  486. return lserrOutOfMemory;
  487. }
  488. pilsobj->pols = pols;
  489. pilsobj->lscbk = *pclscbk;
  490. pilsobj->plsc = plsc;
  491. pilsobj->lsescMain.wchFirst = rubyinit.wchEscMain;
  492. pilsobj->lsescMain.wchLast = rubyinit.wchEscMain;
  493. pilsobj->lsescRuby.wchFirst = rubyinit.wchEscRuby;
  494. pilsobj->lsescRuby.wchLast = rubyinit.wchEscRuby;
  495. pilsobj->rcbk = rubyinit.rcbk;
  496. pilsobj->rubysyntax = rubyinit.rubysyntax;
  497. *ppilsobj = pilsobj;
  498. return lserrNone;
  499. }
  500. /* R U B I D E S T R O Y I L S O B J */
  501. /*----------------------------------------------------------------------------
  502. %%Function: RubyDestroyILSObj
  503. %%Contact: ricksa
  504. DestroyILSObj
  505. Free all resources assocaiated with Ruby ILS object.
  506. ----------------------------------------------------------------------------*/
  507. LSERR WINAPI RubyDestroyILSObj(
  508. PILSOBJ pilsobj) /* (IN): object ilsobj */
  509. {
  510. pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pilsobj);
  511. return lserrNone;
  512. }
  513. /* R U B I S E T D O C */
  514. /*----------------------------------------------------------------------------
  515. %%Function: RubySetDoc
  516. %%Contact: ricksa
  517. SetDoc
  518. Keep track of device resolution.
  519. ----------------------------------------------------------------------------*/
  520. LSERR WINAPI RubySetDoc(
  521. PILSOBJ pilsobj, /* (IN): object ilsobj */
  522. PCLSDOCINF pclsdocinf) /* (IN): initialization data of the document level */
  523. {
  524. pilsobj->lsdevres = pclsdocinf->lsdevres;
  525. return lserrNone;
  526. }
  527. /* R U B I C R E A T E L N O B J */
  528. /*----------------------------------------------------------------------------
  529. %%Function: RubyCreateLNObj
  530. %%Contact: ricksa
  531. CreateLNObj
  532. Create the Line Object for the Ruby. Since we only really need
  533. the global ILS object, just pass that object back as the line object.
  534. ----------------------------------------------------------------------------*/
  535. LSERR WINAPI RubyCreateLNObj(
  536. PCILSOBJ pcilsobj, /* (IN): object ilsobj */
  537. PLNOBJ *pplnobj) /* (OUT): object lnobj */
  538. {
  539. *pplnobj = (PLNOBJ) pcilsobj;
  540. return lserrNone;
  541. }
  542. /* R U B I D E S T R O Y L N O B J */
  543. /*----------------------------------------------------------------------------
  544. %%Function: RubyDestroyLNObj
  545. %%Contact: ricksa
  546. DestroyLNObj
  547. Frees resources associated with the Ruby line object. No-op because
  548. we don't really allocate one.
  549. ----------------------------------------------------------------------------*/
  550. LSERR WINAPI RubyDestroyLNObj(
  551. PLNOBJ plnobj) /* (OUT): object lnobj */
  552. {
  553. Unreferenced(plnobj);
  554. return lserrNone;
  555. }
  556. /* R U B I F M T */
  557. /*----------------------------------------------------------------------------
  558. %%Function: RubyFmt
  559. %%Contact: ricksa
  560. Fmt
  561. Format the Ruby object. This formats the main line and the
  562. pronunciation line. It then queries the client for spacing
  563. information and then completes the formatting.
  564. ----------------------------------------------------------------------------*/
  565. LSERR WINAPI RubyFmt(
  566. PLNOBJ plnobj, /* (IN): object lnobj */
  567. PCFMTIN pcfmtin, /* (IN): formatting input */
  568. FMTRES *pfmtres) /* (OUT): formatting result */
  569. {
  570. PDOBJ pdobj;
  571. LSERR lserr;
  572. PILSOBJ pilsobj = (PILSOBJ) plnobj;
  573. POLS pols = pilsobj->pols;
  574. LSCP cpStartMain;
  575. LSCP cpStartRuby = pcfmtin->lsfgi.cpFirst + 1;
  576. LSCP cpOut;
  577. LSTFLOW lstflow = pcfmtin->lsfgi.lstflow;
  578. DWORD cdwRunsMain;
  579. DWORD cdwRunsRuby;
  580. PLSRUN *pplsrunMain = NULL;
  581. PLSRUN *pplsrunRuby = NULL;
  582. FMTRES fmtres;
  583. OBJDIM objdimAll;
  584. FMTRES fmtr = fmtrCompletedRun;
  585. BOOL fSpecialLineStartEnd;
  586. /*
  587. * Allocate the DOBJ
  588. */
  589. pdobj = pilsobj->lscbk.pfnNewPtr(pols, sizeof(*pdobj));
  590. if (pdobj == NULL) return RubyFmtFailed (NULL, lserrOutOfMemory);
  591. ZeroMemory(pdobj, sizeof(*pdobj));
  592. pdobj->pilsobj = pilsobj;
  593. pdobj->plsdn = pcfmtin->plsdnTop;
  594. pdobj->cpStart = pcfmtin->lsfgi.cpFirst;
  595. pdobj->fFirstOnLine = pcfmtin->lsfgi.fFirstOnLine;
  596. pdobj->lstflow = lstflow;
  597. if (RubyPronunciationLineFirst == pilsobj->rubysyntax)
  598. {
  599. /*
  600. * Build pronunciation line of text
  601. */
  602. lserr = FormatLine(pilsobj->plsc, cpStartRuby, LONG_MAX, lstflow,
  603. &pdobj->plssublRuby, RUBY_RUBY_ESC_CNT, &pilsobj->lsescRuby,
  604. &pdobj->objdimRuby, &cpOut, &pdobj->sublnlsdnRuby.plsdnStart,
  605. &pdobj->sublnlsdnRuby.plsdnEnd, &fmtres);
  606. /* +1 moves passed the ruby line escape character */
  607. cpStartMain = cpOut + 1;
  608. pdobj->cpStartRuby = cpStartRuby;
  609. pdobj->cpStartMain = cpStartMain;
  610. /*
  611. * Build main line of text
  612. */
  613. if (lserrNone == lserr)
  614. {
  615. lserr = FormatLine(pilsobj->plsc, cpStartMain, LONG_MAX, lstflow,
  616. &pdobj->plssublMain, RUBY_MAIN_ESC_CNT, &pilsobj->lsescMain,
  617. &pdobj->objdimMain, &cpOut, &pdobj->sublnlsdnMain.plsdnStart,
  618. &pdobj->sublnlsdnMain.plsdnEnd, &fmtres);
  619. }
  620. }
  621. else
  622. {
  623. /*
  624. * Build main line of text
  625. */
  626. cpStartMain = cpStartRuby;
  627. lserr = FormatLine(pilsobj->plsc, cpStartMain, LONG_MAX, lstflow,
  628. &pdobj->plssublMain, RUBY_MAIN_ESC_CNT, &pilsobj->lsescMain,
  629. &pdobj->objdimMain, &cpOut, &pdobj->sublnlsdnMain.plsdnStart,
  630. &pdobj->sublnlsdnMain.plsdnEnd, &fmtres);
  631. /* +1 moves passed the main line escape character */
  632. cpStartRuby = cpOut + 1;
  633. pdobj->cpStartRuby = cpStartRuby;
  634. pdobj->cpStartMain = cpStartMain;
  635. /*
  636. * Build pronunciation line of text
  637. */
  638. if (lserrNone == lserr)
  639. {
  640. lserr = FormatLine(pilsobj->plsc, cpStartRuby, LONG_MAX, lstflow,
  641. &pdobj->plssublRuby, RUBY_RUBY_ESC_CNT, &pilsobj->lsescRuby,
  642. &pdobj->objdimRuby, &cpOut, &pdobj->sublnlsdnRuby.plsdnStart,
  643. &pdobj->sublnlsdnRuby.plsdnEnd, &fmtres);
  644. }
  645. }
  646. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  647. lserr = GetRunsForSubline(pilsobj, pdobj->plssublMain, &cdwRunsMain, &pplsrunMain);
  648. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  649. lserr = GetRunsForSubline(pilsobj, pdobj->plssublRuby, &cdwRunsRuby, &pplsrunRuby);
  650. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  651. /* Save the first and last plsrun for use in GetModWidth */
  652. if (cdwRunsRuby != 0)
  653. {
  654. pdobj->plsrunFirstRubyChar = pplsrunRuby[0];
  655. pdobj->plsrunLastRubyChar = pplsrunRuby[cdwRunsRuby - 1];
  656. }
  657. /*
  658. * Calculate the object dimensions.
  659. */
  660. lserr = pilsobj->rcbk.pfnFetchRubyPosition(pols, pdobj->cpStart, pdobj->lstflow,
  661. cdwRunsMain, pplsrunMain, &pdobj->objdimMain.heightsRef,
  662. &pdobj->objdimMain.heightsPres, cdwRunsRuby, pplsrunRuby,
  663. &pdobj->objdimRuby.heightsRef, &pdobj->objdimRuby.heightsPres,
  664. &objdimAll.heightsRef, &objdimAll.heightsPres,
  665. &pdobj->dvpMainOffset, &pdobj->dvrRubyOffset,
  666. &pdobj->dvpRubyOffset, &pdobj->rubycharjust,
  667. &fSpecialLineStartEnd);
  668. /* Free buffers allocated for plsruns for this call */
  669. if (pplsrunMain != NULL) pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pplsrunMain);
  670. if (pplsrunRuby != NULL) pilsobj->lscbk.pfnDisposePtr(pilsobj->pols, pplsrunRuby);
  671. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  672. /*
  673. * Special line start/end adjustment matters only when a justification of
  674. * centered, 0:1:0 or 1:2:1 is selected.
  675. */
  676. if (fSpecialLineStartEnd
  677. && (pdobj->rubycharjust != rcjLeft)
  678. && (pdobj->rubycharjust != rcjRight))
  679. {
  680. pdobj->fSpecialLineStartEnd = TRUE;
  681. }
  682. /* Distribute space for Ruby */
  683. lserr = DoRubySpaceDistribution(pdobj);
  684. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  685. /* ur is ur of longest subline. */
  686. objdimAll.dur = pdobj->objdimMain.dur;
  687. if (pdobj->objdimMain.dur < pdobj->objdimRuby.dur)
  688. {
  689. objdimAll.dur = pdobj->objdimRuby.dur;
  690. }
  691. pdobj->sobjhelp.objdimAll = objdimAll;
  692. /* Need to add 1 to take into account escape character at end. */
  693. pdobj->sobjhelp.dcp = cpOut - pdobj->cpStart + 1;
  694. lserr = LsdnFinishRegular(pilsobj->plsc, pdobj->sobjhelp.dcp,
  695. pcfmtin->lsfrun.plsrun, pcfmtin->lsfrun.plschp, pdobj,
  696. &pdobj->sobjhelp.objdimAll);
  697. if (lserr != lserrNone) return RubyFmtFailed (pdobj, lserr);
  698. if (pcfmtin->lsfgi.urPen + objdimAll.dur > pcfmtin->lsfgi.urColumnMax)
  699. {
  700. fmtr = fmtrExceededMargin;
  701. }
  702. *pfmtres = fmtr;
  703. AssertSz(((pdobj->fFirstOnLine && pcfmtin->lsfgi.fFirstOnLine)
  704. || (!pdobj->fFirstOnLine && !pcfmtin->lsfgi.fFirstOnLine)),
  705. "RubyFmt - bad first on line flag");
  706. return lserrNone;
  707. }
  708. /* R U B Y G E T M O D W I D T H P R E C E D I N G C H A R */
  709. /*----------------------------------------------------------------------------
  710. %%Function: RubyGetModWidthPrecedingChar
  711. %%Contact: ricksa
  712. .
  713. ----------------------------------------------------------------------------*/
  714. LSERR WINAPI RubyGetModWidthPrecedingChar(
  715. PDOBJ pdobj, /* (IN): dobj */
  716. PLSRUN plsrun, /* (IN): plsrun of the object */
  717. PLSRUN plsrunText, /* (IN): plsrun of the preceding char */
  718. PCHEIGHTS pcheightsRef, /* (IN): height info about character */
  719. WCHAR wchar, /* (IN): preceding character */
  720. MWCLS mwcls, /* (IN): ModWidth class of preceding character */
  721. long *pdurChange) /* (OUT): amount by which width of the preceding char is to be changed */
  722. {
  723. AssertSz(!pdobj->fFirstOnLine, "RubyGetModWidthPrecedingChar got called for first char");
  724. return ModWidthHandler(pdobj, rubyBefore, plsrunText, wchar, mwcls,
  725. pcheightsRef, plsrun, pdobj->plsrunFirstRubyChar, pdobj->durDiff,
  726. pdurChange, &pdobj->durModBefore);
  727. }
  728. /* R U B Y G E T M O D W I D T H F O L L O W I N G C H A R */
  729. /*----------------------------------------------------------------------------
  730. %%Function: RubyGetModWidthFollowingChar
  731. %%Contact: ricksa
  732. .
  733. ----------------------------------------------------------------------------*/
  734. LSERR WINAPI RubyGetModWidthFollowingChar(
  735. PDOBJ pdobj, /* (IN): dobj */
  736. PLSRUN plsrun, /* (IN): plsrun of the object */
  737. PLSRUN plsrunText, /* (IN): plsrun of the following char */
  738. PCHEIGHTS pcheightsRef, /* (IN): height info about character */
  739. WCHAR wchar, /* (IN): following character */
  740. MWCLS mwcls, /* (IN): ModWidth class of the following character */
  741. long *pdurChange) /* (OUT): amount by which width of the following char is to be changed */
  742. {
  743. long durDiff = pdobj->durDiff;
  744. pdobj->fModAfterCalled = TRUE;
  745. switch (pdobj->rubycharjust)
  746. {
  747. case rcjRight:
  748. /* Right justified so no overhang on right */
  749. durDiff = 0;
  750. break;
  751. case rcjLeft:
  752. /* For left, max overhang is difference between widths of lines */
  753. durDiff = pdobj->objdimMain.dur - pdobj->objdimRuby.dur;
  754. break;
  755. default:
  756. break;
  757. }
  758. return ModWidthHandler(pdobj, rubyAfter, plsrunText, wchar, mwcls,
  759. pcheightsRef, plsrun, pdobj->plsrunLastRubyChar, durDiff, pdurChange,
  760. &pdobj->sobjhelp.durModAfter);
  761. }
  762. /* R U B Y S E T B R E A K */
  763. /*----------------------------------------------------------------------------
  764. %%Function: RubySetBreak
  765. %%Contact: ricksa
  766. SetBreak
  767. .
  768. ----------------------------------------------------------------------------*/
  769. LSERR WINAPI RubySetBreak(
  770. PDOBJ pdobj, /* (IN): dobj which is broken */
  771. BRKKIND brkkind, /* (IN): prev | next | force | after */
  772. DWORD cBreakRecord, /* (IN): size of array */
  773. BREAKREC *rgBreakRecord, /* (IN): array of break records */
  774. DWORD *pcActualBreakRecord) /* (IN): actual number of used elements in array */
  775. {
  776. LSERR lserr = lserrNone;
  777. LSCP cpOut;
  778. LSDCP dcpVisible;
  779. /* REVIEW (antons): Check this strange logic after new breaking will work */
  780. Unreferenced (rgBreakRecord);
  781. Unreferenced (cBreakRecord);
  782. Unreferenced (brkkind);
  783. Unreferenced (pdobj);
  784. Unreferenced (cpOut);
  785. Unreferenced (dcpVisible);
  786. *pcActualBreakRecord = 0;
  787. #ifdef UNDEFINED
  788. if (pdobj->fSpecialLineStartEnd && !pdobj->fFirstOnLine &&
  789. brkkind != brkkindImposedAfter)
  790. {
  791. /*
  792. * Because object is last on line and Ruby overhangs, we need to adjust
  793. * its width for the new overhang.
  794. */
  795. PILSOBJ pilsobj = pdobj->pilsobj;
  796. FMTRES fmtres;
  797. long dur;
  798. long dcpOffset = pdobj->dcpRuby;
  799. if (RubyMainLineFirst == pdobj->pilsobj->rubysyntax)
  800. {
  801. dcpOffset = 0;
  802. }
  803. /* clear out original subline */
  804. LsDestroySubline(pdobj->plssublMain);
  805. /* Format the main line over again */
  806. lserr = FormatLine(pilsobj->plsc, pdobj->cpStart + dcpOffset + 1,
  807. LONG_MAX, pdobj->lstflow, &pdobj->plssublMain, RUBY_MAIN_ESC_CNT,
  808. &pilsobj->lsescMain, &pdobj->objdimMain, &cpOut,
  809. &pdobj->sublnlsdnMain.plsdnStart,
  810. &pdobj->sublnlsdnMain.plsdnEnd, &fmtres);
  811. if (lserr != lserrNone) return lserr;
  812. dur = pdobj->objdimRuby.dur - pdobj->objdimMain.dur;
  813. AssertSz(dur > 0, "RubySetBreak - no overhang width");
  814. lserr = LssbGetVisibleDcpInSubline(pdobj->plssublMain, &dcpVisible);
  815. if (lserrNone == lserr)
  816. {
  817. pdobj->durDiff = 0;
  818. if (dur > (long) dcpVisible)
  819. {
  820. pdobj->durDiff = -(dur / (long) dcpVisible);
  821. dur += pdobj->durDiff;
  822. }
  823. /* Force to right just so we can guranatee end on same pixel */
  824. pdobj->rubycharjust = rcjRight;
  825. lserr = LsdnDistribute(pilsobj->plsc,
  826. pdobj->sublnlsdnMain.plsdnStart,
  827. pdobj->sublnlsdnMain.plsdnEnd, dur);
  828. }
  829. }
  830. #endif
  831. return lserr;
  832. }
  833. /* R U B Y G E T S P E C I A L E F F E C T S I N S I D E */
  834. /*----------------------------------------------------------------------------
  835. %%Function: RubyGetSpecialEffectsInside
  836. %%Contact: ricksa
  837. GetSpecialEffectsInside
  838. .
  839. ----------------------------------------------------------------------------*/
  840. LSERR WINAPI RubyGetSpecialEffectsInside(
  841. PDOBJ pdobj, /* (IN): dobj */
  842. UINT *pEffectsFlags) /* (OUT): Special effects for this object */
  843. {
  844. LSERR lserr = LsGetSpecialEffectsSubline(pdobj->plssublMain, pEffectsFlags);
  845. if (lserrNone == lserr)
  846. {
  847. UINT uiSpecialEffectsRuby;
  848. lserr = LsGetSpecialEffectsSubline(pdobj->plssublRuby, &uiSpecialEffectsRuby);
  849. *pEffectsFlags |= uiSpecialEffectsRuby;
  850. }
  851. return lserr;
  852. }
  853. /* R U B Y C A L C P R E S E N T A T I O N */
  854. /*----------------------------------------------------------------------------
  855. %%Function: RubyCalcPresentation
  856. %%Contact: ricksa
  857. CalcPresentation
  858. This has two jobs. First, it prepares each line for presentation. Then,
  859. it calculates the positions of the lines in output device coordinates.
  860. ----------------------------------------------------------------------------*/
  861. LSERR WINAPI RubyCalcPresentation(
  862. PDOBJ pdobj, /* (IN): dobj */
  863. long dup, /* (IN): dup of dobj */
  864. LSKJUST lskjust, /* (IN): Justification type */
  865. BOOL fLastVisibleOnLine ) /* (IN): Is this object last visible on line? */
  866. {
  867. PILSOBJ pilsobj = pdobj->pilsobj;
  868. LSERR lserr = lserrNone;
  869. long durOffsetMain;
  870. long durOffsetRuby;
  871. long durDiff = pdobj->durDiff;
  872. Unreferenced (lskjust);
  873. Unreferenced(dup);
  874. /*
  875. * Prepare lines for presentation
  876. */
  877. if (pdobj->fSpecialLineStartEnd && !pdobj->fFirstOnLine && fLastVisibleOnLine)
  878. {
  879. pdobj->rubycharjust = rcjRight;
  880. };
  881. lserr = LsMatchPresSubline(pdobj->plssublMain);
  882. if (lserr != lserrNone)
  883. {
  884. return lserr;
  885. }
  886. lserr = LsMatchPresSubline(pdobj->plssublRuby);
  887. if (lserr != lserrNone)
  888. {
  889. return lserr;
  890. }
  891. /*
  892. * Calculate positions of lines
  893. */
  894. if (pdobj->fFirstOnLine && pdobj->fSpecialLineStartEnd)
  895. {
  896. durDiff = 0;
  897. }
  898. durOffsetMain = pdobj->durModBefore;
  899. /* Calculate amount to adjust in reference */
  900. if ((durDiff < 0) && (pdobj->rubycharjust != rcjLeft))
  901. {
  902. /* Ruby line overhangs main line */
  903. durOffsetMain -= durDiff;
  904. }
  905. pdobj->dupOffsetMain = UpFromUr(pdobj->lstflow, (&pilsobj->lsdevres),
  906. durOffsetMain);
  907. durOffsetRuby = pdobj->durModBefore;
  908. if (durDiff > 0)
  909. {
  910. /* Main line underhangs ruby line */
  911. durOffsetRuby += durDiff;
  912. }
  913. pdobj->dupOffsetRuby = UpFromUr(pdobj->lstflow, (&pilsobj->lsdevres),
  914. durOffsetRuby);
  915. if (rcjRight == pdobj->rubycharjust)
  916. {
  917. /*
  918. * There can be a pixel rounding error in the above calculations
  919. * so that we massage the above calculations so that when the
  920. * adjustment is right, both lines are guaranteed to end of the
  921. * same pixel.
  922. */
  923. MassageForRightAdjust(pdobj);
  924. }
  925. return lserr;
  926. }
  927. /* R U B Y Q U E R Y P O I N T P C P */
  928. /*----------------------------------------------------------------------------
  929. %%Function: RubyQueryPointPcp
  930. %%Contact: ricksa
  931. Map dup to dcp
  932. There is a certain trickiness about how we determine which subline
  933. to query. Because the client specifies the offsets, the sublines
  934. can actually wind up anywhere. We use the simple algorithm that
  935. if the query does not fall into the Ruby pronunciation line, they
  936. actually mean the main line of text.
  937. ----------------------------------------------------------------------------*/
  938. LSERR WINAPI RubyQueryPointPcp(
  939. PDOBJ pdobj, /*(IN): dobj to query */
  940. PCPOINTUV ppointuvQuery, /*(IN): query point (uQuery,vQuery) */
  941. PCLSQIN plsqin, /*(IN): query input */
  942. PLSQOUT plsqout) /*(OUT): query output */
  943. {
  944. PLSSUBL plssubl;
  945. long dupAdj;
  946. long dvpAdj;
  947. long dvpRubyOffset = pdobj->dvpRubyOffset;
  948. /*
  949. * Decide which line to to return based on the height of the point input
  950. */
  951. /* Assume main line */
  952. plssubl = pdobj->plssublMain;
  953. dupAdj = pdobj->dupOffsetMain;
  954. dvpAdj = 0;
  955. if ((ppointuvQuery->v > (dvpRubyOffset - pdobj->objdimRuby.heightsPres.dvDescent))
  956. && (ppointuvQuery->v <= (dvpRubyOffset + pdobj->objdimRuby.heightsPres.dvAscent)))
  957. {
  958. /* hit second line */
  959. plssubl = pdobj->plssublRuby;
  960. dupAdj = pdobj->dupOffsetRuby;
  961. dvpAdj = pdobj->dvpRubyOffset;
  962. }
  963. return CreateQueryResult(plssubl, dupAdj, dvpAdj, plsqin, plsqout);
  964. }
  965. /* R U B Y Q U E R Y C P P P O I N T */
  966. /*----------------------------------------------------------------------------
  967. %%Function: RubyQueryCpPpoint
  968. %%Contact: ricksa
  969. Map dcp to dup
  970. If client wants all text treated as a single object, then the handler
  971. just returns the object dimensions. Otherwise, we calculate the line to
  972. query and ask that line for the dimensions of the dcp.
  973. ----------------------------------------------------------------------------*/
  974. LSERR WINAPI RubyQueryCpPpoint(
  975. PDOBJ pdobj, /*(IN): dobj to query, */
  976. LSDCP dcp, /*(IN): dcp for the query */
  977. PCLSQIN plsqin, /*(IN): query input */
  978. PLSQOUT plsqout) /*(OUT): query output */
  979. {
  980. PLSSUBL plssubl;
  981. long dupAdj;
  982. long dvpAdj;
  983. BOOL fMain = fFalse;
  984. LSCP cpQuery = pdobj->cpStart + dcp;
  985. /*
  986. * Calculate subline to query
  987. */
  988. /* Assume ruby line */
  989. plssubl = pdobj->plssublRuby;
  990. dupAdj = pdobj->dupOffsetRuby;
  991. dvpAdj = pdobj->dvpRubyOffset;
  992. /* + 1 means we include the cp of the object in the Ruby pronunciation line. */
  993. if (RubyPronunciationLineFirst == pdobj->pilsobj->rubysyntax)
  994. {
  995. /* Ruby pronunciation line is first */
  996. if (cpQuery >= pdobj->cpStartMain)
  997. {
  998. fMain = fTrue;
  999. }
  1000. }
  1001. else
  1002. {
  1003. /* Main text line is first */
  1004. if (cpQuery < pdobj->cpStartRuby)
  1005. {
  1006. fMain = fTrue;
  1007. }
  1008. }
  1009. if (fMain)
  1010. {
  1011. plssubl = pdobj->plssublMain;
  1012. dupAdj = pdobj->dupOffsetMain;
  1013. dvpAdj = pdobj->dvpMainOffset;
  1014. }
  1015. return CreateQueryResult(plssubl, dupAdj, dvpAdj, plsqin, plsqout);
  1016. }
  1017. /* R U B I D I S P L A Y */
  1018. /*----------------------------------------------------------------------------
  1019. %%Function: RubyDisplay
  1020. %%Contact: ricksa
  1021. Display
  1022. This calculates the positions of the various lines for the
  1023. display and then displays them.
  1024. ----------------------------------------------------------------------------*/
  1025. LSERR WINAPI RubyDisplay(
  1026. PDOBJ pdobj, /*(IN): dobj to display */
  1027. PCDISPIN pcdispin) /*(IN): display info */
  1028. {
  1029. LSERR lserr;
  1030. LSTFLOW lstflow = pcdispin->lstflow;
  1031. UINT kDispMode = pcdispin->kDispMode;
  1032. POINT ptLine;
  1033. /* Calculate point to start displaying main line. */
  1034. GetMainPoint(pdobj, &pcdispin->ptPen, lstflow, &ptLine);
  1035. /* display first line */
  1036. lserr = LsDisplaySubline(pdobj->plssublMain, &ptLine, kDispMode,
  1037. pcdispin->prcClip);
  1038. if (lserr != lserrNone)
  1039. {
  1040. return lserr;
  1041. }
  1042. /* Calculate point to start displaying ruby line. */
  1043. GetRubyPoint(pdobj, &pcdispin->ptPen, lstflow, &ptLine);
  1044. /* display ruby line */
  1045. return LsDisplaySubline(pdobj->plssublRuby, &ptLine, kDispMode,
  1046. pcdispin->prcClip);
  1047. }
  1048. /* R U B I D E S T R O Y D O B J */
  1049. /*----------------------------------------------------------------------------
  1050. %%Function: RubyDestroyDobj
  1051. %%Contact: ricksa
  1052. DestroyDobj
  1053. Free all resources connected with the input dobj.
  1054. ----------------------------------------------------------------------------*/
  1055. LSERR WINAPI RubyDestroyDobj(
  1056. PDOBJ pdobj) /*(IN): dobj to destroy */
  1057. {
  1058. return RubyFreeDobj (pdobj);
  1059. }
  1060. /* R U B Y E N U M */
  1061. /*----------------------------------------------------------------------------
  1062. %%Function: RubyEnum
  1063. %%Contact: ricksa
  1064. Enum
  1065. Enumeration callback - passed to client.
  1066. ----------------------------------------------------------------------------*/
  1067. LSERR WINAPI RubyEnum(
  1068. PDOBJ pdobj, /*(IN): dobj to enumerate */
  1069. PLSRUN plsrun, /*(IN): from DNODE */
  1070. PCLSCHP plschp, /*(IN): from DNODE */
  1071. LSCP cp, /*(IN): from DNODE */
  1072. LSDCP dcp, /*(IN): from DNODE */
  1073. LSTFLOW lstflow, /*(IN): text flow*/
  1074. BOOL fReverse, /*(IN): enumerate in reverse order */
  1075. BOOL fGeometryNeeded, /*(IN): */
  1076. const POINT *pt, /*(IN): starting position (top left), iff fGeometryNeeded */
  1077. PCHEIGHTS pcheights, /*(IN): from DNODE, relevant iff fGeometryNeeded */
  1078. long dupRun) /*(IN): from DNODE, relevant iff fGeometryNeeded */
  1079. {
  1080. POINT ptMain;
  1081. POINT ptRuby;
  1082. long dupMain = 0;
  1083. long dupRuby = 0;
  1084. LSERR lserr;
  1085. LSTFLOW lstflowIgnored;
  1086. if (fGeometryNeeded)
  1087. {
  1088. GetMainPoint(pdobj, pt, lstflow, &ptMain);
  1089. GetRubyPoint(pdobj, pt, lstflow, &ptMain);
  1090. lserr = LssbGetDupSubline(pdobj->plssublMain, &lstflowIgnored, &dupMain);
  1091. AssertSz(lserrNone == lserr, "RubyEnum - can't get dup for main");
  1092. lserr = LssbGetDupSubline(pdobj->plssublRuby, &lstflowIgnored, &dupRuby);
  1093. AssertSz(lserrNone == lserr, "RubyEnum - can't get dup for ruby");
  1094. }
  1095. return pdobj->pilsobj->rcbk.pfnRubyEnum(pdobj->pilsobj->pols, plsrun,
  1096. plschp, cp, dcp, lstflow, fReverse, fGeometryNeeded, pt, pcheights,
  1097. dupRun, &ptMain, &pdobj->objdimMain.heightsPres, dupMain, &ptRuby,
  1098. &pdobj->objdimRuby.heightsPres, dupRuby, pdobj->plssublMain,
  1099. pdobj->plssublRuby);
  1100. }
  1101. /* R U B I H A N D L E R I N I T */
  1102. /*----------------------------------------------------------------------------
  1103. %%Function: RubyHandlerInit
  1104. %%Contact: ricksa
  1105. Initialize global Ruby data and return LSIMETHODS.
  1106. ----------------------------------------------------------------------------*/
  1107. LSERR WINAPI LsGetRubyLsimethods(
  1108. LSIMETHODS *plsim)
  1109. {
  1110. plsim->pfnCreateILSObj = RubyCreateILSObj;
  1111. plsim->pfnDestroyILSObj = RubyDestroyILSObj;
  1112. plsim->pfnSetDoc = RubySetDoc;
  1113. plsim->pfnCreateLNObj = RubyCreateLNObj;
  1114. plsim->pfnDestroyLNObj = RubyDestroyLNObj;
  1115. plsim->pfnFmt = RubyFmt;
  1116. plsim->pfnFmtResume = ObjHelpFmtResume;
  1117. plsim->pfnGetModWidthPrecedingChar = RubyGetModWidthPrecedingChar;
  1118. plsim->pfnGetModWidthFollowingChar = RubyGetModWidthFollowingChar;
  1119. plsim->pfnTruncateChunk = SobjTruncateChunk;
  1120. plsim->pfnFindPrevBreakChunk = SobjFindPrevBreakChunk;
  1121. plsim->pfnFindNextBreakChunk = SobjFindNextBreakChunk;
  1122. plsim->pfnForceBreakChunk = SobjForceBreakChunk;
  1123. plsim->pfnSetBreak = RubySetBreak;
  1124. plsim->pfnGetSpecialEffectsInside = RubyGetSpecialEffectsInside;
  1125. plsim->pfnFExpandWithPrecedingChar = ObjHelpFExpandWithPrecedingChar;
  1126. plsim->pfnFExpandWithFollowingChar = ObjHelpFExpandWithFollowingChar;
  1127. plsim->pfnCalcPresentation = RubyCalcPresentation;
  1128. plsim->pfnQueryPointPcp = RubyQueryPointPcp;
  1129. plsim->pfnQueryCpPpoint = RubyQueryCpPpoint;
  1130. plsim->pfnDisplay = RubyDisplay;
  1131. plsim->pfnDestroyDObj = RubyDestroyDobj;
  1132. plsim->pfnEnum = RubyEnum;
  1133. return lserrNone;
  1134. }