LayoutUtil.c 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: LayoutUtil.c /main/26 1996/11/06 12:25:09 cde-hp $ */
  24. /************************************<+>*************************************
  25. ****************************************************************************
  26. **
  27. ** File: LayoutUtil.c
  28. **
  29. ** Project: Cde DtHelp
  30. **
  31. ** Description:
  32. **
  33. ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
  34. **
  35. ** (c) Copyright 1993, 1994 Hewlett-Packard Company
  36. ** (c) Copyright 1993, 1994 International Business Machines Corp.
  37. ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  38. ** (c) Copyright 1993, 1994 Novell, Inc.
  39. **
  40. **
  41. **
  42. ****************************************************************************
  43. ************************************<+>*************************************/
  44. /*
  45. * system includes
  46. */
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <limits.h>
  50. /*
  51. * Canvas Engine includes
  52. */
  53. #include "CanvasP.h"
  54. #include "CanvasSegP.h"
  55. /*
  56. * private includes
  57. */
  58. #include "CanvasI.h"
  59. #include "CvStringI.h"
  60. #include "LayoutUtilI.h"
  61. #include "StringFuncsI.h"
  62. #include "VirtFuncsI.h"
  63. /******************************************************************************
  64. *
  65. * Private Defines
  66. *
  67. *****************************************************************************/
  68. #define GROW_SIZE 10
  69. #define CheckFormat(x) \
  70. (((x)->format_y == -1 || (x)->format_y > (x)->y_pos) ? False : True)
  71. /******************************************************************************
  72. *
  73. * Private Variables
  74. *
  75. *****************************************************************************/
  76. static char *OneByteCantBeginList = "])}`\"\'.,;?:!";
  77. static char *OneByteCantEndList = "[({`\"";
  78. static _DtCvLayoutInfo DefLayInfo =
  79. {
  80. NULL, /* _DtCvSegmentI *line_seg; */
  81. 0, /* unsigned int line_start; */
  82. 0, /* unsigned int line_bytes; */
  83. 0, /* _DtCvUnit cur_len; */
  84. 0, /* _DtCvUnit max_x_pos; */
  85. 0, /* _DtCvUnit cur_max_x; */
  86. 0, /* _DtCvUnit y_pos; */
  87. 0, /* _DtCvUnit text_x_pos; */
  88. 0, /* _DtCvUnit leading; */
  89. -1, /* int lst_hyper; */
  90. _CEFORMAT_ALL, /* int format_y; */
  91. -1, /* int join_line; */
  92. FALSE, /* _DtCvValue lst_vis; */
  93. FALSE, /* _DtCvValue join; */
  94. FALSE, /* _DtCvValue align_flag; */
  95. NULL, /* const char *align_char; */
  96. -1, /* _DtCvUnit align_pos; */
  97. 0, /* int delayed_search_saves */
  98. };
  99. static const _DtCvSelectData DefSelectData = { -1, -1, -1, -1 };
  100. static const _DtCvTraversalInfo DefTravData =
  101. {
  102. _DtCvFALSE /* active */,
  103. _DtCvTraversalNone /* type */,
  104. -1 /* idx */,
  105. 0 /* x_pos */,
  106. 0 /* y_pos */,
  107. 0 /* width */,
  108. 0 /* height */,
  109. NULL /* *seg_ptr */
  110. };
  111. /******************************************************************************
  112. *
  113. * Private Functions
  114. *
  115. *****************************************************************************/
  116. /******************************************************************************
  117. * Function: IsTrueMultiByte
  118. *
  119. * Returns: True if the character is a multibyte character
  120. * False if the character is a single byte character.
  121. *****************************************************************************/
  122. static _DtCvValue
  123. IsTrueMultiByte (wchar_t wc_char)
  124. {
  125. char buf[MB_LEN_MAX];
  126. /*
  127. * check to see if this is a one byte character
  128. * There might not be a multibyte list for this locale.
  129. * Can't break on single byte characters.
  130. */
  131. if (1 != wctomb(buf, wc_char))
  132. return True;
  133. return False;
  134. }
  135. /******************************************************************************
  136. * Function: CheckList
  137. *
  138. * Returns: True if the character matches one of the characters in
  139. * the MultiCantEndList.
  140. * False if the character does not match an item in
  141. * the MultiCantEndList.
  142. *****************************************************************************/
  143. static _DtCvValue
  144. CheckList (
  145. wchar_t wc_char,
  146. const wchar_t *list)
  147. {
  148. /*
  149. * check the multibyte list for the character
  150. */
  151. if (list != NULL)
  152. {
  153. while ('\0' != *list)
  154. {
  155. /*
  156. * it matches, return true
  157. */
  158. if (*list == wc_char)
  159. return True;
  160. list++;
  161. }
  162. }
  163. return False;
  164. }
  165. /*****************************************************************************
  166. * Function: static int CompareTraversalPos (_DtCvHandle canvas);
  167. *
  168. * Parameters:
  169. *
  170. * Returns:
  171. *
  172. * Purpose:
  173. *
  174. *****************************************************************************/
  175. static int
  176. CompareTraversalPos (
  177. const void *a,
  178. const void *b)
  179. {
  180. _DtCvTraversalInfo *linkA = (_DtCvTraversalInfo *) a;
  181. _DtCvTraversalInfo *linkB = (_DtCvTraversalInfo *) b;
  182. _DtCvUnit centA = linkA->y_pos + (linkA->height >> 1);
  183. _DtCvUnit centB = linkB->y_pos + (linkB->height >> 1);
  184. if (linkA->y_pos + linkA->height < centB && centA < linkB->y_pos)
  185. return -1;
  186. if (linkB->y_pos + linkB->height < centA && centB < linkA->y_pos)
  187. return 1;
  188. if (linkA->x_pos != linkB->x_pos)
  189. return ((linkA->x_pos < linkB->x_pos) ? -1 : 1);
  190. if (linkA->y_pos != linkB->y_pos)
  191. return ((linkA->y_pos < linkB->y_pos) ? -1 : 1);
  192. if (linkA->height != linkB->height)
  193. return ((linkA->height < linkB->height) ? -1 : 1);
  194. if (linkA->width != linkB->width)
  195. return ((linkA->width < linkB->width) ? -1 : 1);
  196. return 0;
  197. }
  198. /******************************************************************************
  199. *
  200. * Private Layout Utility Functions
  201. *
  202. *****************************************************************************/
  203. /******************************************************************************
  204. * Function: void _DtCvInitLayoutInfo ()
  205. *
  206. * Parameters:
  207. *
  208. * Returns: Nothing.
  209. *
  210. *****************************************************************************/
  211. void
  212. _DtCvInitLayoutInfo (
  213. _DtCanvasStruct *canvas,
  214. _DtCvLayoutInfo *layout)
  215. {
  216. *layout = DefLayInfo;
  217. layout->y_pos = canvas->metrics.top_margin;
  218. }
  219. /******************************************************************************
  220. * Function: int _DtCvGetTraversalWidth ()
  221. *
  222. * Parameters:
  223. *
  224. * Returns: The total amount of space to add before and after the
  225. * segment to take into account traversal/link metrics on
  226. * this segment including any necessary to 'close' out the
  227. * link on the previous segment.
  228. *
  229. *****************************************************************************/
  230. int
  231. _DtCvGetTraversalWidth (
  232. _DtCanvasStruct *canvas,
  233. _DtCvSegmentI *p_seg,
  234. int lst_hyper)
  235. {
  236. int value = 0;
  237. int lnkBefore = 0;
  238. int lnkAfter = 0;
  239. /*
  240. * does this segment have a different link than the previous one?
  241. */
  242. if (lst_hyper != p_seg->link_idx)
  243. {
  244. /*
  245. * is the link visible?
  246. */
  247. if (_DtCvIsSegVisibleLink(p_seg))
  248. {
  249. /*
  250. * get the visible link metrics
  251. */
  252. lnkBefore = canvas->link_info.space_before;
  253. lnkAfter = canvas->link_info.space_after;
  254. }
  255. if (_DtCvIsSegALink(p_seg))
  256. {
  257. /*
  258. * if the last 'link' was really a link, close it out by
  259. * leaving room for the traversal and link end indicators
  260. */
  261. if (lst_hyper != -1)
  262. value += (canvas->traversal_info.space_after + lnkAfter);
  263. /*
  264. * leave space for the traversal/link begin and end
  265. * indicators for this segment.
  266. */
  267. value += (canvas->traversal_info.space_before
  268. + canvas->traversal_info.space_after
  269. + lnkBefore
  270. + lnkAfter);
  271. }
  272. }
  273. return value;
  274. }
  275. /******************************************************************************
  276. * Function: _DtCvAddLines
  277. *
  278. * makes sure the last x number of lines are blank.
  279. *****************************************************************************/
  280. void
  281. _DtCvAddSpace (
  282. _DtCvUnit number,
  283. _DtCvUnit *ret_y)
  284. {
  285. /*
  286. * anything to do?
  287. */
  288. if (0 >= number)
  289. return;
  290. /*
  291. * adjust the global Y position to allow the extra room
  292. */
  293. *ret_y = *ret_y + number;
  294. }
  295. /******************************************************************************
  296. * Function: CheckOneByteCantEndList
  297. *
  298. * Returns: True if the character matches one of the characters in
  299. * the OneByteCantEndList.
  300. * False if the character does not match an item in
  301. * the OneByteCantEndList.
  302. *****************************************************************************/
  303. _DtCvValue
  304. _DtCvCheckOneByteCantEndList (
  305. char c,
  306. char *cant_end_list)
  307. {
  308. int i;
  309. for (i = 0; cant_end_list[i]; i++)
  310. if (cant_end_list[i] == c)
  311. return True;
  312. return False;
  313. }
  314. /******************************************************************************
  315. * Function: CheckOneByteCantBeginList
  316. *
  317. * Returns: True if the character matches one of the characters in
  318. * the OneByteCantBeginList.
  319. * False if the character does not match an item in
  320. * the OneByteCantBeginList.
  321. *****************************************************************************/
  322. _DtCvValue
  323. _DtCvCheckOneByteCantBeginList (
  324. char c,
  325. char *cant_begin_list)
  326. {
  327. int i;
  328. for (i = 0; cant_begin_list[i]; i++)
  329. if (cant_begin_list[i] == c)
  330. return True;
  331. return False;
  332. }
  333. /******************************************************************************
  334. * Function: CheckLineSyntax
  335. *
  336. * Returns: True if the segment can end a line.
  337. * False if the segment can not end a line.
  338. *
  339. * Purpose: Checks the line syntax. Will not allow a segment to end
  340. * a line if:
  341. * the segment does not end with a hypen.
  342. * the segment does not end with a space and the
  343. * next segment does not begin with a space.
  344. * the segment ends with a two byte characters that
  345. * can not end a line.
  346. * The next segment starts with a two byte character
  347. * that can not begin a line.
  348. * the segment ends with an one-byte open type and
  349. * the next segment starts with a
  350. * two byte character.
  351. * the segment ends with a two byte character and
  352. * the next segment starts with a one-byte
  353. * close type.
  354. * the next segment is a non-breaking string or region.
  355. *
  356. *****************************************************************************/
  357. _DtCvValue
  358. _DtCvCheckLineSyntax (
  359. _DtCanvasStruct *canvas,
  360. _DtCvSegmentI *pSeg,
  361. int start,
  362. int str_len,
  363. _DtCvValue skip_hypen_ck)
  364. {
  365. int myStrLen = 0;
  366. int wcFlag = 0;
  367. void *pChar = NULL;
  368. wchar_t nextChar;
  369. wchar_t lastChar = 0;
  370. _DtCvValue lstCharMb = False;
  371. _DtCvValue nxtCharMb = False;
  372. /*
  373. * while this is a marker or a noop without a end-of-line, go to the
  374. * next segment.
  375. */
  376. while (NULL != pSeg && (_DtCvIsSegMarker(pSeg) ||
  377. (_DtCvIsSegNoop(pSeg) && !_DtCvIsSegNewLine(pSeg))))
  378. pSeg = pSeg->next_seg;
  379. /*
  380. * if this segment is null or not a string or region, stop the
  381. * test right now.
  382. */
  383. if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
  384. return True;
  385. /*
  386. * Get the string segment stats
  387. */
  388. if (_DtCvIsSegString(pSeg))
  389. {
  390. wcFlag = _DtCvIsSegWideChar(pSeg);
  391. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg), wcFlag, start);
  392. myStrLen = _DtCvStrLen (pChar, wcFlag);
  393. }
  394. /*
  395. * if this is a region or a string segment (at the end of its string)
  396. * and it has a newline on it, then it can end a line.
  397. */
  398. if ((_DtCvIsSegRegion(pSeg) ||
  399. (_DtCvIsSegString(pSeg) && myStrLen == str_len))
  400. && (_DtCvIsSegNewLine (pSeg) || pSeg->next_seg == NULL))
  401. return True;
  402. /*
  403. * if this is a region, then check it's breaking flag.
  404. */
  405. if (_DtCvIsSegRegion(pSeg))
  406. {
  407. if (_DtCvIsSegNonBreakingChar(pSeg))
  408. return False;
  409. return True;
  410. }
  411. /*
  412. * so, to get this far, this is a string segment.
  413. *
  414. * Problems with indexing?
  415. */
  416. if (str_len <= 0)
  417. return True;
  418. /*
  419. * do we need to check the last character in the string?
  420. * If skip_hypen_ck is true, it means that 'lastChar' would be a hypen.
  421. */
  422. if (False == skip_hypen_ck)
  423. {
  424. /*
  425. * this region is a string, get its string information.
  426. */
  427. lastChar = _DtCvChar(pChar, wcFlag, str_len - 1);
  428. /*
  429. * check to make sure the last character is a valid last
  430. * character.
  431. */
  432. if (' ' == lastChar || '-' == lastChar)
  433. return True;
  434. /*
  435. * If this string is a multi-byte, check the list of multi-bytes
  436. * that can't end a line. If one is found it can't end a line.
  437. */
  438. if ((wcFlag || canvas->mb_length > 1) &&
  439. CheckList(lastChar, canvas->locale.cant_end_chars) == True)
  440. return False;
  441. /*
  442. * so at the end of these tests, the last character is
  443. * -) not a blank.
  444. * -) not a hypen.
  445. * -) either a single byte character or multibyte character
  446. * that can end the line (including a single byte in
  447. * wide char form).
  448. *
  449. * set the flag for the type of character lastChar is.
  450. * if skip_hypen_ck was True, then lstCharMb remains False
  451. * which is logical since it means that the caller has already
  452. * processed a hypen (a single byte character).
  453. */
  454. lstCharMb = IsTrueMultiByte(lastChar);
  455. }
  456. /*
  457. * Check for more characters in the string and
  458. * check its next character for breakable space.
  459. */
  460. if (myStrLen > str_len)
  461. {
  462. /*
  463. * go to the next character.
  464. */
  465. nextChar = _DtCvChar(pChar, wcFlag, str_len);
  466. /*
  467. * Is it a valid break point?
  468. */
  469. if (' ' == nextChar)
  470. return True;
  471. /*
  472. * set the multibyte flag for the next character
  473. */
  474. nxtCharMb = IsTrueMultiByte(nextChar);
  475. /*
  476. * If this is wide char string, check the list of multi-byte
  477. * that can't begin a line.
  478. *
  479. * But only if the last character wasn't a hypen! Otherwise
  480. * it's a character after a hypen and should not be broken on.
  481. *
  482. * if this character is in the 'cannot begin line' list, then it
  483. * can't be broken on (a return value of true). (A wide char
  484. * encoding of a single byte character should come back as False
  485. * as long as the character is not in the list.)
  486. *
  487. * Have to double check to make sure it is a multibyte
  488. * character (want it to go through the CheckMulti list just in
  489. * case it's specified in there, before eliminating it).
  490. */
  491. if (False == skip_hypen_ck && (wcFlag || canvas->mb_length > 1)
  492. && CheckList(nextChar,canvas->locale.cant_begin_chars) == False
  493. && True == nxtCharMb)
  494. return True;
  495. /*
  496. * either the character is after a hypen (starting a line) OR it
  497. * is a multibyte character in the 'cannot begin a line' list OR
  498. * it is a single byte character. Therefore, this is a
  499. * nonbreakable character.
  500. */
  501. return False;
  502. }
  503. /*
  504. * We were at the last character of the string.
  505. * go to the next segment and see if it can start a new line.
  506. */
  507. do
  508. {
  509. pSeg = pSeg->next_seg;
  510. } while (pSeg != NULL && (_DtCvIsSegMarker(pSeg) ||
  511. (_DtCvIsSegNoop (pSeg) && !(_DtCvIsSegNewLine(pSeg)))));
  512. /*
  513. * If there isn't another valid segment, then the original segment
  514. * can end the line.
  515. */
  516. if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
  517. return True;
  518. /*
  519. * if the last if fell through, then pSeg is a string or region.
  520. * check to see if you can break on it.
  521. */
  522. if (_DtCvIsSegNonBreakingChar(pSeg))
  523. return False;
  524. /*
  525. * if the last if fell through, then this is a breaking string or
  526. * region. Therefore, if a region, you can break on it.
  527. */
  528. if (_DtCvIsSegRegion(pSeg))
  529. return True;
  530. /*
  531. * To get this far, the next segment must be a string. Check the
  532. * first character of the string to see if it can start a new line.
  533. */
  534. nextChar = _DtCvChar(_DtCvStringOfStringSeg(pSeg),
  535. _DtCvIsSegWideChar(pSeg), 0);
  536. if (' ' == nextChar)
  537. return True;
  538. /*
  539. * If the previous character was a single byte character (or a hypen),
  540. * it couldn't end a line. If this is a single byte string, then
  541. * this string can't start a line......
  542. */
  543. if (_DtCvIsSegRegChar(pSeg) &&
  544. (True == skip_hypen_ck || False == lstCharMb))
  545. return False;
  546. /*
  547. * If this is multi-byte, check the list of multi-byte
  548. * that can't begin a line.
  549. */
  550. if (_DtCvIsSegWideChar(pSeg) || canvas->mb_length > 1)
  551. {
  552. /*
  553. * plus checking the 'can not begin a line' list, check
  554. * if the previous character was a hypen, then this can't be
  555. * broken on either.
  556. */
  557. if (True == skip_hypen_ck ||
  558. CheckList(nextChar, canvas->locale.cant_begin_chars) == True)
  559. return False;
  560. /*
  561. * if the previous character was a multi-byte and this
  562. * character is a multibyte, then it is a valid break.
  563. */
  564. nxtCharMb = IsTrueMultiByte(nextChar);
  565. if (True == lstCharMb && True == nxtCharMb)
  566. return True;
  567. }
  568. /*
  569. * if the last character was a single byte character, then there
  570. * is still more to check - 1 byte punctuation around multi-byte.
  571. */
  572. if (False == lstCharMb &&
  573. _DtCvCheckOneByteCantEndList((char)lastChar,OneByteCantEndList) == True)
  574. return False;
  575. /*
  576. * or was the last character a multibyte and is followed by single byte
  577. * punctuation?
  578. */
  579. if (True == lstCharMb && False == nxtCharMb &&
  580. _DtCvCheckOneByteCantBeginList((char)nextChar, OneByteCantBeginList)
  581. == True)
  582. return False;
  583. return True;
  584. }
  585. /******************************************************************************
  586. * Function: _DtCvGetNextWidth
  587. *
  588. * Purpose: Determines the width of the next legal segment.
  589. *
  590. * Returns: The width of the next legal segment.
  591. *
  592. *****************************************************************************/
  593. int
  594. _DtCvGetNextWidth (
  595. _DtCanvasStruct *canvas,
  596. int old_type,
  597. int lst_hyper,
  598. _DtCvSegmentI *pSeg,
  599. int start,
  600. _DtCvSegmentI *prev_seg,
  601. _DtCvSegmentI **nextSeg,
  602. int *nextStart,
  603. int *widthCount)
  604. {
  605. int result;
  606. int len = 0;
  607. int mbl;
  608. int tLen;
  609. int wcFlag;
  610. int curWidth;
  611. int myLength;
  612. int nextLen = 0;
  613. void *pChar;
  614. char *tChar;
  615. _DtCvValue good_len;
  616. /*
  617. * pass over noops that don't have newlines and markers
  618. */
  619. while (pSeg != NULL && (_DtCvIsSegMarker(pSeg) ||
  620. (_DtCvIsSegNoop (pSeg) && !(_DtCvIsSegNewLine(pSeg)))))
  621. {
  622. pSeg = pSeg->next_seg;
  623. start = 0;
  624. }
  625. if (nextSeg != NULL)
  626. *nextSeg = pSeg;
  627. if (nextStart != NULL)
  628. *nextStart = start;
  629. /*
  630. * if the next segment is null or anything else but a string or region;
  631. * return that there is no more after this segment.
  632. */
  633. if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
  634. return 0;
  635. /*
  636. * this segment is a region or string
  637. * check for region...anything left is a string.
  638. */
  639. if (_DtCvIsSegRegion(pSeg))
  640. {
  641. /*
  642. * can I break on this region
  643. */
  644. if (_DtCvIsSegNonBreakingChar(pSeg))
  645. {
  646. /*
  647. * no...set the lengths and continue
  648. */
  649. len = 1;
  650. curWidth = _DtCvWidthOfRegionSeg(pSeg);
  651. }
  652. else
  653. return 0;
  654. }
  655. /*
  656. * is this a non breaking string?
  657. */
  658. else if (_DtCvIsSegNonBreakingChar(pSeg))
  659. {
  660. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  661. _DtCvIsSegWideChar(pSeg), start);
  662. len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
  663. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  664. + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
  665. }
  666. /*
  667. * so this is a string with possible breaks in it.
  668. */
  669. else
  670. {
  671. /*
  672. * get the string stats
  673. */
  674. wcFlag = _DtCvIsSegWideChar (pSeg);
  675. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg), wcFlag, start);
  676. myLength = _DtCvStrLen (pChar, wcFlag);
  677. /*
  678. * if a single byte string, zoom through it looking for
  679. * specific breaking characters.
  680. */
  681. if (0 == wcFlag && canvas->mb_length == 1)
  682. {
  683. tChar = pChar;
  684. len = 0;
  685. do
  686. {
  687. /*
  688. * checking for a hypen or space
  689. */
  690. good_len = True;
  691. result = _DtCvStrcspn ((void *) tChar, " -", 0, &tLen);
  692. len += tLen;
  693. /*
  694. * check for '-'. Some of the possible combinations are:
  695. * -text
  696. * - text
  697. * -/text/
  698. * text/-text/
  699. * text-text
  700. * text text
  701. *
  702. * if it is the first character to check and there is no
  703. * previous segment, then it is starting a line and can
  704. * not be broken on.
  705. *
  706. * _DtCvStrcpn return 0 if one of the characters in the
  707. * test string was found.
  708. */
  709. if (0 == result && '-' == tChar[tLen] && 0 == len &&
  710. NULL == prev_seg &&
  711. _DtCvCheckLineSyntax(canvas,pSeg,start,1,True) == False)
  712. {
  713. len++;
  714. tLen++;
  715. tChar += tLen;
  716. good_len = False;
  717. }
  718. } while (!good_len);
  719. /*
  720. * found either a space or a hypen or null byte.
  721. * If we found a hypen, include it.
  722. */
  723. if ('-' == *tChar)
  724. len++;
  725. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  726. + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
  727. /*
  728. * Did we find a space or hypen?
  729. * If not, can this segment stand alone?
  730. */
  731. if (result == 0 ||
  732. _DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
  733. {
  734. if (nextSeg != NULL)
  735. *nextSeg = pSeg;
  736. if (nextStart != NULL)
  737. *nextStart = start + len;
  738. if (widthCount != NULL)
  739. *widthCount = len;
  740. return curWidth;
  741. }
  742. }
  743. /*
  744. * multibyte (wide char string), look for a break the hard way.
  745. */
  746. else
  747. {
  748. len = 0;
  749. while (len < myLength)
  750. {
  751. if (wcFlag) len++;
  752. else
  753. {
  754. mbl = mblen(pChar + len, MB_CUR_MAX);
  755. if (mbl == -1)
  756. {
  757. ++len;
  758. continue;
  759. }
  760. else if (!mbl) break;
  761. else len += mbl;
  762. }
  763. if (_DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
  764. {
  765. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  766. _DtCvIsSegWideChar(pSeg), start);
  767. curWidth = _DtCvGetStringWidth(canvas,pSeg,pChar,len)
  768. + _DtCvGetTraversalWidth(canvas,pSeg,lst_hyper);
  769. if (nextSeg != NULL)
  770. *nextSeg = pSeg;
  771. if (nextStart != NULL)
  772. *nextStart = start + len;
  773. if (widthCount != NULL)
  774. *widthCount = len;
  775. return curWidth;
  776. }
  777. }
  778. /*
  779. * Didn't find a smaller segment that satisfied the requirements.
  780. * Determine the length of the current segment.
  781. */
  782. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  783. + _DtCvGetTraversalWidth(canvas, pSeg,
  784. lst_hyper);
  785. }
  786. }
  787. /*
  788. * sigh...need to go further...this segment can't end a line
  789. * either.
  790. */
  791. prev_seg = pSeg;
  792. pSeg = pSeg->next_seg;
  793. if (pSeg != NULL)
  794. {
  795. start = 0;
  796. curWidth += _DtCvGetNextWidth (canvas,
  797. _DtCvPrimaryTypeOfSeg (prev_seg), lst_hyper,
  798. pSeg, start, prev_seg,
  799. nextSeg, nextStart, &nextLen);
  800. }
  801. if (widthCount != NULL)
  802. *widthCount = len + nextLen;
  803. return (curWidth);
  804. }
  805. /******************************************************************************
  806. * Function: _DtCvSaveInfo
  807. *
  808. * Initializes a line table element to the segment it should display.
  809. *****************************************************************************/
  810. void
  811. _DtCvSaveInfo (
  812. _DtCanvasStruct *canvas,
  813. _DtCvLayoutInfo *layout,
  814. _DtCvUnit max_width,
  815. _DtCvUnit r_margin,
  816. _DtCvFrmtOption txt_justify)
  817. {
  818. /*****************************************************************
  819. * The ascent for a line is described as the number of units
  820. * above the baseline.
  821. *
  822. * The descent for a line is described as the number of units
  823. * below the baseline.
  824. *
  825. * Neither the ascent or decent value includes the baseline
  826. ****************************************************************/
  827. int len;
  828. int start = layout->line_start;
  829. int count = layout->line_bytes;
  830. long txtCnt = canvas->txt_cnt;
  831. _DtCvUnit maxAscent = 0;
  832. _DtCvUnit maxDescent = 0;
  833. _DtCvUnit maxRegion = 0;
  834. _DtCvUnit superY = 0;
  835. _DtCvUnit subY = 0;
  836. _DtCvUnit fontAscent;
  837. _DtCvUnit fontDescent;
  838. _DtCvValue fndLnk = False;
  839. _DtCvValue visLnk = False;
  840. void *pChar;
  841. _DtCvSegmentI *pSeg = layout->line_seg;
  842. if (txtCnt >= canvas->txt_max)
  843. {
  844. canvas->txt_max += GROW_SIZE;
  845. if (canvas->txt_lst)
  846. canvas->txt_lst = (_DtCvDspLine *) realloc (
  847. (void *) canvas->txt_lst,
  848. (sizeof(_DtCvDspLine) * canvas->txt_max));
  849. else
  850. canvas->txt_lst = (_DtCvDspLine *) malloc (
  851. (sizeof(_DtCvDspLine) * canvas->txt_max));
  852. /*
  853. * NOTE....should this routine return a value?
  854. * If (re)alloc error occurs, this simply ignores the problem.
  855. */
  856. if (canvas->txt_lst == NULL)
  857. {
  858. canvas->txt_max = 0;
  859. canvas->txt_cnt = 0;
  860. return;
  861. }
  862. }
  863. while (pSeg != NULL && count > 0)
  864. {
  865. /*
  866. * set which line will this segment sit on, iff this is the
  867. * first access to the segment.
  868. */
  869. if ((void *) -1 == pSeg->internal_use)
  870. pSeg->internal_use = (void *) txtCnt;
  871. /*
  872. * now get the segment's sizing so we can determine
  873. * the height and depth of the line.
  874. */
  875. len = 1;
  876. fontAscent = 0;
  877. fontDescent = 0;
  878. if (_DtCvIsSegVisibleLink(pSeg))
  879. visLnk = True;
  880. if (_DtCvIsSegALink(pSeg))
  881. fndLnk = True;
  882. /*
  883. * get the ascent and descent of the segment along with a length
  884. */
  885. if (_DtCvIsSegString(pSeg))
  886. {
  887. _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
  888. &fontAscent, &fontDescent, NULL, NULL, NULL);
  889. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  890. _DtCvIsSegWideChar(pSeg), start);
  891. len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
  892. if (len > count)
  893. len = count;
  894. }
  895. else if (_DtCvIsSegRegion(pSeg))
  896. {
  897. if (-1 == _DtCvAscentOfRegionSeg(pSeg))
  898. {
  899. if (maxRegion < _DtCvHeightOfRegionSeg(pSeg))
  900. maxRegion = _DtCvHeightOfRegionSeg(pSeg);
  901. }
  902. else
  903. {
  904. fontAscent = _DtCvAscentOfRegionSeg(pSeg);
  905. fontDescent = _DtCvHeightOfRegionSeg(pSeg) - fontAscent;
  906. }
  907. }
  908. /*
  909. * adjust the ascent and descent values by their subscript
  910. * or superscript adjustments.
  911. */
  912. if (_DtCvIsSegSuperScript(pSeg))
  913. {
  914. fontAscent += superY;
  915. fontDescent -= superY;
  916. if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
  917. && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + superY)
  918. maxRegion = _DtCvHeightOfRegionSeg(pSeg) + superY;
  919. }
  920. else if (_DtCvIsSegSubScript(pSeg))
  921. {
  922. fontAscent -= subY;
  923. fontDescent += subY;
  924. if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
  925. && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + subY)
  926. maxRegion = _DtCvHeightOfRegionSeg(pSeg) + subY;
  927. }
  928. else /* not a subscript or superscript */
  929. {
  930. /*
  931. * set up the super and sub script offsets for following
  932. * segments.
  933. */
  934. if (_DtCvIsSegString (pSeg))
  935. _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
  936. NULL, NULL, NULL, &superY, &subY);
  937. else if (_DtCvIsSegRegion(pSeg))
  938. {
  939. superY = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
  940. subY = superY;
  941. }
  942. }
  943. /*
  944. * now determine the maximums for ascent and descent.
  945. */
  946. if (fontAscent > maxAscent)
  947. maxAscent = fontAscent;
  948. if (fontDescent > maxDescent)
  949. maxDescent = fontDescent;
  950. /*
  951. * decrement the count
  952. */
  953. count -= len;
  954. /*
  955. * If this segment terminates the paragraph
  956. * force the end of the loop.
  957. */
  958. pSeg = pSeg->next_disp;
  959. start = 0;
  960. }
  961. if (txt_justify == _DtCvJUSTIFY_RIGHT || _DtCvJUSTIFY_CENTER == txt_justify)
  962. {
  963. /*
  964. * justify the line.
  965. */
  966. _DtCvUnit workWidth = max_width - layout->text_x_pos -
  967. r_margin - layout->cur_len;
  968. if (txt_justify == _DtCvJUSTIFY_CENTER)
  969. workWidth = workWidth / 2;
  970. if (workWidth < 0)
  971. workWidth = 0;
  972. layout->text_x_pos += workWidth;
  973. }
  974. /*
  975. * adjust for any special characters found
  976. */
  977. if (maxRegion > maxAscent + maxDescent + 1)
  978. maxAscent = maxRegion - maxDescent - 1;
  979. /*
  980. * check to see if the max values have even been touched.
  981. */
  982. if (layout->line_bytes == 0 && maxAscent == 0 && maxDescent == 0)
  983. maxAscent = canvas->metrics.line_height;
  984. /*
  985. * adjust ascent and descent by the traversal and link info
  986. */
  987. maxDescent += layout->leading;
  988. if (fndLnk)
  989. {
  990. maxAscent += canvas->traversal_info.space_above;
  991. maxDescent += canvas->traversal_info.space_below;
  992. if (visLnk)
  993. {
  994. maxAscent += canvas->link_info.space_above;
  995. maxDescent += canvas->link_info.space_below;
  996. }
  997. }
  998. /*
  999. * save the line information, if there is a string here.
  1000. */
  1001. if (layout->line_bytes > 0)
  1002. {
  1003. canvas->txt_lst[txtCnt].processed = _DtCvFALSE;
  1004. canvas->txt_lst[txtCnt].text_x = layout->text_x_pos;
  1005. canvas->txt_lst[txtCnt].max_x = layout->text_x_pos;
  1006. canvas->txt_lst[txtCnt].baseline = layout->y_pos + maxAscent;
  1007. canvas->txt_lst[txtCnt].descent = maxDescent;
  1008. canvas->txt_lst[txtCnt].ascent = maxAscent;
  1009. canvas->txt_lst[txtCnt].byte_index = layout->line_start;
  1010. canvas->txt_lst[txtCnt].length = layout->line_bytes;
  1011. canvas->txt_lst[txtCnt].seg_ptr = layout->line_seg;
  1012. canvas->txt_cnt++;
  1013. }
  1014. /*
  1015. * blank line is one half the normal size line
  1016. */
  1017. else
  1018. {
  1019. maxAscent = (maxAscent + maxDescent) / 2;
  1020. maxDescent = 0;
  1021. }
  1022. if (layout->text_x_pos + layout->cur_len > layout->cur_max_x)
  1023. layout->cur_max_x = layout->text_x_pos + layout->cur_len;
  1024. if (layout->text_x_pos + layout->cur_len > layout->max_x_pos)
  1025. layout->max_x_pos = layout->text_x_pos + layout->cur_len;
  1026. /*
  1027. * zero the string info
  1028. */
  1029. layout->line_bytes = 0;
  1030. layout->cur_len = 0;
  1031. layout->lst_hyper = -1;
  1032. layout->lst_vis = False;
  1033. _DtCvSetJoinInfo(layout, False, -1);
  1034. /*
  1035. * adjust where the next line is positioned.
  1036. */
  1037. layout->y_pos = layout->y_pos + maxAscent + maxDescent + 1;
  1038. }
  1039. /******************************************************************************
  1040. * Function: _DtCvCheckAddHyperToTravList
  1041. *
  1042. *****************************************************************************/
  1043. void
  1044. _DtCvCheckAddHyperToTravList (
  1045. _DtCanvasStruct *canvas,
  1046. _DtCvSegmentI *p_seg,
  1047. _DtCvValue flag,
  1048. _DtCvValue *lst_vis,
  1049. int *lst_hyper,
  1050. _DtCvUnit *cur_len)
  1051. {
  1052. int nxtHyper;
  1053. int prevIdx;
  1054. _DtCvValue junk;
  1055. _DtCvUnit retLen = *cur_len;
  1056. if (_DtCvIsSegALink (p_seg))
  1057. {
  1058. nxtHyper = _DtCvGetNextTravEntry(canvas);
  1059. if (-1 == nxtHyper)
  1060. /*
  1061. * NOTE....should this routine return a value?
  1062. * If (re)alloc error occurs, this simply ignores the problem.
  1063. */
  1064. return;
  1065. prevIdx = nxtHyper - 1;
  1066. if (prevIdx < 0
  1067. || _DtCvTraversalLink != canvas->trav_lst[prevIdx].type
  1068. || p_seg->link_idx != canvas->trav_lst[prevIdx].seg_ptr->link_idx)
  1069. {
  1070. /*
  1071. * save this hypertext link in the traversal list
  1072. */
  1073. _DtCvSetTravEntryInfo (canvas, nxtHyper, _DtCvTraversalLink, p_seg,
  1074. canvas->txt_cnt, _DtCvTRUE);
  1075. }
  1076. }
  1077. /*
  1078. * take into account the link metrics.
  1079. */
  1080. junk = _DtCvIsSegVisibleLink(p_seg);
  1081. *lst_vis = _DtCvModifyXpos(canvas->link_info, p_seg, junk,
  1082. *lst_vis, *lst_hyper,
  1083. &retLen);
  1084. /*
  1085. * take into account the traversal metrics
  1086. */
  1087. junk = _DtCvIsSegALink(p_seg);
  1088. (void) _DtCvModifyXpos(canvas->traversal_info, p_seg, junk,
  1089. ((_DtCvValue) True), *lst_hyper,
  1090. &retLen);
  1091. *lst_hyper = p_seg->link_idx;
  1092. if (_DtCvTRUE == flag)
  1093. *cur_len = retLen;
  1094. }
  1095. /******************************************************************************
  1096. * Function: ProcessStringSegment
  1097. *
  1098. * chops a string segment up until its completely used.
  1099. *
  1100. * Returns:
  1101. * 0 if the entire string segment was processed.
  1102. * 1 if the required number of lines were processed.
  1103. *****************************************************************************/
  1104. int
  1105. _DtCvProcessStringSegment(
  1106. _DtCanvasStruct *canvas,
  1107. _DtCvLayoutInfo *lay_info,
  1108. _DtCvUnit max_width,
  1109. _DtCvUnit l_margin,
  1110. _DtCvUnit r_margin,
  1111. _DtCvSegmentI *cur_seg,
  1112. unsigned int *cur_start,
  1113. _DtCvFrmtOption txt_justify,
  1114. _DtCvValue stat_flag)
  1115. {
  1116. _DtCvUnit workWidth;
  1117. _DtCvUnit stringLen;
  1118. _DtCvUnit textWidth;
  1119. _DtCvUnit nWidth;
  1120. _DtCvUnit spaceSize = 0;
  1121. int oldType;
  1122. int retStart;
  1123. int retCount;
  1124. wchar_t *wcp;
  1125. void *pChar;
  1126. char *strPtr;
  1127. _DtCvValue done = False;
  1128. _DtCvSegmentI *retSeg;
  1129. if (NULL != _DtCvStringOfStringSeg(cur_seg))
  1130. {
  1131. if (lay_info->cur_len == 0)
  1132. {
  1133. lay_info->line_seg = cur_seg;
  1134. lay_info->line_start = *cur_start;
  1135. }
  1136. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1137. lay_info->delayed_search_saves++;
  1138. oldType = _DtCvPrimaryTypeOfSeg (cur_seg);
  1139. /*
  1140. * is alignment in effect?
  1141. */
  1142. if (TRUE == lay_info->align_flag)
  1143. {
  1144. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1145. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1146. nWidth = _DtCvStrcspn (pChar, lay_info->align_char,
  1147. _DtCvIsSegWideChar(cur_seg),
  1148. &stringLen);
  1149. if (-1 == nWidth)
  1150. return -1;
  1151. /*
  1152. * we got a valid length back, calculate the length
  1153. */
  1154. textWidth = 0;
  1155. if (0 != stringLen)
  1156. textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen);
  1157. /*
  1158. * check to see if this a hypertext that needs
  1159. * to be remembered.
  1160. */
  1161. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1162. &(lay_info->lst_vis),
  1163. &(lay_info->lst_hyper),
  1164. &(lay_info->cur_len));
  1165. /*
  1166. * update the length and position information
  1167. * to skip past the characters before the alignment character.
  1168. */
  1169. lay_info->line_bytes += stringLen;
  1170. lay_info->cur_len += (textWidth
  1171. + _DtCvGetTraversalWidth(canvas,
  1172. cur_seg, lay_info->lst_hyper));
  1173. *cur_start += stringLen;
  1174. /*
  1175. * if we didn't find the character, check to see if this forces
  1176. * a newline - honor it if it does. We'll check the next
  1177. * string segment for the alignment character.
  1178. */
  1179. if (1 == nWidth && _DtCvIsSegNewLine (cur_seg)
  1180. && lay_info->line_bytes)
  1181. {
  1182. _DtCvSaveInfo (canvas,lay_info,max_width,r_margin,txt_justify);
  1183. while (lay_info->delayed_search_saves > 0) {
  1184. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1185. lay_info->delayed_search_saves--;
  1186. }
  1187. return 0;
  1188. }
  1189. /*
  1190. * so we found the character, now get it's width.
  1191. */
  1192. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1193. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1194. textWidth = _DtCvGetStringWidth(canvas, cur_seg, pChar, 1)
  1195. + _DtCvGetTraversalWidth(canvas, cur_seg,
  1196. lay_info->lst_hyper);
  1197. /*
  1198. * is this the second or more align position?
  1199. * if so, need to shift the character to align with others.
  1200. */
  1201. if (lay_info->align_pos >
  1202. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
  1203. lay_info->text_x_pos = lay_info->align_pos - lay_info->cur_len
  1204. - textWidth / 2;
  1205. /*
  1206. * otherwise, does this exceed the previous alignments?
  1207. * if so, the table processing should catch that we've
  1208. * changed the alignment position and re-format the others.
  1209. */
  1210. else if (lay_info->align_pos <
  1211. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
  1212. lay_info->align_pos =
  1213. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2;
  1214. /*
  1215. * indicate that the character has been found.
  1216. */
  1217. lay_info->align_flag = False;
  1218. /*
  1219. * check to see if this item can end a line.
  1220. * if can't end the line, force a join for the next segment or
  1221. * for the rest of this segment.
  1222. */
  1223. if (False == _DtCvCheckLineSyntax(canvas,cur_seg,*cur_start,1,False))
  1224. lay_info->join = True;
  1225. /*
  1226. * update the length and position information to
  1227. * include the character.
  1228. */
  1229. lay_info->line_bytes++;
  1230. lay_info->cur_len += textWidth;
  1231. *cur_start += 1;
  1232. /*
  1233. * check to see if this is the end of the segment.
  1234. */
  1235. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1236. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1237. if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
  1238. ||
  1239. (_DtCvIsSegRegChar(cur_seg) && '\0' == *((char *) pChar)))
  1240. return 0;
  1241. }
  1242. while (1)
  1243. {
  1244. /*
  1245. * recalculate the width
  1246. */
  1247. workWidth = max_width - lay_info->text_x_pos -
  1248. lay_info->cur_len - r_margin;
  1249. /*
  1250. * adjust the character pointer and get the
  1251. * length of the string.
  1252. */
  1253. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1254. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1255. stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
  1256. /*
  1257. * get the pixel width of the text string.
  1258. */
  1259. textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen)
  1260. + _DtCvGetTraversalWidth(canvas, cur_seg,
  1261. lay_info->lst_hyper);
  1262. /*
  1263. * Will it fit in the current width?
  1264. */
  1265. if (stat_flag == True || textWidth <= workWidth)
  1266. {
  1267. /*
  1268. * Yes, this segment or part of a segment can fit in the
  1269. * current width. But can the last character of this
  1270. * segment end a line and can the beginning of the next
  1271. * segment start a new line?
  1272. */
  1273. if (stat_flag == True ||
  1274. _DtCvCheckLineSyntax (canvas, cur_seg,
  1275. *cur_start, stringLen, False) == TRUE)
  1276. {
  1277. /*
  1278. * check to see if this a hypertext that needs
  1279. * to be remembered.
  1280. */
  1281. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1282. &(lay_info->lst_vis),
  1283. &(lay_info->lst_hyper),
  1284. &(lay_info->cur_len));
  1285. /*
  1286. * The line syntax is good.
  1287. * Update the global and width variables.
  1288. */
  1289. lay_info->line_bytes += stringLen;
  1290. lay_info->cur_len += textWidth;
  1291. _DtCvSetJoinInfo(lay_info,
  1292. _DtCvIsSegNonBreakingChar(cur_seg),
  1293. -1);
  1294. /*
  1295. * Check to see if this segment forces an end
  1296. */
  1297. if (_DtCvIsSegNewLine (cur_seg) && lay_info->line_bytes) {
  1298. _DtCvSaveInfo (canvas, lay_info, max_width,
  1299. r_margin, txt_justify);
  1300. while (lay_info->delayed_search_saves > 0) {
  1301. _DtCvSetSearchEntryInfo(canvas,
  1302. canvas->txt_cnt - 1);
  1303. lay_info->delayed_search_saves--;
  1304. }
  1305. }
  1306. return 0;
  1307. }
  1308. /*
  1309. * CheckLineSyntax says that either this line couldn't
  1310. * end a line or the next segment couldn't start a line.
  1311. * Therefore, find out how much of the next segment or
  1312. * segments we need to incorporate to satisfy the Line
  1313. * Syntax rules.
  1314. */
  1315. nWidth = _DtCvGetNextWidth (canvas, oldType,
  1316. lay_info->lst_hyper,
  1317. cur_seg->next_seg, 0, cur_seg,
  1318. &retSeg, &retStart, &retCount);
  1319. /*
  1320. * will this segment + the next segment fit?
  1321. */
  1322. if (textWidth + nWidth <= workWidth)
  1323. {
  1324. /*
  1325. * check to see if this a hypertext that needs
  1326. * to be remembered.
  1327. */
  1328. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1329. &(lay_info->lst_vis),
  1330. &(lay_info->lst_hyper),
  1331. &(lay_info->cur_len));
  1332. /*
  1333. * YEAH Team!! It Fits!!
  1334. *
  1335. * Update the global and width variables.
  1336. */
  1337. lay_info->line_bytes += stringLen;
  1338. lay_info->cur_len += textWidth;
  1339. _DtCvSetJoinInfo(lay_info, False, -1);
  1340. return 0;
  1341. }
  1342. }
  1343. /*
  1344. * the text width plus the next segment is tooo big
  1345. * to fit. Reduce the current segment if possible
  1346. */
  1347. done = False;
  1348. textWidth = 0;
  1349. stringLen = 0;
  1350. while (!done)
  1351. {
  1352. nWidth = _DtCvGetNextWidth (canvas, oldType,
  1353. lay_info->lst_hyper,
  1354. cur_seg, *cur_start, NULL,
  1355. &retSeg, &retStart, &retCount);
  1356. if (retSeg == cur_seg && textWidth + nWidth <= workWidth)
  1357. {
  1358. /*
  1359. * check to see if this a hypertext that needs
  1360. * to be remembered.
  1361. */
  1362. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1363. &(lay_info->lst_vis),
  1364. &(lay_info->lst_hyper),
  1365. &(lay_info->cur_len));
  1366. _DtCvSetJoinInfo(lay_info, False, -1);
  1367. *cur_start = retStart;
  1368. stringLen += retCount;
  1369. textWidth += nWidth;
  1370. spaceSize = 0;
  1371. /*
  1372. * take into account a space if that is where it breaks.
  1373. */
  1374. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1375. _DtCvIsSegWideChar(cur_seg),
  1376. *cur_start);
  1377. if ((_DtCvIsSegWideChar(cur_seg) &&
  1378. (' ' == *((wchar_t *) pChar)))
  1379. ||
  1380. (_DtCvIsSegRegChar(cur_seg) &&
  1381. (' ' == *((char *) pChar))))
  1382. {
  1383. spaceSize = _DtCvGetStringWidth(canvas,
  1384. cur_seg, pChar, 1)
  1385. + _DtCvGetTraversalWidth (canvas,
  1386. cur_seg, lay_info->lst_hyper);
  1387. textWidth += spaceSize;
  1388. stringLen++;
  1389. (*cur_start)++;
  1390. }
  1391. }
  1392. else
  1393. {
  1394. /*
  1395. * Done trying to find a segment that will
  1396. * fit in the size given
  1397. */
  1398. done = True;
  1399. }
  1400. }
  1401. /*
  1402. * Update the global variables
  1403. */
  1404. lay_info->line_bytes += stringLen;
  1405. lay_info->cur_len += textWidth;
  1406. if (lay_info->join == True || lay_info->line_bytes == 0)
  1407. {
  1408. /*
  1409. * This line would be empty if we followed the rules.
  1410. * Or it would break a line improperly.
  1411. * Force this onto the line.
  1412. * check to see if this a hypertext that needs
  1413. * to be remembered.
  1414. */
  1415. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1416. &(lay_info->lst_vis),
  1417. &(lay_info->lst_hyper),
  1418. &(lay_info->cur_len));
  1419. /*
  1420. * Couldn't find a smaller, have to
  1421. * go with the larger segment.
  1422. */
  1423. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1424. _DtCvIsSegWideChar(cur_seg),
  1425. *cur_start);
  1426. stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
  1427. if (retCount > 0 && retCount < stringLen)
  1428. stringLen = retCount;
  1429. lay_info->line_bytes += stringLen;
  1430. lay_info->cur_len += (_DtCvGetStringWidth(canvas, cur_seg,
  1431. pChar, stringLen)
  1432. + _DtCvGetTraversalWidth (canvas,
  1433. cur_seg, lay_info->lst_hyper));
  1434. _DtCvSetJoinInfo(lay_info, False, -1);
  1435. /*
  1436. * If we had to do a bigger segment,
  1437. * then we're done processing the target segment.
  1438. */
  1439. if (stringLen == _DtCvStrLen(pChar,_DtCvIsSegWideChar(cur_seg)))
  1440. {
  1441. if (_DtCvCheckLineSyntax (canvas, cur_seg,
  1442. *cur_start, stringLen, False) == False)
  1443. _DtCvSetJoinInfo(lay_info, True, -1);
  1444. else if (_DtCvIsSegNewLine (cur_seg)) {
  1445. _DtCvSaveInfo (canvas, lay_info, max_width,
  1446. r_margin, txt_justify);
  1447. while (lay_info->delayed_search_saves > 0) {
  1448. _DtCvSetSearchEntryInfo(canvas,
  1449. canvas->txt_cnt - 1);
  1450. lay_info->delayed_search_saves--;
  1451. }
  1452. }
  1453. return 0;
  1454. }
  1455. *cur_start = retStart;
  1456. }
  1457. else if (spaceSize)
  1458. {
  1459. /*
  1460. * If a space was included as the last character,
  1461. * remove it now.
  1462. */
  1463. lay_info->line_bytes--;
  1464. lay_info->cur_len -= spaceSize;
  1465. }
  1466. /*
  1467. * Save the information
  1468. */
  1469. _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
  1470. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1471. lay_info->delayed_search_saves--;
  1472. while (lay_info->delayed_search_saves > 0) {
  1473. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1474. lay_info->delayed_search_saves--;
  1475. }
  1476. /*
  1477. * Skip the spaces.
  1478. */
  1479. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1480. _DtCvIsSegWideChar(cur_seg),
  1481. *cur_start);
  1482. if (_DtCvIsSegWideChar(cur_seg))
  1483. {
  1484. wcp = pChar;
  1485. while (' ' == *wcp)
  1486. {
  1487. wcp++;
  1488. (*cur_start)++;
  1489. }
  1490. pChar = wcp;
  1491. }
  1492. else /* single byte string */
  1493. {
  1494. strPtr = pChar;
  1495. while (' ' == *strPtr)
  1496. {
  1497. strPtr++;
  1498. (*cur_start)++;
  1499. }
  1500. pChar = strPtr;
  1501. }
  1502. /*
  1503. * are we at the end of the segment?
  1504. */
  1505. if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
  1506. ||
  1507. (_DtCvIsSegRegChar(cur_seg) && 0 == *((char *) pChar)))
  1508. return 0;
  1509. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1510. lay_info->delayed_search_saves++;
  1511. /*
  1512. * Initialize the global variables
  1513. */
  1514. lay_info->line_seg = cur_seg;
  1515. lay_info->line_start = *cur_start;
  1516. lay_info->text_x_pos = l_margin;
  1517. if (CheckFormat(lay_info) == True)
  1518. return 1;
  1519. /*
  1520. * check to see if this a hypertext that needs
  1521. * to be remembered.
  1522. */
  1523. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1524. &(lay_info->lst_vis),
  1525. &(lay_info->lst_hyper),
  1526. &(lay_info->cur_len));
  1527. }
  1528. }
  1529. else if (_DtCvIsSegNewLine (cur_seg))
  1530. {
  1531. /*
  1532. * Force a save - even if it is an empty line.
  1533. */
  1534. _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
  1535. while (lay_info->delayed_search_saves > 0) {
  1536. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1537. lay_info->delayed_search_saves--;
  1538. }
  1539. }
  1540. return 0;
  1541. } /* End _DtCvProcessStringSegment */
  1542. /******************************************************************************
  1543. * Function: _DtCvSetJoinInfo
  1544. *
  1545. * Returns: sets the joining information to the given information.
  1546. *
  1547. *****************************************************************************/
  1548. void
  1549. _DtCvSetJoinInfo (
  1550. _DtCvLayoutInfo *lay_info,
  1551. _DtCvValue flag,
  1552. int txt_ln)
  1553. {
  1554. lay_info->join = flag;
  1555. lay_info->join_line = txt_ln;
  1556. }
  1557. /******************************************************************************
  1558. * Function: _DtCvGetNextTravEntry
  1559. *
  1560. * Returns: >= 0 if success,
  1561. * -1 if failure.
  1562. *
  1563. * Purpose: Return the next available entry in the traversal list.
  1564. *
  1565. *****************************************************************************/
  1566. int
  1567. _DtCvGetNextTravEntry (
  1568. _DtCanvasStruct *canvas)
  1569. {
  1570. int nxtEntry = canvas->trav_cnt;
  1571. /*
  1572. * does the list need to grow?
  1573. */
  1574. if (nxtEntry >= canvas->trav_max)
  1575. {
  1576. /*
  1577. * grow by a set amount
  1578. */
  1579. canvas->trav_max += GROW_SIZE;
  1580. /*
  1581. * realloc or malloc?
  1582. */
  1583. if (NULL != canvas->trav_lst)
  1584. canvas->trav_lst = (_DtCvTraversalInfo *) realloc (
  1585. (char *) canvas->trav_lst,
  1586. ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
  1587. else
  1588. canvas->trav_lst = (_DtCvTraversalInfo *) malloc (
  1589. ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
  1590. /*
  1591. * did the memory allocation work? if not return error code.
  1592. */
  1593. if (NULL == canvas->trav_lst)
  1594. {
  1595. canvas->trav_max = 0;
  1596. canvas->trav_cnt = 0;
  1597. nxtEntry = -1;
  1598. }
  1599. }
  1600. canvas->trav_lst[nxtEntry] = DefTravData;
  1601. return nxtEntry;
  1602. }
  1603. /******************************************************************************
  1604. * Function: _DtCvSetTravEntryInfo
  1605. *
  1606. * Returns: 0 if success,
  1607. * -1 if failure.
  1608. *
  1609. * Purpose: Set the high level information in an entry of the traversal
  1610. * list.
  1611. *****************************************************************************/
  1612. int
  1613. _DtCvSetTravEntryInfo (
  1614. _DtCanvasStruct *canvas,
  1615. int entry,
  1616. _DtCvTraversalType type,
  1617. _DtCvSegmentI *p_seg,
  1618. int line_idx,
  1619. _DtCvValue inc)
  1620. {
  1621. int result = -1;
  1622. if (-1 != entry && entry <= canvas->trav_cnt)
  1623. {
  1624. _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
  1625. travEntry->type = type;
  1626. travEntry->seg_ptr = p_seg;
  1627. travEntry->idx = line_idx;
  1628. if (_DtCvTRUE == inc)
  1629. canvas->trav_cnt++;
  1630. result = 0;
  1631. }
  1632. return result;
  1633. }
  1634. int
  1635. _DtCvGetNextSearchEntry(_DtCanvasStruct* canvas)
  1636. {
  1637. if (canvas->search_cnt >= canvas->search_max) {
  1638. canvas->search_max += GROW_SIZE;
  1639. if (canvas->searchs)
  1640. canvas->searchs = (_DtCvSearchData *)
  1641. realloc((void*)canvas->searchs,
  1642. canvas->search_max * sizeof(_DtCvSearchData));
  1643. else
  1644. canvas->searchs = (_DtCvSearchData *)
  1645. malloc(canvas->search_max * sizeof(_DtCvSearchData));
  1646. }
  1647. canvas->searchs[canvas->search_cnt].idx = -1;
  1648. return canvas->search_cnt++;
  1649. }
  1650. void
  1651. _DtCvSetSearchEntryInfo(_DtCanvasStruct* canvas, int line_idx)
  1652. {
  1653. int search_idx;
  1654. /* get a next available slot for search */
  1655. search_idx = _DtCvGetNextSearchEntry(canvas);
  1656. /* save information (i.e. line_idx) */
  1657. canvas->searchs[search_idx].idx = line_idx;
  1658. }
  1659. /******************************************************************************
  1660. * Function: _DtCvSetTravEntryPos
  1661. *
  1662. * Returns: 0 if success,
  1663. * -1 if failure.
  1664. *
  1665. * Purpose: Set the position and dimension information of an entry in
  1666. * the traversal list.
  1667. *
  1668. *****************************************************************************/
  1669. int
  1670. _DtCvSetTravEntryPos (
  1671. _DtCanvasStruct *canvas,
  1672. int entry,
  1673. _DtCvUnit x,
  1674. _DtCvUnit y,
  1675. _DtCvUnit width,
  1676. _DtCvUnit height)
  1677. {
  1678. int result = -1;
  1679. if (-1 != entry && entry <= canvas->trav_cnt)
  1680. {
  1681. _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
  1682. travEntry->x_pos = x;
  1683. travEntry->y_pos = y;
  1684. travEntry->width = width;
  1685. travEntry->height = height;
  1686. result = 0;
  1687. }
  1688. return result;
  1689. }
  1690. /******************************************************************************
  1691. * Function: _DtCvCalcMarkPos
  1692. *
  1693. * Returns: 0 if success,
  1694. * -1 if failure.
  1695. *
  1696. * Purpose: Calcalate the position and dimension information of a mark.
  1697. *
  1698. *****************************************************************************/
  1699. int
  1700. _DtCvCalcMarkPos (
  1701. _DtCanvasStruct *canvas,
  1702. int entry,
  1703. _DtCvUnit *ret_x,
  1704. _DtCvUnit *ret_y,
  1705. _DtCvUnit *ret_width,
  1706. _DtCvUnit *ret_height)
  1707. {
  1708. int result = -1;
  1709. if (-1 != entry && entry <= canvas->mark_cnt)
  1710. {
  1711. _DtCvMarkData *mark = &(canvas->marks[entry]);
  1712. /*
  1713. * if we've got a line index for the mark, get the positions.
  1714. */
  1715. if (-1 != mark->beg.line_idx && -1 != mark->end.line_idx)
  1716. {
  1717. _DtCvDspLine *line = &(canvas->txt_lst[mark->beg.line_idx]);
  1718. *ret_x = mark->beg.x;
  1719. *ret_y = mark->beg.y - line->ascent;
  1720. if (mark->beg.line_idx == mark->end.line_idx)
  1721. *ret_width = mark->end.x - *ret_x;
  1722. else
  1723. *ret_width = canvas->txt_lst[mark->beg.line_idx].max_x - *ret_x;
  1724. *ret_height = line->ascent + line->descent + 1;
  1725. result = 0;
  1726. }
  1727. }
  1728. return result;
  1729. }
  1730. /******************************************************************************
  1731. * Function: _DtCvSortTraversalList
  1732. *
  1733. * Returns: nothing
  1734. *
  1735. * Purpose: Sort the traversal list
  1736. *
  1737. *****************************************************************************/
  1738. void
  1739. _DtCvSortTraversalList (
  1740. _DtCanvasStruct *canvas,
  1741. _DtCvValue retain)
  1742. {
  1743. int curTrav = canvas->cur_trav;
  1744. if (1 < canvas->trav_cnt)
  1745. {
  1746. /*
  1747. * indicate this is the current traversal
  1748. */
  1749. if (-1 != curTrav)
  1750. canvas->trav_lst[curTrav].active = retain;
  1751. /*
  1752. * sort the items.
  1753. */
  1754. qsort (canvas->trav_lst, canvas->trav_cnt, sizeof(_DtCvTraversalInfo),
  1755. CompareTraversalPos);
  1756. if (_DtCvTRUE == retain && -1 != curTrav &&
  1757. _DtCvFALSE == canvas->trav_lst[curTrav].active)
  1758. {
  1759. curTrav = 0;
  1760. while (_DtCvFALSE == canvas->trav_lst[curTrav].active)
  1761. curTrav++;
  1762. canvas->cur_trav = curTrav;
  1763. }
  1764. /*
  1765. * clear the active flag
  1766. */
  1767. if (-1 != curTrav)
  1768. canvas->trav_lst[curTrav].active = _DtCvFALSE;
  1769. }
  1770. }
  1771. /*****************************************************************************
  1772. * Function: _DtCvCvtSegsToPts()
  1773. *
  1774. * Purpose: Given a set of segments, determine the ending points.
  1775. *
  1776. *****************************************************************************/
  1777. _DtCvStatus
  1778. _DtCvCvtSegsToPts (
  1779. _DtCanvasStruct *canvas,
  1780. _DtCvSegPtsI **segs,
  1781. _DtCvSelectData *beg,
  1782. _DtCvSelectData *end,
  1783. _DtCvUnit *ret_y1,
  1784. _DtCvUnit *ret_y2,
  1785. _DtCvSegmentI **ret_seg)
  1786. {
  1787. int count;
  1788. int cnt;
  1789. int start;
  1790. int length;
  1791. long lineIdx;
  1792. int linkIdx = -1;
  1793. _DtCvValue lastVisLnk = _DtCvFALSE;
  1794. _DtCvUnit minY = -1;
  1795. _DtCvUnit maxY = 0;
  1796. _DtCvUnit startX;
  1797. _DtCvUnit endX;
  1798. _DtCvUnit segWidth;
  1799. _DtCvSegmentI *pSeg;
  1800. _DtCvSegmentI *saveSeg;
  1801. _DtCvSegmentI **retSeg;
  1802. _DtCvDspLine *lines = canvas->txt_lst;
  1803. _DtCvFlags result = _DtCvSTATUS_NONE;
  1804. _DtCvSelectData *tmpBeg;
  1805. _DtCvSelectData *tmpEnd;
  1806. _DtCvSelectData bReg;
  1807. _DtCvSelectData eReg;
  1808. /*
  1809. * initialize the structures.
  1810. */
  1811. bReg = DefSelectData;
  1812. eReg = DefSelectData;
  1813. *beg = DefSelectData;
  1814. *end = DefSelectData;
  1815. /*
  1816. * go through each segment and determine the starting positions.
  1817. */
  1818. while (NULL != *segs)
  1819. {
  1820. result = _DtCvSTATUS_OK;
  1821. /*
  1822. * what line is this segment on?
  1823. */
  1824. lineIdx = (long) ((*segs)->segment->internal_use);
  1825. /*
  1826. * get some information about the line
  1827. */
  1828. length = lines[lineIdx].length;
  1829. start = lines[lineIdx].byte_index;
  1830. startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
  1831. pSeg = lines[lineIdx].seg_ptr;
  1832. /*
  1833. * now skip the segments on this line that aren't in the data pt.
  1834. */
  1835. while (NULL != pSeg && pSeg != (*segs)->segment)
  1836. {
  1837. /*
  1838. * advance past any hypertext link offsets.
  1839. */
  1840. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1841. &linkIdx, &lastVisLnk);
  1842. /*
  1843. * we know that this is not the segment we are looking for,
  1844. * so go past it.
  1845. */
  1846. _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
  1847. &cnt, &segWidth, NULL);
  1848. /*
  1849. * skip the segment's width, decrease the overall length by
  1850. * the segment's count, reset the character start point and
  1851. * go to the next segment.
  1852. */
  1853. startX += segWidth;
  1854. length -= cnt;
  1855. start = 0;
  1856. pSeg = pSeg->next_disp;
  1857. }
  1858. /*
  1859. * This segment should be all or partially selected.
  1860. */
  1861. if (NULL == pSeg)
  1862. return _DtCvSTATUS_BAD;
  1863. /*
  1864. * now figure the start location.
  1865. */
  1866. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1867. &linkIdx, &lastVisLnk);
  1868. /*
  1869. * guarenteed that this is the *first* line that the segment
  1870. * exists on. Therefore, may have to go to another line for
  1871. * the correct offset
  1872. */
  1873. while (start + length < (*segs)->offset)
  1874. {
  1875. do { lineIdx++; } while (lineIdx < canvas->txt_cnt
  1876. && pSeg != lines[lineIdx].seg_ptr);
  1877. if (lineIdx >= canvas->txt_cnt)
  1878. return _DtCvSTATUS_BAD;
  1879. length = lines[lineIdx].length;
  1880. start = lines[lineIdx].byte_index;
  1881. startX = lines[lineIdx].text_x;
  1882. linkIdx = -1;
  1883. lastVisLnk = False;
  1884. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1885. &linkIdx, &lastVisLnk);
  1886. }
  1887. /*
  1888. * how many characters do we need to skip?
  1889. */
  1890. count = (*segs)->offset - start;
  1891. segWidth = 0;
  1892. if (0 < count)
  1893. _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
  1894. &cnt, &segWidth, NULL);
  1895. /*
  1896. * adjust the info by the width of the skipped characters.
  1897. */
  1898. start += count;
  1899. length -= count;
  1900. startX += segWidth;
  1901. /*
  1902. * is this a region? If so set the region information instead.
  1903. */
  1904. tmpBeg = beg;
  1905. tmpEnd = end;
  1906. retSeg = ret_seg;
  1907. if (_DtCvIsSegRegion((*segs)->segment))
  1908. {
  1909. tmpBeg = &bReg;
  1910. tmpEnd = &eReg;
  1911. retSeg = &saveSeg;
  1912. }
  1913. /*
  1914. * does this segment start the selection? text or region?
  1915. */
  1916. if (tmpBeg->x == -1 || tmpBeg->y > lines[lineIdx].baseline ||
  1917. (tmpBeg->line_idx == lineIdx && tmpBeg->x > startX))
  1918. {
  1919. tmpBeg->x = startX;
  1920. tmpBeg->y = lines[lineIdx].baseline;
  1921. tmpBeg->line_idx = lineIdx;
  1922. tmpBeg->char_idx = lines[lineIdx].length - length;
  1923. if (NULL != retSeg)
  1924. *retSeg = (*segs)->segment;
  1925. }
  1926. /*
  1927. * get the amount of this segment that is selected.
  1928. */
  1929. count = (*segs)->len;
  1930. /*
  1931. * is it longer than what's (left) on this line?
  1932. */
  1933. while (count > length)
  1934. {
  1935. /*
  1936. * go to the next line containing the segment
  1937. */
  1938. do {
  1939. /*
  1940. * does this line have the minium y?
  1941. */
  1942. if (minY == -1 ||
  1943. minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
  1944. minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
  1945. lineIdx++;
  1946. } while (lineIdx < canvas->txt_cnt
  1947. && pSeg != lines[lineIdx].seg_ptr);
  1948. /*
  1949. * did we run out of lines?
  1950. */
  1951. if (lineIdx >= canvas->txt_cnt)
  1952. return _DtCvSTATUS_BAD;
  1953. /*
  1954. * start over on this line
  1955. */
  1956. segWidth = 0;
  1957. /*
  1958. * get the true count to the next offset
  1959. */
  1960. cnt = lines[lineIdx].byte_index - start;
  1961. /*
  1962. * get the next lines starting info.
  1963. */
  1964. start = lines[lineIdx].byte_index;
  1965. length = lines[lineIdx].length;
  1966. startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
  1967. linkIdx = -1;
  1968. lastVisLnk = False;
  1969. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1970. &linkIdx, &lastVisLnk);
  1971. /*
  1972. * subtract the previous length
  1973. */
  1974. count -= cnt;
  1975. }
  1976. /*
  1977. * now go down the line, examining each segment.
  1978. */
  1979. while (0 < count)
  1980. {
  1981. /*
  1982. * findout how many characters are in the next segment, and its
  1983. * width.
  1984. */
  1985. _DtCvGetWidthOfSegment(canvas,pSeg,start,count,&cnt,&segWidth,NULL);
  1986. /*
  1987. * there are less than in the count, go to the next segment.
  1988. */
  1989. if (cnt < count)
  1990. {
  1991. pSeg = pSeg->next_disp;
  1992. start = 0;
  1993. startX += segWidth;
  1994. }
  1995. length -= cnt;
  1996. count -= cnt;
  1997. }
  1998. endX = startX + segWidth;
  1999. /*
  2000. * does this segment end a segment?
  2001. */
  2002. if (tmpEnd->x == -1 || tmpEnd->y < lines[lineIdx].baseline ||
  2003. (tmpEnd->line_idx == lineIdx && tmpEnd->x < endX))
  2004. {
  2005. tmpEnd->x = endX;
  2006. tmpEnd->y = lines[lineIdx].baseline;
  2007. tmpEnd->line_idx = lineIdx;
  2008. tmpEnd->char_idx = lines[lineIdx].length - length;
  2009. }
  2010. /*
  2011. * check for min and max values
  2012. */
  2013. if (minY == -1 ||
  2014. minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
  2015. minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
  2016. if (maxY < lines[lineIdx].baseline + lines[lineIdx].descent)
  2017. maxY = lines[lineIdx].baseline + lines[lineIdx].descent;
  2018. /*
  2019. * go to the next segment
  2020. */
  2021. segs++;
  2022. }
  2023. /*
  2024. * now determine if a region really starts the beginning of a
  2025. * selection or a text does.
  2026. *
  2027. * was a region found?
  2028. */
  2029. if (-1 != bReg.x)
  2030. {
  2031. /*
  2032. * if no text was found, take the region information.
  2033. */
  2034. if (-1 == beg->x)
  2035. {
  2036. *beg = bReg;
  2037. if (NULL != ret_seg)
  2038. *ret_seg = saveSeg;
  2039. }
  2040. /*
  2041. * or if the region is inline to the other
  2042. * text and it is before the text, then take it's x value.
  2043. */
  2044. else if (bReg.x < beg->x &&
  2045. (bReg.line_idx == beg->line_idx ||
  2046. /*
  2047. * Or if the region is 'standalone' (a bullet of a list, a
  2048. * graphic to wrap around, etc.) then check to see if it
  2049. * straddles the other information and is before the text. If
  2050. * it does, take it's x value.
  2051. */
  2052. _DtCvStraddlesPt(beg->y,
  2053. bReg.y - lines[bReg.line_idx].ascent,
  2054. bReg.y - lines[bReg.line_idx].descent)))
  2055. {
  2056. beg->x = bReg.x;
  2057. if (NULL != ret_seg)
  2058. *ret_seg = saveSeg;
  2059. }
  2060. }
  2061. /*
  2062. * now determine if a region really ends the selection or a text does.
  2063. *
  2064. * was a region found?
  2065. */
  2066. if (-1 != eReg.x)
  2067. {
  2068. /*
  2069. * if no text was found, take the region information.
  2070. */
  2071. if (-1 == end->x)
  2072. *end = eReg;
  2073. /*
  2074. * or if the region is inline to the other
  2075. * text and it is before the text, then take it's x value.
  2076. */
  2077. else if (eReg.x > end->x &&
  2078. (eReg.line_idx == end->line_idx ||
  2079. /*
  2080. * Or if the region is 'standalone' (a bullet of a list, a
  2081. * graphic to wrap around, etc.) then check to see if it
  2082. * straddles the other information and is before the text. If
  2083. * it does, take it's x value.
  2084. */
  2085. _DtCvStraddlesPt(end->y,
  2086. eReg.y - lines[eReg.line_idx].ascent,
  2087. eReg.y - lines[eReg.line_idx].descent)))
  2088. end->x = eReg.x;
  2089. }
  2090. if (NULL != ret_y1)
  2091. *ret_y1 = minY;
  2092. if (NULL != ret_y2)
  2093. *ret_y2 = maxY;
  2094. return result;
  2095. }
  2096. /*****************************************************************************
  2097. * Function: _DtCvAddToMarkList()
  2098. *
  2099. * Purpose: Add a mark to the list of marks.
  2100. *
  2101. *****************************************************************************/
  2102. int
  2103. _DtCvAddToMarkList (
  2104. _DtCanvasStruct *canvas,
  2105. _DtCvPointer client_data,
  2106. _DtCvValue flag,
  2107. _DtCvSelectData *beg,
  2108. _DtCvSelectData *end)
  2109. {
  2110. _DtCvMarkData *nxtMark;
  2111. /*
  2112. * does the array need more memory?
  2113. */
  2114. if (canvas->mark_cnt >= canvas->mark_max)
  2115. {
  2116. canvas->mark_max += GROW_SIZE;
  2117. if (NULL == canvas->marks)
  2118. canvas->marks = (_DtCvMarkData *) malloc(
  2119. sizeof(_DtCvMarkData) * canvas->mark_max);
  2120. else
  2121. canvas->marks = (_DtCvMarkData *) realloc((void *) canvas->marks,
  2122. sizeof(_DtCvMarkData) * canvas->mark_max);
  2123. /*
  2124. * memory loss - bail
  2125. */
  2126. if (NULL == canvas->marks)
  2127. return -1;
  2128. }
  2129. /*
  2130. * set the mark information
  2131. */
  2132. nxtMark = &(canvas->marks[canvas->mark_cnt]);
  2133. nxtMark->on = flag;
  2134. nxtMark->client_data = client_data;
  2135. nxtMark->beg = *beg;
  2136. nxtMark->end = *end;
  2137. canvas->mark_cnt++;
  2138. return (canvas->mark_cnt - 1);
  2139. }