LayoutUtil.c 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366
  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 &&
  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
  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))
  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 tLen;
  608. int wcFlag;
  609. int curWidth;
  610. int myLength;
  611. int nextLen = 0;
  612. void *pChar;
  613. char *tChar;
  614. _DtCvValue good_len;
  615. /*
  616. * pass over noops that don't have newlines and markers
  617. */
  618. while (pSeg != NULL && (_DtCvIsSegMarker(pSeg) ||
  619. (_DtCvIsSegNoop (pSeg) && !(_DtCvIsSegNewLine(pSeg)))))
  620. {
  621. pSeg = pSeg->next_seg;
  622. start = 0;
  623. }
  624. if (nextSeg != NULL)
  625. *nextSeg = pSeg;
  626. if (nextStart != NULL)
  627. *nextStart = start;
  628. /*
  629. * if the next segment is null or anything else but a string or region;
  630. * return that there is no more after this segment.
  631. */
  632. if (pSeg == NULL || !(_DtCvIsSegString(pSeg) || _DtCvIsSegRegion(pSeg)))
  633. return 0;
  634. /*
  635. * this segment is a region or string
  636. * check for region...anything left is a string.
  637. */
  638. if (_DtCvIsSegRegion(pSeg))
  639. {
  640. /*
  641. * can I break on this region
  642. */
  643. if (_DtCvIsSegNonBreakingChar(pSeg))
  644. {
  645. /*
  646. * no...set the lengths and continue
  647. */
  648. len = 1;
  649. curWidth = _DtCvWidthOfRegionSeg(pSeg);
  650. }
  651. else
  652. return 0;
  653. }
  654. /*
  655. * is this a non breaking string?
  656. */
  657. else if (_DtCvIsSegNonBreakingChar(pSeg))
  658. {
  659. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  660. _DtCvIsSegWideChar(pSeg), start);
  661. len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
  662. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  663. + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
  664. }
  665. /*
  666. * so this is a string with possible breaks in it.
  667. */
  668. else
  669. {
  670. /*
  671. * get the string stats
  672. */
  673. wcFlag = _DtCvIsSegWideChar (pSeg);
  674. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg), wcFlag, start);
  675. myLength = _DtCvStrLen (pChar, wcFlag);
  676. /*
  677. * if a single byte string, zoom through it looking for
  678. * specific breaking characters.
  679. */
  680. if (0 == wcFlag)
  681. {
  682. tChar = pChar;
  683. len = 0;
  684. do
  685. {
  686. /*
  687. * checking for a hypen or space
  688. */
  689. good_len = True;
  690. result = _DtCvStrcspn ((void *) tChar, " -", 0, &tLen);
  691. len += tLen;
  692. /*
  693. * check for '-'. Some of the possible combinations are:
  694. * -text
  695. * - text
  696. * -/text/
  697. * text/-text/
  698. * text-text
  699. * text text
  700. *
  701. * if it is the first character to check and there is no
  702. * previous segment, then it is starting a line and can
  703. * not be broken on.
  704. *
  705. * _DtCvStrcpn return 0 if one of the characters in the
  706. * test string was found.
  707. */
  708. if (0 == result && '-' == tChar[tLen] && 0 == len &&
  709. NULL == prev_seg &&
  710. _DtCvCheckLineSyntax(canvas,pSeg,start,1,True) == False)
  711. {
  712. len++;
  713. tLen++;
  714. tChar += tLen;
  715. good_len = False;
  716. }
  717. } while (!good_len);
  718. /*
  719. * found either a space or a hypen or null byte.
  720. * If we found a hypen, include it.
  721. */
  722. if ('-' == *tChar)
  723. len++;
  724. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  725. + _DtCvGetTraversalWidth(canvas, pSeg, lst_hyper);
  726. /*
  727. * Did we find a space or hypen?
  728. * If not, can this segment stand alone?
  729. */
  730. if (result == 0 ||
  731. _DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
  732. {
  733. if (nextSeg != NULL)
  734. *nextSeg = pSeg;
  735. if (nextStart != NULL)
  736. *nextStart = start + len;
  737. if (widthCount != NULL)
  738. *widthCount = len;
  739. return curWidth;
  740. }
  741. }
  742. /*
  743. * multibyte (wide char string), look for a break the hard way.
  744. */
  745. else
  746. {
  747. len = 0;
  748. while (len < myLength)
  749. {
  750. len++;
  751. if (_DtCvCheckLineSyntax(canvas,pSeg,start,len,False) == True)
  752. {
  753. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  754. _DtCvIsSegWideChar(pSeg), start);
  755. curWidth = _DtCvGetStringWidth(canvas,pSeg,pChar,len)
  756. + _DtCvGetTraversalWidth(canvas,pSeg,lst_hyper);
  757. if (nextSeg != NULL)
  758. *nextSeg = pSeg;
  759. if (nextStart != NULL)
  760. *nextStart = start + len;
  761. if (widthCount != NULL)
  762. *widthCount = len;
  763. return curWidth;
  764. }
  765. }
  766. /*
  767. * Didn't find a smaller segment that satisfied the requirements.
  768. * Determine the length of the current segment.
  769. */
  770. curWidth = _DtCvGetStringWidth (canvas, pSeg, pChar, len)
  771. + _DtCvGetTraversalWidth(canvas, pSeg,
  772. lst_hyper);
  773. }
  774. }
  775. /*
  776. * sigh...need to go further...this segment can't end a line
  777. * either.
  778. */
  779. prev_seg = pSeg;
  780. pSeg = pSeg->next_seg;
  781. if (pSeg != NULL)
  782. {
  783. start = 0;
  784. curWidth += _DtCvGetNextWidth (canvas,
  785. _DtCvPrimaryTypeOfSeg (prev_seg), lst_hyper,
  786. pSeg, start, prev_seg,
  787. nextSeg, nextStart, &nextLen);
  788. }
  789. if (widthCount != NULL)
  790. *widthCount = len + nextLen;
  791. return (curWidth);
  792. }
  793. /******************************************************************************
  794. * Function: _DtCvSaveInfo
  795. *
  796. * Initializes a line table element to the segment it should display.
  797. *****************************************************************************/
  798. void
  799. _DtCvSaveInfo (
  800. _DtCanvasStruct *canvas,
  801. _DtCvLayoutInfo *layout,
  802. _DtCvUnit max_width,
  803. _DtCvUnit r_margin,
  804. _DtCvFrmtOption txt_justify)
  805. {
  806. /*****************************************************************
  807. * The ascent for a line is described as the number of units
  808. * above the baseline.
  809. *
  810. * The descent for a line is described as the number of units
  811. * below the baseline.
  812. *
  813. * Neither the ascent or decent value includes the baseline
  814. ****************************************************************/
  815. int len;
  816. int start = layout->line_start;
  817. int count = layout->line_bytes;
  818. long txtCnt = canvas->txt_cnt;
  819. _DtCvUnit maxAscent = 0;
  820. _DtCvUnit maxDescent = 0;
  821. _DtCvUnit maxRegion = 0;
  822. _DtCvUnit superY = 0;
  823. _DtCvUnit subY = 0;
  824. _DtCvUnit fontAscent;
  825. _DtCvUnit fontDescent;
  826. _DtCvValue fndLnk = False;
  827. _DtCvValue visLnk = False;
  828. void *pChar;
  829. _DtCvSegmentI *pSeg = layout->line_seg;
  830. if (txtCnt >= canvas->txt_max)
  831. {
  832. canvas->txt_max += GROW_SIZE;
  833. if (canvas->txt_lst)
  834. canvas->txt_lst = (_DtCvDspLine *) realloc (
  835. (void *) canvas->txt_lst,
  836. (sizeof(_DtCvDspLine) * canvas->txt_max));
  837. else
  838. canvas->txt_lst = (_DtCvDspLine *) malloc (
  839. (sizeof(_DtCvDspLine) * canvas->txt_max));
  840. /*
  841. * NOTE....should this routine return a value?
  842. * If (re)alloc error occurs, this simply ignores the problem.
  843. */
  844. if (canvas->txt_lst == NULL)
  845. {
  846. canvas->txt_max = 0;
  847. canvas->txt_cnt = 0;
  848. return;
  849. }
  850. }
  851. while (pSeg != NULL && count > 0)
  852. {
  853. /*
  854. * set which line will this segment sit on, iff this is the
  855. * first access to the segment.
  856. */
  857. if ((void *) -1 == pSeg->internal_use)
  858. pSeg->internal_use = (void *) txtCnt;
  859. /*
  860. * now get the segment's sizing so we can determine
  861. * the height and depth of the line.
  862. */
  863. len = 1;
  864. fontAscent = 0;
  865. fontDescent = 0;
  866. if (_DtCvIsSegVisibleLink(pSeg))
  867. visLnk = True;
  868. if (_DtCvIsSegALink(pSeg))
  869. fndLnk = True;
  870. /*
  871. * get the ascent and descent of the segment along with a length
  872. */
  873. if (_DtCvIsSegString(pSeg))
  874. {
  875. _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
  876. &fontAscent, &fontDescent, NULL, NULL, NULL);
  877. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
  878. _DtCvIsSegWideChar(pSeg), start);
  879. len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
  880. if (len > count)
  881. len = count;
  882. }
  883. else if (_DtCvIsSegRegion(pSeg))
  884. {
  885. if (-1 == _DtCvAscentOfRegionSeg(pSeg))
  886. {
  887. if (maxRegion < _DtCvHeightOfRegionSeg(pSeg))
  888. maxRegion = _DtCvHeightOfRegionSeg(pSeg);
  889. }
  890. else
  891. {
  892. fontAscent = _DtCvAscentOfRegionSeg(pSeg);
  893. fontDescent = _DtCvHeightOfRegionSeg(pSeg) - fontAscent;
  894. }
  895. }
  896. /*
  897. * adjust the ascent and descent values by their subscript
  898. * or superscript adjustments.
  899. */
  900. if (_DtCvIsSegSuperScript(pSeg))
  901. {
  902. fontAscent += superY;
  903. fontDescent -= superY;
  904. if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
  905. && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + superY)
  906. maxRegion = _DtCvHeightOfRegionSeg(pSeg) + superY;
  907. }
  908. else if (_DtCvIsSegSubScript(pSeg))
  909. {
  910. fontAscent -= subY;
  911. fontDescent += subY;
  912. if (_DtCvIsSegRegion(pSeg) && -1 == _DtCvAscentOfRegionSeg(pSeg)
  913. && maxRegion < _DtCvHeightOfRegionSeg(pSeg) + subY)
  914. maxRegion = _DtCvHeightOfRegionSeg(pSeg) + subY;
  915. }
  916. else /* not a subscript or superscript */
  917. {
  918. /*
  919. * set up the super and sub script offsets for following
  920. * segments.
  921. */
  922. if (_DtCvIsSegString (pSeg))
  923. _DtCvFontMetrics(canvas,_DtCvFontOfStringSeg(pSeg),
  924. NULL, NULL, NULL, &superY, &subY);
  925. else if (_DtCvIsSegRegion(pSeg))
  926. {
  927. superY = _DtCvHeightOfRegionSeg(pSeg) * 4 / 10;
  928. subY = superY;
  929. }
  930. }
  931. /*
  932. * now determine the maximums for ascent and descent.
  933. */
  934. if (fontAscent > maxAscent)
  935. maxAscent = fontAscent;
  936. if (fontDescent > maxDescent)
  937. maxDescent = fontDescent;
  938. /*
  939. * decrement the count
  940. */
  941. count -= len;
  942. /*
  943. * If this segment terminates the paragraph
  944. * force the end of the loop.
  945. */
  946. pSeg = pSeg->next_disp;
  947. start = 0;
  948. }
  949. if (txt_justify == _DtCvJUSTIFY_RIGHT || _DtCvJUSTIFY_CENTER == txt_justify)
  950. {
  951. /*
  952. * justify the line.
  953. */
  954. _DtCvUnit workWidth = max_width - layout->text_x_pos -
  955. r_margin - layout->cur_len;
  956. if (txt_justify == _DtCvJUSTIFY_CENTER)
  957. workWidth = workWidth / 2;
  958. if (workWidth < 0)
  959. workWidth = 0;
  960. layout->text_x_pos += workWidth;
  961. }
  962. /*
  963. * adjust for any special characters found
  964. */
  965. if (maxRegion > maxAscent + maxDescent + 1)
  966. maxAscent = maxRegion - maxDescent - 1;
  967. /*
  968. * check to see if the max values have even been touched.
  969. */
  970. if (layout->line_bytes == 0 && maxAscent == 0 && maxDescent == 0)
  971. maxAscent = canvas->metrics.line_height;
  972. /*
  973. * adjust ascent and descent by the traversal and link info
  974. */
  975. maxDescent += layout->leading;
  976. if (fndLnk)
  977. {
  978. maxAscent += canvas->traversal_info.space_above;
  979. maxDescent += canvas->traversal_info.space_below;
  980. if (visLnk)
  981. {
  982. maxAscent += canvas->link_info.space_above;
  983. maxDescent += canvas->link_info.space_below;
  984. }
  985. }
  986. /*
  987. * save the line information, if there is a string here.
  988. */
  989. if (layout->line_bytes > 0)
  990. {
  991. canvas->txt_lst[txtCnt].processed = _DtCvFALSE;
  992. canvas->txt_lst[txtCnt].text_x = layout->text_x_pos;
  993. canvas->txt_lst[txtCnt].max_x = layout->text_x_pos;
  994. canvas->txt_lst[txtCnt].baseline = layout->y_pos + maxAscent;
  995. canvas->txt_lst[txtCnt].descent = maxDescent;
  996. canvas->txt_lst[txtCnt].ascent = maxAscent;
  997. canvas->txt_lst[txtCnt].byte_index = layout->line_start;
  998. canvas->txt_lst[txtCnt].length = layout->line_bytes;
  999. canvas->txt_lst[txtCnt].seg_ptr = layout->line_seg;
  1000. canvas->txt_cnt++;
  1001. }
  1002. /*
  1003. * blank line is one half the normal size line
  1004. */
  1005. else
  1006. {
  1007. maxAscent = (maxAscent + maxDescent) / 2;
  1008. maxDescent = 0;
  1009. }
  1010. if (layout->text_x_pos + layout->cur_len > layout->cur_max_x)
  1011. layout->cur_max_x = layout->text_x_pos + layout->cur_len;
  1012. if (layout->text_x_pos + layout->cur_len > layout->max_x_pos)
  1013. layout->max_x_pos = layout->text_x_pos + layout->cur_len;
  1014. /*
  1015. * zero the string info
  1016. */
  1017. layout->line_bytes = 0;
  1018. layout->cur_len = 0;
  1019. layout->lst_hyper = -1;
  1020. layout->lst_vis = False;
  1021. _DtCvSetJoinInfo(layout, False, -1);
  1022. /*
  1023. * adjust where the next line is positioned.
  1024. */
  1025. layout->y_pos = layout->y_pos + maxAscent + maxDescent + 1;
  1026. }
  1027. /******************************************************************************
  1028. * Function: _DtCvCheckAddHyperToTravList
  1029. *
  1030. *****************************************************************************/
  1031. void
  1032. _DtCvCheckAddHyperToTravList (
  1033. _DtCanvasStruct *canvas,
  1034. _DtCvSegmentI *p_seg,
  1035. _DtCvValue flag,
  1036. _DtCvValue *lst_vis,
  1037. int *lst_hyper,
  1038. _DtCvUnit *cur_len)
  1039. {
  1040. int nxtHyper;
  1041. int prevIdx;
  1042. _DtCvValue junk;
  1043. _DtCvUnit retLen = *cur_len;
  1044. if (_DtCvIsSegALink (p_seg))
  1045. {
  1046. nxtHyper = _DtCvGetNextTravEntry(canvas);
  1047. if (-1 == nxtHyper)
  1048. /*
  1049. * NOTE....should this routine return a value?
  1050. * If (re)alloc error occurs, this simply ignores the problem.
  1051. */
  1052. return;
  1053. prevIdx = nxtHyper - 1;
  1054. if (prevIdx < 0
  1055. || _DtCvTraversalLink != canvas->trav_lst[prevIdx].type
  1056. || p_seg->link_idx != canvas->trav_lst[prevIdx].seg_ptr->link_idx)
  1057. {
  1058. /*
  1059. * save this hypertext link in the traversal list
  1060. */
  1061. _DtCvSetTravEntryInfo (canvas, nxtHyper, _DtCvTraversalLink, p_seg,
  1062. canvas->txt_cnt, _DtCvTRUE);
  1063. }
  1064. }
  1065. /*
  1066. * take into account the link metrics.
  1067. */
  1068. junk = _DtCvIsSegVisibleLink(p_seg);
  1069. *lst_vis = _DtCvModifyXpos(canvas->link_info, p_seg, junk,
  1070. *lst_vis, *lst_hyper,
  1071. &retLen);
  1072. /*
  1073. * take into account the traversal metrics
  1074. */
  1075. junk = _DtCvIsSegALink(p_seg);
  1076. (void) _DtCvModifyXpos(canvas->traversal_info, p_seg, junk,
  1077. ((_DtCvValue) True), *lst_hyper,
  1078. &retLen);
  1079. *lst_hyper = p_seg->link_idx;
  1080. if (_DtCvTRUE == flag)
  1081. *cur_len = retLen;
  1082. }
  1083. /******************************************************************************
  1084. * Function: ProcessStringSegment
  1085. *
  1086. * chops a string segment up until its completely used.
  1087. *
  1088. * Returns:
  1089. * 0 if the entire string segment was processed.
  1090. * 1 if the required number of lines were processed.
  1091. *****************************************************************************/
  1092. int
  1093. _DtCvProcessStringSegment(
  1094. _DtCanvasStruct *canvas,
  1095. _DtCvLayoutInfo *lay_info,
  1096. _DtCvUnit max_width,
  1097. _DtCvUnit l_margin,
  1098. _DtCvUnit r_margin,
  1099. _DtCvSegmentI *cur_seg,
  1100. unsigned int *cur_start,
  1101. _DtCvFrmtOption txt_justify,
  1102. _DtCvValue stat_flag)
  1103. {
  1104. _DtCvUnit workWidth;
  1105. _DtCvUnit stringLen;
  1106. _DtCvUnit textWidth;
  1107. _DtCvUnit nWidth;
  1108. _DtCvUnit spaceSize = 0;
  1109. int oldType;
  1110. int retStart;
  1111. int retCount;
  1112. wchar_t *wcp;
  1113. void *pChar;
  1114. char *strPtr;
  1115. _DtCvValue done = False;
  1116. _DtCvSegmentI *retSeg;
  1117. if (NULL != _DtCvStringOfStringSeg(cur_seg))
  1118. {
  1119. if (lay_info->cur_len == 0)
  1120. {
  1121. lay_info->line_seg = cur_seg;
  1122. lay_info->line_start = *cur_start;
  1123. }
  1124. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1125. lay_info->delayed_search_saves++;
  1126. oldType = _DtCvPrimaryTypeOfSeg (cur_seg);
  1127. /*
  1128. * is alignment in effect?
  1129. */
  1130. if (TRUE == lay_info->align_flag)
  1131. {
  1132. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1133. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1134. nWidth = _DtCvStrcspn (pChar, lay_info->align_char,
  1135. _DtCvIsSegWideChar(cur_seg),
  1136. &stringLen);
  1137. if (-1 == nWidth)
  1138. return -1;
  1139. /*
  1140. * we got a valid length back, calculate the length
  1141. */
  1142. textWidth = 0;
  1143. if (0 != stringLen)
  1144. textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen);
  1145. /*
  1146. * check to see if this a hypertext that needs
  1147. * to be remembered.
  1148. */
  1149. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1150. &(lay_info->lst_vis),
  1151. &(lay_info->lst_hyper),
  1152. &(lay_info->cur_len));
  1153. /*
  1154. * update the length and position information
  1155. * to skip past the characters before the alignment character.
  1156. */
  1157. lay_info->line_bytes += stringLen;
  1158. lay_info->cur_len += (textWidth
  1159. + _DtCvGetTraversalWidth(canvas,
  1160. cur_seg, lay_info->lst_hyper));
  1161. *cur_start += stringLen;
  1162. /*
  1163. * if we didn't find the character, check to see if this forces
  1164. * a newline - honor it if it does. We'll check the next
  1165. * string segment for the alignment character.
  1166. */
  1167. if (1 == nWidth && _DtCvIsSegNewLine (cur_seg)
  1168. && lay_info->line_bytes)
  1169. {
  1170. _DtCvSaveInfo (canvas,lay_info,max_width,r_margin,txt_justify);
  1171. while (lay_info->delayed_search_saves > 0) {
  1172. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1173. lay_info->delayed_search_saves--;
  1174. }
  1175. return 0;
  1176. }
  1177. /*
  1178. * so we found the character, now get it's width.
  1179. */
  1180. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1181. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1182. textWidth = _DtCvGetStringWidth(canvas, cur_seg, pChar, 1)
  1183. + _DtCvGetTraversalWidth(canvas, cur_seg,
  1184. lay_info->lst_hyper);
  1185. /*
  1186. * is this the second or more align position?
  1187. * if so, need to shift the character to align with others.
  1188. */
  1189. if (lay_info->align_pos >
  1190. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
  1191. lay_info->text_x_pos = lay_info->align_pos - lay_info->cur_len
  1192. - textWidth / 2;
  1193. /*
  1194. * otherwise, does this exceed the previous alignments?
  1195. * if so, the table processing should catch that we've
  1196. * changed the alignment position and re-format the others.
  1197. */
  1198. else if (lay_info->align_pos <
  1199. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2)
  1200. lay_info->align_pos =
  1201. lay_info->text_x_pos + lay_info->cur_len + textWidth / 2;
  1202. /*
  1203. * indicate that the character has been found.
  1204. */
  1205. lay_info->align_flag = False;
  1206. /*
  1207. * check to see if this item can end a line.
  1208. * if can't end the line, force a join for the next segment or
  1209. * for the rest of this segment.
  1210. */
  1211. if (False == _DtCvCheckLineSyntax(canvas,cur_seg,*cur_start,1,False))
  1212. lay_info->join = True;
  1213. /*
  1214. * update the length and position information to
  1215. * include the character.
  1216. */
  1217. lay_info->line_bytes++;
  1218. lay_info->cur_len += textWidth;
  1219. *cur_start += 1;
  1220. /*
  1221. * check to see if this is the end of the segment.
  1222. */
  1223. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1224. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1225. if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
  1226. ||
  1227. (_DtCvIsSegRegChar(cur_seg) && '\0' == *((char *) pChar)))
  1228. return 0;
  1229. }
  1230. while (1)
  1231. {
  1232. /*
  1233. * recalculate the width
  1234. */
  1235. workWidth = max_width - lay_info->text_x_pos -
  1236. lay_info->cur_len - r_margin;
  1237. /*
  1238. * adjust the character pointer and get the
  1239. * length of the string.
  1240. */
  1241. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1242. _DtCvIsSegWideChar(cur_seg), *cur_start);
  1243. stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
  1244. /*
  1245. * get the pixel width of the text string.
  1246. */
  1247. textWidth = _DtCvGetStringWidth(canvas,cur_seg,pChar,stringLen)
  1248. + _DtCvGetTraversalWidth(canvas, cur_seg,
  1249. lay_info->lst_hyper);
  1250. /*
  1251. * Will it fit in the current width?
  1252. */
  1253. if (stat_flag == True || textWidth <= workWidth)
  1254. {
  1255. /*
  1256. * Yes, this segment or part of a segment can fit in the
  1257. * current width. But can the last character of this
  1258. * segment end a line and can the beginning of the next
  1259. * segment start a new line?
  1260. */
  1261. if (stat_flag == True ||
  1262. _DtCvCheckLineSyntax (canvas, cur_seg,
  1263. *cur_start, stringLen, False) == TRUE)
  1264. {
  1265. /*
  1266. * check to see if this a hypertext that needs
  1267. * to be remembered.
  1268. */
  1269. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1270. &(lay_info->lst_vis),
  1271. &(lay_info->lst_hyper),
  1272. &(lay_info->cur_len));
  1273. /*
  1274. * The line syntax is good.
  1275. * Update the global and width variables.
  1276. */
  1277. lay_info->line_bytes += stringLen;
  1278. lay_info->cur_len += textWidth;
  1279. _DtCvSetJoinInfo(lay_info,
  1280. _DtCvIsSegNonBreakingChar(cur_seg),
  1281. -1);
  1282. /*
  1283. * Check to see if this segment forces an end
  1284. */
  1285. if (_DtCvIsSegNewLine (cur_seg) && lay_info->line_bytes) {
  1286. _DtCvSaveInfo (canvas, lay_info, max_width,
  1287. r_margin, txt_justify);
  1288. while (lay_info->delayed_search_saves > 0) {
  1289. _DtCvSetSearchEntryInfo(canvas,
  1290. canvas->txt_cnt - 1);
  1291. lay_info->delayed_search_saves--;
  1292. }
  1293. }
  1294. return 0;
  1295. }
  1296. /*
  1297. * CheckLineSyntax says that either this line couldn't
  1298. * end a line or the next segment couldn't start a line.
  1299. * Therefore, find out how much of the next segment or
  1300. * segments we need to incorporate to satisfy the Line
  1301. * Syntax rules.
  1302. */
  1303. nWidth = _DtCvGetNextWidth (canvas, oldType,
  1304. lay_info->lst_hyper,
  1305. cur_seg->next_seg, 0, cur_seg,
  1306. &retSeg, &retStart, &retCount);
  1307. /*
  1308. * will this segment + the next segment fit?
  1309. */
  1310. if (textWidth + nWidth <= workWidth)
  1311. {
  1312. /*
  1313. * check to see if this a hypertext that needs
  1314. * to be remembered.
  1315. */
  1316. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1317. &(lay_info->lst_vis),
  1318. &(lay_info->lst_hyper),
  1319. &(lay_info->cur_len));
  1320. /*
  1321. * YEAH Team!! It Fits!!
  1322. *
  1323. * Update the global and width variables.
  1324. */
  1325. lay_info->line_bytes += stringLen;
  1326. lay_info->cur_len += textWidth;
  1327. _DtCvSetJoinInfo(lay_info, False, -1);
  1328. return 0;
  1329. }
  1330. }
  1331. /*
  1332. * the text width plus the next segment is tooo big
  1333. * to fit. Reduce the current segment if possible
  1334. */
  1335. done = False;
  1336. textWidth = 0;
  1337. stringLen = 0;
  1338. while (!done)
  1339. {
  1340. nWidth = _DtCvGetNextWidth (canvas, oldType,
  1341. lay_info->lst_hyper,
  1342. cur_seg, *cur_start, NULL,
  1343. &retSeg, &retStart, &retCount);
  1344. if (retSeg == cur_seg && textWidth + nWidth <= workWidth)
  1345. {
  1346. /*
  1347. * check to see if this a hypertext that needs
  1348. * to be remembered.
  1349. */
  1350. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvFALSE,
  1351. &(lay_info->lst_vis),
  1352. &(lay_info->lst_hyper),
  1353. &(lay_info->cur_len));
  1354. _DtCvSetJoinInfo(lay_info, False, -1);
  1355. *cur_start = retStart;
  1356. stringLen += retCount;
  1357. textWidth += nWidth;
  1358. spaceSize = 0;
  1359. /*
  1360. * take into account a space if that is where it breaks.
  1361. */
  1362. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1363. _DtCvIsSegWideChar(cur_seg),
  1364. *cur_start);
  1365. if ((_DtCvIsSegWideChar(cur_seg) &&
  1366. (' ' == *((wchar_t *) pChar)))
  1367. ||
  1368. (_DtCvIsSegRegChar(cur_seg) &&
  1369. (' ' == *((char *) pChar))))
  1370. {
  1371. spaceSize = _DtCvGetStringWidth(canvas,
  1372. cur_seg, pChar, 1)
  1373. + _DtCvGetTraversalWidth (canvas,
  1374. cur_seg, lay_info->lst_hyper);
  1375. textWidth += spaceSize;
  1376. stringLen++;
  1377. (*cur_start)++;
  1378. }
  1379. }
  1380. else
  1381. {
  1382. /*
  1383. * Done trying to find a segment that will
  1384. * fit in the size given
  1385. */
  1386. done = True;
  1387. }
  1388. }
  1389. /*
  1390. * Update the global variables
  1391. */
  1392. lay_info->line_bytes += stringLen;
  1393. lay_info->cur_len += textWidth;
  1394. if (lay_info->join == True || lay_info->line_bytes == 0)
  1395. {
  1396. /*
  1397. * This line would be empty if we followed the rules.
  1398. * Or it would break a line improperly.
  1399. * Force this onto the line.
  1400. * check to see if this a hypertext that needs
  1401. * to be remembered.
  1402. */
  1403. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1404. &(lay_info->lst_vis),
  1405. &(lay_info->lst_hyper),
  1406. &(lay_info->cur_len));
  1407. /*
  1408. * Couldn't find a smaller, have to
  1409. * go with the larger segment.
  1410. */
  1411. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1412. _DtCvIsSegWideChar(cur_seg),
  1413. *cur_start);
  1414. stringLen = _DtCvStrLen (pChar, _DtCvIsSegWideChar(cur_seg));
  1415. if (retCount > 0 && retCount < stringLen)
  1416. stringLen = retCount;
  1417. lay_info->line_bytes += stringLen;
  1418. lay_info->cur_len += (_DtCvGetStringWidth(canvas, cur_seg,
  1419. pChar, stringLen)
  1420. + _DtCvGetTraversalWidth (canvas,
  1421. cur_seg, lay_info->lst_hyper));
  1422. _DtCvSetJoinInfo(lay_info, False, -1);
  1423. /*
  1424. * If we had to do a bigger segment,
  1425. * then we're done processing the target segment.
  1426. */
  1427. if (stringLen == _DtCvStrLen(pChar,_DtCvIsSegWideChar(cur_seg)))
  1428. {
  1429. if (_DtCvCheckLineSyntax (canvas, cur_seg,
  1430. *cur_start, stringLen, False) == False)
  1431. _DtCvSetJoinInfo(lay_info, True, -1);
  1432. else if (_DtCvIsSegNewLine (cur_seg)) {
  1433. _DtCvSaveInfo (canvas, lay_info, max_width,
  1434. r_margin, txt_justify);
  1435. while (lay_info->delayed_search_saves > 0) {
  1436. _DtCvSetSearchEntryInfo(canvas,
  1437. canvas->txt_cnt - 1);
  1438. lay_info->delayed_search_saves--;
  1439. }
  1440. }
  1441. return 0;
  1442. }
  1443. *cur_start = retStart;
  1444. }
  1445. else if (spaceSize)
  1446. {
  1447. /*
  1448. * If a space was included as the last character,
  1449. * remove it now.
  1450. */
  1451. lay_info->line_bytes--;
  1452. lay_info->cur_len -= spaceSize;
  1453. }
  1454. /*
  1455. * Save the information
  1456. */
  1457. _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
  1458. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1459. lay_info->delayed_search_saves--;
  1460. while (lay_info->delayed_search_saves > 0) {
  1461. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1462. lay_info->delayed_search_saves--;
  1463. }
  1464. /*
  1465. * Skip the spaces.
  1466. */
  1467. pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(cur_seg),
  1468. _DtCvIsSegWideChar(cur_seg),
  1469. *cur_start);
  1470. if (_DtCvIsSegWideChar(cur_seg))
  1471. {
  1472. wcp = pChar;
  1473. while (' ' == *wcp)
  1474. {
  1475. wcp++;
  1476. (*cur_start)++;
  1477. }
  1478. pChar = wcp;
  1479. }
  1480. else /* single byte string */
  1481. {
  1482. strPtr = pChar;
  1483. while (' ' == *strPtr)
  1484. {
  1485. strPtr++;
  1486. (*cur_start)++;
  1487. }
  1488. pChar = strPtr;
  1489. }
  1490. /*
  1491. * are we at the end of the segment?
  1492. */
  1493. if ((_DtCvIsSegWideChar(cur_seg) && 0 == *((wchar_t *) pChar))
  1494. ||
  1495. (_DtCvIsSegRegChar(cur_seg) && 0 == *((char *) pChar)))
  1496. return 0;
  1497. if (*cur_start == 0 && (cur_seg->type & _DtCvSEARCH_FLAG))
  1498. lay_info->delayed_search_saves++;
  1499. /*
  1500. * Initialize the global variables
  1501. */
  1502. lay_info->line_seg = cur_seg;
  1503. lay_info->line_start = *cur_start;
  1504. lay_info->text_x_pos = l_margin;
  1505. if (CheckFormat(lay_info) == True)
  1506. return 1;
  1507. /*
  1508. * check to see if this a hypertext that needs
  1509. * to be remembered.
  1510. */
  1511. _DtCvCheckAddHyperToTravList (canvas, cur_seg, _DtCvTRUE,
  1512. &(lay_info->lst_vis),
  1513. &(lay_info->lst_hyper),
  1514. &(lay_info->cur_len));
  1515. }
  1516. }
  1517. else if (_DtCvIsSegNewLine (cur_seg))
  1518. {
  1519. /*
  1520. * Force a save - even if it is an empty line.
  1521. */
  1522. _DtCvSaveInfo (canvas, lay_info, max_width, r_margin, txt_justify);
  1523. while (lay_info->delayed_search_saves > 0) {
  1524. _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
  1525. lay_info->delayed_search_saves--;
  1526. }
  1527. }
  1528. return 0;
  1529. } /* End _DtCvProcessStringSegment */
  1530. /******************************************************************************
  1531. * Function: _DtCvSetJoinInfo
  1532. *
  1533. * Returns: sets the joining information to the given information.
  1534. *
  1535. *****************************************************************************/
  1536. void
  1537. _DtCvSetJoinInfo (
  1538. _DtCvLayoutInfo *lay_info,
  1539. _DtCvValue flag,
  1540. int txt_ln)
  1541. {
  1542. lay_info->join = flag;
  1543. lay_info->join_line = txt_ln;
  1544. }
  1545. /******************************************************************************
  1546. * Function: _DtCvGetNextTravEntry
  1547. *
  1548. * Returns: >= 0 if success,
  1549. * -1 if failure.
  1550. *
  1551. * Purpose: Return the next available entry in the traversal list.
  1552. *
  1553. *****************************************************************************/
  1554. int
  1555. _DtCvGetNextTravEntry (
  1556. _DtCanvasStruct *canvas)
  1557. {
  1558. int nxtEntry = canvas->trav_cnt;
  1559. /*
  1560. * does the list need to grow?
  1561. */
  1562. if (nxtEntry >= canvas->trav_max)
  1563. {
  1564. /*
  1565. * grow by a set amount
  1566. */
  1567. canvas->trav_max += GROW_SIZE;
  1568. /*
  1569. * realloc or malloc?
  1570. */
  1571. if (NULL != canvas->trav_lst)
  1572. canvas->trav_lst = (_DtCvTraversalInfo *) realloc (
  1573. (char *) canvas->trav_lst,
  1574. ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
  1575. else
  1576. canvas->trav_lst = (_DtCvTraversalInfo *) malloc (
  1577. ((sizeof(_DtCvTraversalInfo)) * canvas->trav_max));
  1578. /*
  1579. * did the memory allocation work? if not return error code.
  1580. */
  1581. if (NULL == canvas->trav_lst)
  1582. {
  1583. canvas->trav_max = 0;
  1584. canvas->trav_cnt = 0;
  1585. nxtEntry = -1;
  1586. }
  1587. }
  1588. canvas->trav_lst[nxtEntry] = DefTravData;
  1589. return nxtEntry;
  1590. }
  1591. /******************************************************************************
  1592. * Function: _DtCvSetTravEntryInfo
  1593. *
  1594. * Returns: 0 if success,
  1595. * -1 if failure.
  1596. *
  1597. * Purpose: Set the high level information in an entry of the traversal
  1598. * list.
  1599. *****************************************************************************/
  1600. int
  1601. _DtCvSetTravEntryInfo (
  1602. _DtCanvasStruct *canvas,
  1603. int entry,
  1604. _DtCvTraversalType type,
  1605. _DtCvSegmentI *p_seg,
  1606. int line_idx,
  1607. _DtCvValue inc)
  1608. {
  1609. int result = -1;
  1610. if (-1 != entry && entry <= canvas->trav_cnt)
  1611. {
  1612. _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
  1613. travEntry->type = type;
  1614. travEntry->seg_ptr = p_seg;
  1615. travEntry->idx = line_idx;
  1616. if (_DtCvTRUE == inc)
  1617. canvas->trav_cnt++;
  1618. result = 0;
  1619. }
  1620. return result;
  1621. }
  1622. int
  1623. _DtCvGetNextSearchEntry(_DtCanvasStruct* canvas)
  1624. {
  1625. if (canvas->search_cnt >= canvas->search_max) {
  1626. canvas->search_max += GROW_SIZE;
  1627. if (canvas->searchs)
  1628. canvas->searchs = (_DtCvSearchData *)
  1629. realloc((void*)canvas->searchs,
  1630. canvas->search_max * sizeof(_DtCvSearchData));
  1631. else
  1632. canvas->searchs = (_DtCvSearchData *)
  1633. malloc(canvas->search_max * sizeof(_DtCvSearchData));
  1634. }
  1635. canvas->searchs[canvas->search_cnt].idx = -1;
  1636. return canvas->search_cnt++;
  1637. }
  1638. int
  1639. _DtCvSetSearchEntryInfo(_DtCanvasStruct* canvas, int line_idx)
  1640. {
  1641. int search_idx;
  1642. /* get a next available slot for search */
  1643. search_idx = _DtCvGetNextSearchEntry(canvas);
  1644. /* save information (i.e. line_idx) */
  1645. canvas->searchs[search_idx].idx = line_idx;
  1646. }
  1647. /******************************************************************************
  1648. * Function: _DtCvSetTravEntryPos
  1649. *
  1650. * Returns: 0 if success,
  1651. * -1 if failure.
  1652. *
  1653. * Purpose: Set the position and dimension information of an entry in
  1654. * the traversal list.
  1655. *
  1656. *****************************************************************************/
  1657. int
  1658. _DtCvSetTravEntryPos (
  1659. _DtCanvasStruct *canvas,
  1660. int entry,
  1661. _DtCvUnit x,
  1662. _DtCvUnit y,
  1663. _DtCvUnit width,
  1664. _DtCvUnit height)
  1665. {
  1666. int result = -1;
  1667. if (-1 != entry && entry <= canvas->trav_cnt)
  1668. {
  1669. _DtCvTraversalInfo *travEntry = &(canvas->trav_lst[entry]);
  1670. travEntry->x_pos = x;
  1671. travEntry->y_pos = y;
  1672. travEntry->width = width;
  1673. travEntry->height = height;
  1674. result = 0;
  1675. }
  1676. return result;
  1677. }
  1678. /******************************************************************************
  1679. * Function: _DtCvCalcMarkPos
  1680. *
  1681. * Returns: 0 if success,
  1682. * -1 if failure.
  1683. *
  1684. * Purpose: Calcalate the position and dimension information of a mark.
  1685. *
  1686. *****************************************************************************/
  1687. int
  1688. _DtCvCalcMarkPos (
  1689. _DtCanvasStruct *canvas,
  1690. int entry,
  1691. _DtCvUnit *ret_x,
  1692. _DtCvUnit *ret_y,
  1693. _DtCvUnit *ret_width,
  1694. _DtCvUnit *ret_height)
  1695. {
  1696. int result = -1;
  1697. if (-1 != entry && entry <= canvas->mark_cnt)
  1698. {
  1699. _DtCvMarkData *mark = &(canvas->marks[entry]);
  1700. /*
  1701. * if we've got a line index for the mark, get the positions.
  1702. */
  1703. if (-1 != mark->beg.line_idx && -1 != mark->end.line_idx)
  1704. {
  1705. _DtCvDspLine *line = &(canvas->txt_lst[mark->beg.line_idx]);
  1706. *ret_x = mark->beg.x;
  1707. *ret_y = mark->beg.y - line->ascent;
  1708. if (mark->beg.line_idx == mark->end.line_idx)
  1709. *ret_width = mark->end.x - *ret_x;
  1710. else
  1711. *ret_width = canvas->txt_lst[mark->beg.line_idx].max_x - *ret_x;
  1712. *ret_height = line->ascent + line->descent + 1;
  1713. result = 0;
  1714. }
  1715. }
  1716. return result;
  1717. }
  1718. /******************************************************************************
  1719. * Function: _DtCvSortTraversalList
  1720. *
  1721. * Returns: nothing
  1722. *
  1723. * Purpose: Sort the traversal list
  1724. *
  1725. *****************************************************************************/
  1726. void
  1727. _DtCvSortTraversalList (
  1728. _DtCanvasStruct *canvas,
  1729. _DtCvValue retain)
  1730. {
  1731. int curTrav = canvas->cur_trav;
  1732. if (1 < canvas->trav_cnt)
  1733. {
  1734. /*
  1735. * indicate this is the current traversal
  1736. */
  1737. if (-1 != curTrav)
  1738. canvas->trav_lst[curTrav].active = retain;
  1739. /*
  1740. * sort the items.
  1741. */
  1742. qsort (canvas->trav_lst, canvas->trav_cnt, sizeof(_DtCvTraversalInfo),
  1743. CompareTraversalPos);
  1744. if (_DtCvTRUE == retain && -1 != curTrav &&
  1745. _DtCvFALSE == canvas->trav_lst[curTrav].active)
  1746. {
  1747. curTrav = 0;
  1748. while (_DtCvFALSE == canvas->trav_lst[curTrav].active)
  1749. curTrav++;
  1750. canvas->cur_trav = curTrav;
  1751. }
  1752. /*
  1753. * clear the active flag
  1754. */
  1755. if (-1 != curTrav)
  1756. canvas->trav_lst[curTrav].active = _DtCvFALSE;
  1757. }
  1758. }
  1759. /*****************************************************************************
  1760. * Function: _DtCvCvtSegsToPts()
  1761. *
  1762. * Purpose: Given a set of segments, determine the ending points.
  1763. *
  1764. *****************************************************************************/
  1765. _DtCvStatus
  1766. _DtCvCvtSegsToPts (
  1767. _DtCanvasStruct *canvas,
  1768. _DtCvSegPtsI **segs,
  1769. _DtCvSelectData *beg,
  1770. _DtCvSelectData *end,
  1771. _DtCvUnit *ret_y1,
  1772. _DtCvUnit *ret_y2,
  1773. _DtCvSegmentI **ret_seg)
  1774. {
  1775. int count;
  1776. int cnt;
  1777. int start;
  1778. int length;
  1779. long lineIdx;
  1780. int linkIdx = -1;
  1781. _DtCvValue lastVisLnk = _DtCvFALSE;
  1782. _DtCvUnit minY = -1;
  1783. _DtCvUnit maxY = 0;
  1784. _DtCvUnit startX;
  1785. _DtCvUnit endX;
  1786. _DtCvUnit segWidth;
  1787. _DtCvSegmentI *pSeg;
  1788. _DtCvSegmentI *saveSeg;
  1789. _DtCvSegmentI **retSeg;
  1790. _DtCvDspLine *lines = canvas->txt_lst;
  1791. _DtCvFlags result = _DtCvSTATUS_NONE;
  1792. _DtCvSelectData *tmpBeg;
  1793. _DtCvSelectData *tmpEnd;
  1794. _DtCvSelectData bReg;
  1795. _DtCvSelectData eReg;
  1796. /*
  1797. * initialize the structures.
  1798. */
  1799. bReg = DefSelectData;
  1800. eReg = DefSelectData;
  1801. *beg = DefSelectData;
  1802. *end = DefSelectData;
  1803. /*
  1804. * go through each segment and determine the starting positions.
  1805. */
  1806. while (NULL != *segs)
  1807. {
  1808. result = _DtCvSTATUS_OK;
  1809. /*
  1810. * what line is this segment on?
  1811. */
  1812. lineIdx = (long) ((*segs)->segment->internal_use);
  1813. /*
  1814. * get some information about the line
  1815. */
  1816. length = lines[lineIdx].length;
  1817. start = lines[lineIdx].byte_index;
  1818. startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
  1819. pSeg = lines[lineIdx].seg_ptr;
  1820. /*
  1821. * now skip the segments on this line that aren't in the data pt.
  1822. */
  1823. while (NULL != pSeg && pSeg != (*segs)->segment)
  1824. {
  1825. /*
  1826. * advance past any hypertext link offsets.
  1827. */
  1828. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1829. &linkIdx, &lastVisLnk);
  1830. /*
  1831. * we know that this is not the segment we are looking for,
  1832. * so go past it.
  1833. */
  1834. _DtCvGetWidthOfSegment(canvas, pSeg, start, length,
  1835. &cnt, &segWidth, NULL);
  1836. /*
  1837. * skip the segment's width, decrease the overall length by
  1838. * the segment's count, reset the character start point and
  1839. * go to the next segment.
  1840. */
  1841. startX += segWidth;
  1842. length -= cnt;
  1843. start = 0;
  1844. pSeg = pSeg->next_disp;
  1845. }
  1846. /*
  1847. * This segment should be all or partially selected.
  1848. */
  1849. if (NULL == pSeg)
  1850. return _DtCvSTATUS_BAD;
  1851. /*
  1852. * now figure the start location.
  1853. */
  1854. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1855. &linkIdx, &lastVisLnk);
  1856. /*
  1857. * guarenteed that this is the *first* line that the segment
  1858. * exists on. Therefore, may have to go to another line for
  1859. * the correct offset
  1860. */
  1861. while (start + length < (*segs)->offset)
  1862. {
  1863. do { lineIdx++; } while (lineIdx < canvas->txt_cnt
  1864. && pSeg != lines[lineIdx].seg_ptr);
  1865. if (lineIdx >= canvas->txt_cnt)
  1866. return _DtCvSTATUS_BAD;
  1867. length = lines[lineIdx].length;
  1868. start = lines[lineIdx].byte_index;
  1869. startX = lines[lineIdx].text_x;
  1870. linkIdx = -1;
  1871. lastVisLnk = False;
  1872. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1873. &linkIdx, &lastVisLnk);
  1874. }
  1875. /*
  1876. * how many characters do we need to skip?
  1877. */
  1878. count = (*segs)->offset - start;
  1879. segWidth = 0;
  1880. if (0 < count)
  1881. _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
  1882. &cnt, &segWidth, NULL);
  1883. /*
  1884. * adjust the info by the width of the skipped characters.
  1885. */
  1886. start += count;
  1887. length -= count;
  1888. startX += segWidth;
  1889. /*
  1890. * is this a region? If so set the region information instead.
  1891. */
  1892. tmpBeg = beg;
  1893. tmpEnd = end;
  1894. retSeg = ret_seg;
  1895. if (_DtCvIsSegRegion((*segs)->segment))
  1896. {
  1897. tmpBeg = &bReg;
  1898. tmpEnd = &eReg;
  1899. retSeg = &saveSeg;
  1900. }
  1901. /*
  1902. * does this segment start the selection? text or region?
  1903. */
  1904. if (tmpBeg->x == -1 || tmpBeg->y > lines[lineIdx].baseline ||
  1905. (tmpBeg->line_idx == lineIdx && tmpBeg->x > startX))
  1906. {
  1907. tmpBeg->x = startX;
  1908. tmpBeg->y = lines[lineIdx].baseline;
  1909. tmpBeg->line_idx = lineIdx;
  1910. tmpBeg->char_idx = lines[lineIdx].length - length;
  1911. if (NULL != retSeg)
  1912. *retSeg = (*segs)->segment;
  1913. }
  1914. /*
  1915. * get the amount of this segment that is selected.
  1916. */
  1917. count = (*segs)->len;
  1918. /*
  1919. * is it longer than what's (left) on this line?
  1920. */
  1921. while (count > length)
  1922. {
  1923. /*
  1924. * go to the next line containing the segment
  1925. */
  1926. do {
  1927. /*
  1928. * does this line have the minium y?
  1929. */
  1930. if (minY == -1 ||
  1931. minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
  1932. minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
  1933. lineIdx++;
  1934. } while (lineIdx < canvas->txt_cnt
  1935. && pSeg != lines[lineIdx].seg_ptr);
  1936. /*
  1937. * did we run out of lines?
  1938. */
  1939. if (lineIdx >= canvas->txt_cnt)
  1940. return _DtCvSTATUS_BAD;
  1941. /*
  1942. * start over on this line
  1943. */
  1944. segWidth = 0;
  1945. /*
  1946. * get the true count to the next offset
  1947. */
  1948. cnt = lines[lineIdx].byte_index - start;
  1949. /*
  1950. * get the next lines starting info.
  1951. */
  1952. start = lines[lineIdx].byte_index;
  1953. length = lines[lineIdx].length;
  1954. startX = _DtCvGetStartXOfLine(&(lines[lineIdx]), &pSeg);
  1955. linkIdx = -1;
  1956. lastVisLnk = False;
  1957. startX = _DtCvAdvanceXOfLine(canvas, pSeg, startX,
  1958. &linkIdx, &lastVisLnk);
  1959. /*
  1960. * subtract the previous length
  1961. */
  1962. count -= cnt;
  1963. }
  1964. /*
  1965. * now go down the line, examining each segment.
  1966. */
  1967. while (0 < count)
  1968. {
  1969. /*
  1970. * findout how many characters are in the next segment, and its
  1971. * width.
  1972. */
  1973. _DtCvGetWidthOfSegment(canvas,pSeg,start,count,&cnt,&segWidth,NULL);
  1974. /*
  1975. * there are less than in the count, go to the next segment.
  1976. */
  1977. if (cnt < count)
  1978. {
  1979. pSeg = pSeg->next_disp;
  1980. start = 0;
  1981. startX += segWidth;
  1982. }
  1983. length -= cnt;
  1984. count -= cnt;
  1985. }
  1986. endX = startX + segWidth;
  1987. /*
  1988. * does this segment end a segment?
  1989. */
  1990. if (tmpEnd->x == -1 || tmpEnd->y < lines[lineIdx].baseline ||
  1991. (tmpEnd->line_idx == lineIdx && tmpEnd->x < endX))
  1992. {
  1993. tmpEnd->x = endX;
  1994. tmpEnd->y = lines[lineIdx].baseline;
  1995. tmpEnd->line_idx = lineIdx;
  1996. tmpEnd->char_idx = lines[lineIdx].length - length;
  1997. }
  1998. /*
  1999. * check for min and max values
  2000. */
  2001. if (minY == -1 ||
  2002. minY > lines[lineIdx].baseline - lines[lineIdx].ascent)
  2003. minY = lines[lineIdx].baseline - lines[lineIdx].ascent;
  2004. if (maxY < lines[lineIdx].baseline + lines[lineIdx].descent)
  2005. maxY = lines[lineIdx].baseline + lines[lineIdx].descent;
  2006. /*
  2007. * go to the next segment
  2008. */
  2009. segs++;
  2010. }
  2011. /*
  2012. * now determine if a region really starts the beginning of a
  2013. * selection or a text does.
  2014. *
  2015. * was a region found?
  2016. */
  2017. if (-1 != bReg.x)
  2018. {
  2019. /*
  2020. * if no text was found, take the region information.
  2021. */
  2022. if (-1 == beg->x)
  2023. {
  2024. *beg = bReg;
  2025. if (NULL != ret_seg)
  2026. *ret_seg = saveSeg;
  2027. }
  2028. /*
  2029. * or if the region is inline to the other
  2030. * text and it is before the text, then take it's x value.
  2031. */
  2032. else if (bReg.x < beg->x &&
  2033. (bReg.line_idx == beg->line_idx ||
  2034. /*
  2035. * Or if the region is 'standalone' (a bullet of a list, a
  2036. * graphic to wrap around, etc.) then check to see if it
  2037. * straddles the other information and is before the text. If
  2038. * it does, take it's x value.
  2039. */
  2040. _DtCvStraddlesPt(beg->y,
  2041. bReg.y - lines[bReg.line_idx].ascent,
  2042. bReg.y - lines[bReg.line_idx].descent)))
  2043. {
  2044. beg->x = bReg.x;
  2045. if (NULL != ret_seg)
  2046. *ret_seg = saveSeg;
  2047. }
  2048. }
  2049. /*
  2050. * now determine if a region really ends the selection or a text does.
  2051. *
  2052. * was a region found?
  2053. */
  2054. if (-1 != eReg.x)
  2055. {
  2056. /*
  2057. * if no text was found, take the region information.
  2058. */
  2059. if (-1 == end->x)
  2060. *end = eReg;
  2061. /*
  2062. * or if the region is inline to the other
  2063. * text and it is before the text, then take it's x value.
  2064. */
  2065. else if (eReg.x > end->x &&
  2066. (eReg.line_idx == end->line_idx ||
  2067. /*
  2068. * Or if the region is 'standalone' (a bullet of a list, a
  2069. * graphic to wrap around, etc.) then check to see if it
  2070. * straddles the other information and is before the text. If
  2071. * it does, take it's x value.
  2072. */
  2073. _DtCvStraddlesPt(end->y,
  2074. eReg.y - lines[eReg.line_idx].ascent,
  2075. eReg.y - lines[eReg.line_idx].descent)))
  2076. end->x = eReg.x;
  2077. }
  2078. if (NULL != ret_y1)
  2079. *ret_y1 = minY;
  2080. if (NULL != ret_y2)
  2081. *ret_y2 = maxY;
  2082. return result;
  2083. }
  2084. /*****************************************************************************
  2085. * Function: _DtCvAddToMarkList()
  2086. *
  2087. * Purpose: Add a mark to the list of marks.
  2088. *
  2089. *****************************************************************************/
  2090. int
  2091. _DtCvAddToMarkList (
  2092. _DtCanvasStruct *canvas,
  2093. _DtCvPointer client_data,
  2094. _DtCvValue flag,
  2095. _DtCvSelectData *beg,
  2096. _DtCvSelectData *end)
  2097. {
  2098. _DtCvMarkData *nxtMark;
  2099. /*
  2100. * does the array need more memory?
  2101. */
  2102. if (canvas->mark_cnt >= canvas->mark_max)
  2103. {
  2104. canvas->mark_max += GROW_SIZE;
  2105. if (NULL == canvas->marks)
  2106. canvas->marks = (_DtCvMarkData *) malloc(
  2107. sizeof(_DtCvMarkData) * canvas->mark_max);
  2108. else
  2109. canvas->marks = (_DtCvMarkData *) realloc((void *) canvas->marks,
  2110. sizeof(_DtCvMarkData) * canvas->mark_max);
  2111. /*
  2112. * memory loss - bail
  2113. */
  2114. if (NULL == canvas->marks)
  2115. return -1;
  2116. }
  2117. /*
  2118. * set the mark information
  2119. */
  2120. nxtMark = &(canvas->marks[canvas->mark_cnt]);
  2121. nxtMark->on = flag;
  2122. nxtMark->client_data = client_data;
  2123. nxtMark->beg = *beg;
  2124. nxtMark->end = *end;
  2125. canvas->mark_cnt++;
  2126. return (canvas->mark_cnt - 1);
  2127. }