1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/auxtext.c,v 1.17 2011/05/16 16:21:56 william Exp $
19 */
20
21 #define _INCLUDE_FROM_AUXTEXT_C_
22
23 #include "tgifdefs.h"
24
25 #include "auxtext.e"
26 #include "choice.e"
27 #include "color.e"
28 #include "cursor.e"
29 #include "cutpaste.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "file.e"
33 #include "font.e"
34 #include "miniline.e"
35 #include "msg.e"
36 #include "obj.e"
37 #include "pattern.e"
38 #include "prtgif.e"
39 #include "ps.e"
40 #include "raster.e"
41 #include "rect.e"
42 #include "setup.e"
43 #include "select.e"
44 #include "strtbl.e"
45 #include "text.e"
46 #include "util.e"
47 #include "xbitmap.e"
48 #include "xpixmap.e"
49
50 GC rotateGC=NULL;
51 Pixmap textBackingBitmap=None, textBackingBgBitmap=None;
52 Pixmap textBackingPixmap=None;
53 int textBackingBitmapW=INVALID;
54 int textBackingBitmapH=INVALID;
55 int doubleQuoteDoubleQuote=FALSE;
56 int groupedTextEditable=FALSE;
57
58 struct SelRec *outerSel=NULL, *innerSel=NULL;
59
GetStrSizeInfo(pDynStr,w,lbearing,rextra)60 void GetStrSizeInfo(pDynStr, w, lbearing, rextra)
61 struct DynStrRec *pDynStr;
62 int *w, *lbearing, *rextra;
63 {
64 XCharStruct xcs;
65
66 MyTextExtents(canvasFontPtr, pDynStr->s, pDynStr->sz-1, &xcs);
67 if (w != NULL) *w = xcs.width;
68 if (lbearing != NULL) *lbearing = (xcs.lbearing >= 0 ? 0 : xcs.lbearing);
69 if (rextra != NULL) *rextra = xcs.rbearing-xcs.width;
70 }
71
GetNumberOfMiniLines(minilines)72 int GetNumberOfMiniLines(minilines)
73 MiniLinesInfo *minilines;
74 {
75 int count=0;
76 MiniLineInfo *pMiniLine=minilines->first;
77
78 for ( ; pMiniLine != NULL; pMiniLine=pMiniLine->next, count++) {
79 }
80 return count;
81 }
82
IsHex(ch,pn_val)83 int IsHex(ch, pn_val)
84 char ch;
85 int *pn_val;
86 {
87 if (ch >= '0' && ch <= '9') {
88 *pn_val = ((int)(ch - '0'));
89 return TRUE;
90 }
91 if (ch >= 'a' && ch <= 'f') {
92 *pn_val = 10+((int)(ch - 'a'));
93 return TRUE;
94 }
95 if (ch >= 'A' && ch <= 'F') {
96 *pn_val = 10+((int)(ch - 'F'));
97 return TRUE;
98 }
99 return FALSE;
100 }
101
InputOctalString(pszBuf,pnBufSize)102 int InputOctalString(pszBuf, pnBufSize)
103 char *pszBuf;
104 int *pnBufSize;
105 {
106 int i=0, nBufSizeIn=(*pnBufSize), nError=FALSE;
107 int nPrevIsOctal=FALSE, nByte1OfOctal=TRUE;
108 char *psz=NULL, szSpec[MAXSTRING];
109
110 *pnBufSize = 0;
111 *pszBuf = '\0';
112 *szSpec = '\0';
113 if (canvasFontDoubleByte) {
114 sprintf(gszMsgBox, TgLoadString(STID_INPUT_OCTAL_STR), "\\244\\244");
115 } else {
116 sprintf(gszMsgBox, TgLoadString(STID_INPUT_STR));
117 }
118 Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
119 UtilTrimBlanks(szSpec);
120 if (*szSpec == '\0') return FALSE;
121
122 if (szSpec[0] == '0' && szSpec[1] == 'x') {
123 for (i=0, psz=(&szSpec[2]); !nError && i < nBufSizeIn-1 && *psz != '\0';
124 i++, psz=(&psz[2])) {
125 int hi_nibble=0, lo_nibble=0;
126
127 if (IsHex(psz[0], &hi_nibble) && IsHex(psz[1], &lo_nibble)) {
128 int hval=(((hi_nibble&0x0ff)<<4)+(lo_nibble&0x0ff));
129
130 pszBuf[i] = hval;
131
132 if (canvasFontDoubleByte && canvasFontDoubleByteModBytes) {
133 if ((pszBuf[i] & 0x80) == 0) {
134 pszBuf[i] |= 0x80;
135 }
136 }
137 } else {
138 nError = TRUE;
139 }
140 }
141 } else {
142 for (i=0, psz=szSpec; !nError && i < nBufSizeIn-1 && *psz != '\0';
143 i++, psz++) {
144 int nThisIsOctal=FALSE;
145
146 if (*psz == '\\') {
147 if (psz[1] == '\0') {
148 pszBuf[i] = '\\';
149 } else if (psz[1] == '\\') {
150 pszBuf[i] = '\\';
151 psz++;
152 } else if (psz[1] == 'r') {
153 pszBuf[i] = '\r';
154 psz++;
155 } else if (psz[1] == 'n') {
156 pszBuf[i] = '\n';
157 psz++;
158 } else if (psz[1] >= '0' && psz[1] <= '7') {
159 char *psz1=NULL, saved_ch='\0';
160 int oval=0;
161
162 *psz = '0';
163 for (psz1=(&psz[2]); *psz1 >= '0' && *psz1 <= '7'; psz1++) ;
164 saved_ch = (*psz1);
165 *psz1 = '\0';
166 if (sscanf(psz, "%o", &oval) != 1) {
167 nError = TRUE;
168 } else {
169 pszBuf[i] = (char)(oval & 0xff);
170
171 nThisIsOctal = TRUE;
172 if (canvasFontDoubleByte && canvasFontDoubleByteModBytes) {
173 if (nPrevIsOctal) {
174 nByte1OfOctal = !nByte1OfOctal;
175 } else {
176 nByte1OfOctal = TRUE;
177 }
178 if ((pszBuf[i] & 0x80) == 0) {
179 pszBuf[i] |= 0x80;
180 }
181 }
182 }
183 *psz1 = saved_ch;
184 *psz = '\\';
185 if (!nError) {
186 psz = psz1;
187 psz--;
188 }
189 } else {
190 i--;
191 psz++;
192 }
193 } else {
194 pszBuf[i] = *psz;
195 }
196 nPrevIsOctal = nThisIsOctal;
197 }
198 }
199 if (canvasFontDoubleByte && ((i & 0x1) != 0)) {
200 nError = TRUE;
201 }
202 if (nError) {
203 *pszBuf = '\0';
204 sprintf(gszMsgBox, TgLoadCachedString(CSTID_MALFORMED_INPUT_STR), szSpec);
205 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
206 return FALSE;
207 }
208 pszBuf[i] = '\0';
209 *pnBufSize = i;
210 return TRUE;
211 }
212
CharIsCntrlINS(key_ev,key_sym)213 int CharIsCntrlINS(key_ev, key_sym)
214 XKeyEvent *key_ev;
215 KeySym key_sym;
216 {
217 if (key_ev != NULL && ((key_ev->state & ControlMask) != 0) &&
218 ((key_ev->state & ShiftMask) == 0) &&
219 (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
220 return TRUE;
221 }
222 return FALSE;
223 }
224
CharIsShiftINS(key_ev,key_sym)225 int CharIsShiftINS(key_ev, key_sym)
226 XKeyEvent *key_ev;
227 KeySym key_sym;
228 {
229 if (key_ev != NULL && ((key_ev->state & ControlMask) == 0) &&
230 ((key_ev->state & ShiftMask) != 0) &&
231 (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
232 return TRUE;
233 }
234 return FALSE;
235 }
236
CharIsCntrlShiftINS(key_ev,key_sym)237 int CharIsCntrlShiftINS(key_ev, key_sym)
238 XKeyEvent *key_ev;
239 KeySym key_sym;
240 {
241 if (key_ev != NULL && ((key_ev->state & ControlMask) != 0) &&
242 ((key_ev->state & ShiftMask) != 0) &&
243 (key_sym == XK_Insert || key_sym == XK_KP_Insert)) {
244 return TRUE;
245 }
246 return FALSE;
247 }
248
249 /*
250 * int has_ch=XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
251 *
252 * TranslateKeys(buf, &key_sym);
253 *
254 * if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
255 * } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
256 * } else if (CharIsBSorDEL(key_ev, buf, key_sym, &has_ch, FALSE)) {
257 * } else if (CharIsTAB(key_ev, buf, key_sym, &has_ch)) {
258 * }
259 */
CharIsESC(key_ev,psz_buf,key_sym,pn_has_ch)260 int CharIsESC(key_ev, psz_buf, key_sym, pn_has_ch)
261 XKeyEvent *key_ev;
262 char *psz_buf;
263 KeySym key_sym;
264 int *pn_has_ch;
265 {
266 if (key_sym == XK_Escape) return TRUE;
267 if (key_ev != NULL && (key_ev->state & ControlMask) &&
268 key_sym == XK_bracketleft) {
269 return TRUE;
270 }
271 if (pn_has_ch != NULL) {
272 return ((*pn_has_ch) && *psz_buf == '\033');
273 }
274 return (*psz_buf == '\033');
275 }
276
CharIsCRorLF(key_ev,psz_buf,key_sym,pn_has_ch)277 int CharIsCRorLF(key_ev, psz_buf, key_sym, pn_has_ch)
278 XKeyEvent *key_ev;
279 char *psz_buf;
280 KeySym key_sym;
281 int *pn_has_ch;
282 {
283 if (key_sym==XK_Return || key_sym==XK_KP_Enter || key_sym==XK_Linefeed) {
284 return TRUE;
285 }
286 if (key_ev != NULL && (key_ev->state & ControlMask) &&
287 (key_sym == XK_m || key_sym == XK_j)) {
288 return TRUE;
289 }
290 if (pn_has_ch != NULL) {
291 return ((*pn_has_ch) && (*psz_buf == '\r' || *psz_buf == '\n'));
292 }
293 return (*psz_buf == '\r' || *psz_buf == '\n');
294 }
295
CharIsDEL(key_ev,psz_buf,key_sym,pn_has_ch)296 int CharIsDEL(key_ev, psz_buf, key_sym, pn_has_ch)
297 XKeyEvent *key_ev;
298 char *psz_buf;
299 KeySym key_sym;
300 int *pn_has_ch;
301 {
302 if (key_sym==XK_Delete || key_sym==XK_KP_Delete) {
303 return TRUE;
304 }
305 if (pn_has_ch != NULL) {
306 return ((*pn_has_ch) && (*psz_buf == '\177'));
307 }
308 return (*psz_buf == '\177');
309 }
310
CharIsBS(key_ev,psz_buf,key_sym,pn_has_ch,left_is_BS)311 int CharIsBS(key_ev, psz_buf, key_sym, pn_has_ch, left_is_BS)
312 XKeyEvent *key_ev;
313 char *psz_buf;
314 KeySym key_sym;
315 int *pn_has_ch, left_is_BS;
316 {
317 if ((left_is_BS && (key_sym==XK_Left || key_sym==XK_KP_Left)) ||
318 key_sym==XK_BackSpace) {
319 return TRUE;
320 }
321 if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_h)) {
322 return TRUE;
323 }
324 if (pn_has_ch != NULL) {
325 return ((*pn_has_ch) && (*psz_buf == '\b'));
326 }
327 return (*psz_buf == '\b');
328 }
329
CharIsBSorDEL(key_ev,psz_buf,key_sym,pn_has_ch,left_is_BS)330 int CharIsBSorDEL(key_ev, psz_buf, key_sym, pn_has_ch, left_is_BS)
331 XKeyEvent *key_ev;
332 char *psz_buf;
333 KeySym key_sym;
334 int *pn_has_ch, left_is_BS;
335 {
336 if ((left_is_BS && (key_sym==XK_Left || key_sym==XK_KP_Left)) ||
337 key_sym==XK_BackSpace || key_sym==XK_Delete || key_sym==XK_KP_Delete) {
338 return TRUE;
339 }
340 if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_h)) {
341 return TRUE;
342 }
343 if (pn_has_ch != NULL) {
344 return ((*pn_has_ch) && (*psz_buf == '\b' || *psz_buf == '\177'));
345 }
346 return (*psz_buf == '\b' || *psz_buf == '\177');
347 }
348
CharIsTAB(key_ev,psz_buf,key_sym,pn_has_ch)349 int CharIsTAB(key_ev, psz_buf, key_sym, pn_has_ch)
350 XKeyEvent *key_ev;
351 char *psz_buf;
352 KeySym key_sym;
353 int *pn_has_ch;
354 {
355 if (key_sym==XK_Tab || key_sym==XK_KP_Tab) {
356 return TRUE;
357 }
358 if (key_ev != NULL && (key_ev->state & ControlMask) && (key_sym == XK_i)) {
359 return TRUE;
360 }
361 if (pn_has_ch != NULL) {
362 return ((*pn_has_ch) && (*psz_buf == '\t'));
363 }
364 return (*psz_buf == '\t');
365 }
366
CharIsHome(key_ev,psz_buf,key_sym,pn_has_ch)367 int CharIsHome(key_ev, psz_buf, key_sym, pn_has_ch)
368 XKeyEvent *key_ev;
369 char *psz_buf;
370 KeySym key_sym;
371 int *pn_has_ch;
372 {
373 return (key_sym==XK_Home || key_sym==XK_KP_Home);
374 }
375
CharIsEnd(key_ev,psz_buf,key_sym,pn_has_ch)376 int CharIsEnd(key_ev, psz_buf, key_sym, pn_has_ch)
377 XKeyEvent *key_ev;
378 char *psz_buf;
379 KeySym key_sym;
380 int *pn_has_ch;
381 {
382 return (key_sym==XK_End || key_sym==XK_KP_End);
383 }
384
CharIsCntrlSpace(key_ev,psz_buf,key_sym,pn_has_ch)385 int CharIsCntrlSpace(key_ev, psz_buf, key_sym, pn_has_ch)
386 XKeyEvent *key_ev;
387 char *psz_buf;
388 KeySym key_sym;
389 int *pn_has_ch;
390 {
391 int state=key_ev->state;
392
393 if (((state & ControlMask) == ControlMask) && ((state & METAMASK) == 0)) {
394 if (key_sym == XK_space || (psz_buf[0] == ' ' && psz_buf[1] == '\0')) {
395 return TRUE;
396 } else if (key_sym == XK_backslash || (psz_buf[0] == '\\' &&
397 psz_buf[1] == '\0')) {
398 return TRUE;
399 }
400 }
401 return FALSE;
402 }
403
TranslateKeys(s,key_sym)404 void TranslateKeys(s, key_sym)
405 char *s;
406 KeySym *key_sym;
407 {
408 switch (*key_sym) {
409 case XK_KP_Space: *key_sym=XK_space; s[0]=' '; s[1]='\0'; break;
410 case XK_KP_Tab: *key_sym=XK_Tab; s[0]='\t'; s[1]='\0'; break;
411 case XK_KP_Enter: *key_sym=XK_Return; s[0]='\r'; s[1]='\0'; break;
412 case XK_KP_Equal: *key_sym=XK_equal; s[0]='='; s[1]='\0'; break;
413 case XK_KP_Multiply: *key_sym=XK_multiply; s[0]='*'; s[1]='\0'; break;
414 case XK_KP_Add: *key_sym=XK_plus; s[0]='+'; s[1]='\0'; break;
415 case XK_KP_Separator: *key_sym=XK_comma; s[0]=','; s[1]='\0'; break;
416 case XK_KP_Subtract: *key_sym=XK_minus; s[0]='-'; s[1]='\0'; break;
417 case XK_KP_Decimal: *key_sym=XK_period; s[0]='.'; s[1]='\0'; break;
418 case XK_KP_Divide: *key_sym=XK_slash; s[0]='/'; s[1]='\0'; break;
419
420 case XK_KP_0: *key_sym=XK_0; s[0]='0'; s[1]='\0'; break;
421 case XK_KP_1: *key_sym=XK_1; s[0]='1'; s[1]='\0'; break;
422 case XK_KP_2: *key_sym=XK_2; s[0]='2'; s[1]='\0'; break;
423 case XK_KP_3: *key_sym=XK_3; s[0]='3'; s[1]='\0'; break;
424 case XK_KP_4: *key_sym=XK_4; s[0]='4'; s[1]='\0'; break;
425 case XK_KP_5: *key_sym=XK_5; s[0]='5'; s[1]='\0'; break;
426 case XK_KP_6: *key_sym=XK_6; s[0]='6'; s[1]='\0'; break;
427 case XK_KP_7: *key_sym=XK_7; s[0]='7'; s[1]='\0'; break;
428 case XK_KP_8: *key_sym=XK_8; s[0]='8'; s[1]='\0'; break;
429 case XK_KP_9: *key_sym=XK_9; s[0]='9'; s[1]='\0'; break;
430 }
431 }
432
433 static
GetTransformedTextBBoxAbsVs(ObjPtr,LBearing,RightExtra,Vs)434 void GetTransformedTextBBoxAbsVs(ObjPtr, LBearing, RightExtra, Vs)
435 struct ObjRec *ObjPtr;
436 int LBearing, RightExtra;
437 IntPoint *Vs; /* array of 5 points */
438 {
439 int x, y;
440 struct BBRec bbox;
441
442 bbox.ltx = ObjPtr->orig_obbox.ltx - ObjPtr->x + LBearing;
443 bbox.lty = ObjPtr->orig_obbox.lty - ObjPtr->y;
444 bbox.rbx = ObjPtr->orig_obbox.rbx - ObjPtr->x + RightExtra;
445 bbox.rby = ObjPtr->orig_obbox.rby - ObjPtr->y;
446 TransformOffsetBBoxThroughCTM(&bbox, ObjPtr->ctm, Vs);
447 x = Vs[0].x + ObjPtr->x; y = Vs[0].y + ObjPtr->y;
448 Vs[0].x = Vs[4].x = x; Vs[0].y = Vs[4].y = y;
449 x = Vs[1].x + ObjPtr->x; y = Vs[1].y + ObjPtr->y;
450 Vs[1].x = x; Vs[1].y = y;
451 x = Vs[2].x + ObjPtr->x; y = Vs[2].y + ObjPtr->y;
452 Vs[2].x = x; Vs[2].y = y;
453 x = Vs[3].x + ObjPtr->x; y = Vs[3].y + ObjPtr->y;
454 Vs[3].x = x; Vs[3].y = y;
455 }
456
SetTextOBBox(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)457 void SetTextOBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
458 struct ObjRec *ObjPtr;
459 int Just, W, H, LBearing, RightExtra, Rotate;
460 { /* In this procedure, it is assumed that the x and y field */
461 /* of the text object has the correct information.*/
462 /* The rotation is clockwise */
463 register int mw2, pw2;
464
465 if (ObjPtr->ctm == NULL) {
466 switch (Just) {
467 case JUST_L:
468 switch (Rotate) {
469 case ROTATE0:
470 ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+W;
471 ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
472 break;
473 case ROTATE90:
474 ObjPtr->obbox.ltx = ObjPtr->x-H; ObjPtr->obbox.rbx = ObjPtr->x;
475 ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+W;
476 break;
477 case ROTATE180:
478 ObjPtr->obbox.ltx = ObjPtr->x-W; ObjPtr->obbox.rbx = ObjPtr->x;
479 ObjPtr->obbox.lty = ObjPtr->y-H; ObjPtr->obbox.rby = ObjPtr->y;
480 break;
481 case ROTATE270:
482 ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+H;
483 ObjPtr->obbox.lty = ObjPtr->y-W; ObjPtr->obbox.rby = ObjPtr->y;
484 break;
485 }
486 break;
487 case JUST_C:
488 mw2 = W/2;
489 pw2 = W-W/2;
490 switch (Rotate) {
491 case ROTATE0:
492 ObjPtr->obbox.ltx = ObjPtr->x-mw2;
493 ObjPtr->obbox.rbx = ObjPtr->x+pw2;
494 ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
495 break;
496 case ROTATE90:
497 ObjPtr->obbox.ltx = ObjPtr->x-H;
498 ObjPtr->obbox.rbx = ObjPtr->x;
499 ObjPtr->obbox.lty = ObjPtr->y-mw2;
500 ObjPtr->obbox.rby = ObjPtr->y+pw2;
501 break;
502 case ROTATE180:
503 ObjPtr->obbox.ltx = ObjPtr->x-pw2;
504 ObjPtr->obbox.rbx = ObjPtr->x+mw2;
505 ObjPtr->obbox.lty = ObjPtr->y-H;
506 ObjPtr->obbox.rby = ObjPtr->y;
507 break;
508 case ROTATE270:
509 ObjPtr->obbox.ltx = ObjPtr->x;
510 ObjPtr->obbox.rbx = ObjPtr->x+H;
511 ObjPtr->obbox.lty = ObjPtr->y-pw2;
512 ObjPtr->obbox.rby = ObjPtr->y+mw2;
513 break;
514 }
515 break;
516 case JUST_R:
517 switch (Rotate) {
518 case ROTATE0:
519 ObjPtr->obbox.ltx = ObjPtr->x-W; ObjPtr->obbox.rbx = ObjPtr->x;
520 ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+H;
521 break;
522 case ROTATE90:
523 ObjPtr->obbox.ltx = ObjPtr->x-H; ObjPtr->obbox.rbx = ObjPtr->x;
524 ObjPtr->obbox.lty = ObjPtr->y-W; ObjPtr->obbox.rby = ObjPtr->y;
525 break;
526 case ROTATE180:
527 ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+W;
528 ObjPtr->obbox.lty = ObjPtr->y-H; ObjPtr->obbox.rby = ObjPtr->y;
529 break;
530 case ROTATE270:
531 ObjPtr->obbox.ltx = ObjPtr->x; ObjPtr->obbox.rbx = ObjPtr->x+H;
532 ObjPtr->obbox.lty = ObjPtr->y; ObjPtr->obbox.rby = ObjPtr->y+W;
533 break;
534 }
535 break;
536 }
537 } else {
538 IntPoint abs_obj_obbox_vs[5];
539
540 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
541 ObjPtr->obbox.ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
542 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
543 ObjPtr->obbox.rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
544 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
545 ObjPtr->obbox.lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
546 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
547 ObjPtr->obbox.rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
548 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
549 }
550 }
551
SetTextBBox(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)552 void SetTextBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
553 struct ObjRec *ObjPtr;
554 int Just, W, H, LBearing, RightExtra, Rotate;
555 /* In this procedure, it is assumed that the x and y field */
556 /* of the text object has the correct information.*/
557 /* The rotation is clockwise */
558 {
559 SetTextOBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate);
560
561 if (ObjPtr->ctm == NULL) {
562 switch (Rotate) {
563 case ROTATE0:
564 ObjPtr->bbox.ltx = ObjPtr->obbox.ltx + LBearing;
565 ObjPtr->bbox.rbx = ObjPtr->obbox.rbx + RightExtra;
566 ObjPtr->bbox.lty = ObjPtr->obbox.lty;
567 ObjPtr->bbox.rby = ObjPtr->obbox.rby;
568 break;
569 case ROTATE90:
570 ObjPtr->bbox.ltx = ObjPtr->obbox.ltx;
571 ObjPtr->bbox.rbx = ObjPtr->obbox.rbx;
572 ObjPtr->bbox.lty = ObjPtr->obbox.lty + LBearing;
573 ObjPtr->bbox.rby = ObjPtr->obbox.rby + RightExtra;
574 break;
575 case ROTATE180:
576 ObjPtr->bbox.ltx = ObjPtr->obbox.ltx - RightExtra;
577 ObjPtr->bbox.rbx = ObjPtr->obbox.rbx - LBearing;
578 ObjPtr->bbox.lty = ObjPtr->obbox.lty;
579 ObjPtr->bbox.rby = ObjPtr->obbox.rby;
580 break;
581 case ROTATE270:
582 ObjPtr->bbox.ltx = ObjPtr->obbox.ltx;
583 ObjPtr->bbox.rbx = ObjPtr->obbox.rbx;
584 ObjPtr->bbox.lty = ObjPtr->obbox.lty - RightExtra;
585 ObjPtr->bbox.rby = ObjPtr->obbox.rby - LBearing;
586 break;
587 }
588 } else {
589 IntPoint abs_obj_bbox_vs[5];
590
591 GetTransformedTextBBoxAbsVs(ObjPtr, LBearing, RightExtra,
592 abs_obj_bbox_vs);
593 ObjPtr->bbox.ltx = min(min(abs_obj_bbox_vs[0].x,abs_obj_bbox_vs[1].x),
594 min(abs_obj_bbox_vs[2].x,abs_obj_bbox_vs[3].x));
595 ObjPtr->bbox.rbx = max(max(abs_obj_bbox_vs[0].x,abs_obj_bbox_vs[1].x),
596 max(abs_obj_bbox_vs[2].x,abs_obj_bbox_vs[3].x));
597 ObjPtr->bbox.lty = min(min(abs_obj_bbox_vs[0].y,abs_obj_bbox_vs[1].y),
598 min(abs_obj_bbox_vs[2].y,abs_obj_bbox_vs[3].y));
599 ObjPtr->bbox.rby = max(max(abs_obj_bbox_vs[0].y,abs_obj_bbox_vs[1].y),
600 max(abs_obj_bbox_vs[2].y,abs_obj_bbox_vs[3].y));
601 }
602 ObjPtr->bbox.ltx--;
603 ObjPtr->bbox.rbx++;
604 ObjPtr->bbox.lty--;
605 ObjPtr->bbox.rby++;
606 }
607
SetTextOrigBBoxes(ObjPtr,Just,W,H,LBearing,RightExtra,Rotate)608 void SetTextOrigBBoxes(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate)
609 struct ObjRec *ObjPtr;
610 int Just, W, H, LBearing, RightExtra, Rotate;
611 /* In this procedure, it is assumed that the x and y field */
612 /* of the text object has the correct information.*/
613 /* The rotation is clockwise */
614 {
615 struct BBRec obbox, bbox;
616 struct XfrmMtrxRec *ctm;
617
618 if (ObjPtr->ctm == NULL) return;
619 memcpy(&obbox, &ObjPtr->obbox, sizeof(struct BBRec));
620 memcpy(&bbox, &ObjPtr->bbox, sizeof(struct BBRec));
621 ctm = ObjPtr->ctm;
622 ObjPtr->ctm = NULL;
623
624 SetTextBBox(ObjPtr, Just, W, H, LBearing, RightExtra, Rotate);
625
626 memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
627 memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox, sizeof(struct BBRec));
628 ObjPtr->ctm = ctm;
629 }
630
UpdTextBBox(ObjPtr)631 int UpdTextBBox(ObjPtr)
632 struct ObjRec *ObjPtr;
633 /*
634 * This function should be called every time any part of a text object is
635 * changed.
636 * Therefore, it should never be called if PRTGIF.
637 * Returns FALSE if the text object is changed.
638 */
639 {
640 struct TextRec *text_ptr=ObjPtr->detail.t;
641 int read_only=FALSE;
642 #ifdef _TGIF_DBG /* debug, do not translate */
643 int saved_baseline_y=text_ptr->baseline_y;
644
645 #endif /* _TGIF_DBG */
646
647 if (mainDisplay == NULL) return FALSE;
648
649 #ifdef _TGIF_DBG /* debug, do not translate */
650 if (PRTGIF && !cmdLineOpenDisplay) {
651 fprintf(stderr, "UpdTextBBox() called in PRTGIF!\n");
652 }
653 #endif /* _TGIF_DBG */
654 if (text_ptr->read_only) {
655 return TRUE;
656 }
657 PushCurFont();
658
659 ObjFontInfoToCurFontInfo(text_ptr);
660 allowFontFaceSubstitution = FALSE;
661 read_only = (!RecalcTextMetrics(text_ptr, ObjPtr->x, text_ptr->baseline_y));
662 allowFontFaceSubstitution = TRUE;
663
664 #ifdef _TGIF_DBG /* debug, do not translate */
665 if (text_ptr->baseline_y != saved_baseline_y) {
666 TgAssert(FALSE,
667 "Text_ptr->baseline_y changed in UpdTextBBox()", "Restored");
668 text_ptr->baseline_y = saved_baseline_y;
669 }
670 #endif /* _TGIF_DBG */
671
672 if (read_only) {
673 PopCurFont();
674 return FALSE;
675 }
676 ObjPtr->y = text_ptr->baseline_y - text_ptr->minilines.first->asc;
677
678 SetTextOrigBBoxes(ObjPtr, textJust, text_ptr->w, text_ptr->h,
679 text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
680 SetTextBBox(ObjPtr, textJust, text_ptr->w, text_ptr->h,
681 text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
682
683 PopCurFont();
684 return (!read_only);
685 }
686
PixelOnOff(image,col_start,row_start,scale)687 int PixelOnOff(image, col_start, row_start, scale)
688 XImage *image;
689 int col_start, row_start, scale;
690 {
691 register int m, n;
692 int on_count=0, off_count=0;
693
694 if (scale == 2) {
695 for (m = 0; m < 2; m++) {
696 for (n = 0; n < 2; n++) {
697 switch (XGetPixel(image,col_start+n,row_start+m)) {
698 case 0: if (++off_count > 2) return 0; break;
699 case 1: if (++on_count >= 2) return 1; break;
700 }
701 }
702 }
703 } else if (scale > 2) {
704 int half_scale=scale>>1;
705
706 for (m = 0; m < 2; m++) {
707 for (n = 0; n < 2; n++) {
708 switch (PixelOnOff(image, col_start+n*half_scale,
709 row_start+m*half_scale, half_scale)) {
710 case 0: if (++off_count > 2) return 0; break;
711 case 1: if (++on_count >= 2) return 1; break;
712 }
713 }
714 }
715 } else {
716 return 1;
717 }
718 return 0;
719 }
720
721 static
PaintBackingPixmap(text_ptr,bbox_w,bbox_h,min_lbearing,max_rextra,baseline_y)722 int PaintBackingPixmap(text_ptr, bbox_w, bbox_h, min_lbearing, max_rextra,
723 baseline_y)
724 struct TextRec *text_ptr;
725 int bbox_w, bbox_h, min_lbearing, max_rextra, baseline_y;
726 /*
727 * bbox_w includes left bearing and right extra.
728 */
729 {
730 MiniLinesInfo *minilines=(&text_ptr->minilines);
731 int x=0, w=minilines->w, saved_pen=penPat, saved_trans_pat=transPat;
732
733 if (bbox_w > textBackingBitmapW || bbox_h > textBackingBitmapH) {
734 int tmp_w, tmp_h;
735
736 if (textBackingBitmap != None) {
737 XFreePixmap(mainDisplay, textBackingBitmap);
738 }
739 if (textBackingBgBitmap != None) {
740 XFreePixmap(mainDisplay, textBackingBgBitmap);
741 }
742 if (textBackingPixmap != None) {
743 XFreePixmap(mainDisplay, textBackingPixmap);
744 }
745 tmp_w = max(bbox_w,textBackingBitmapW);
746 tmp_h = max(bbox_h,textBackingBitmapH);
747 textBackingBitmap = XCreatePixmap(mainDisplay, mainWindow,
748 tmp_w, tmp_h, 1);
749 textBackingBgBitmap = XCreatePixmap(mainDisplay, mainWindow,
750 tmp_w, tmp_h, 1);
751 textBackingPixmap = XCreatePixmap(mainDisplay, mainWindow,
752 tmp_w, tmp_h, mainDepth);
753 if (textBackingBitmap == None || textBackingBgBitmap == None ||
754 textBackingPixmap == None) {
755 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
756 return FailAllocPixmapMessage(tmp_w, tmp_h);
757 }
758 textBackingBitmapW = tmp_w;
759 textBackingBitmapH = tmp_h;
760 }
761 switch (textJust) {
762 case JUST_L: x = (-min_lbearing); break;
763 case JUST_C:
764 x = ((bbox_w+min_lbearing-max_rextra-w)>>1)-min_lbearing+(w>>1);
765 break;
766 case JUST_R: x = bbox_w-max_rextra; break;
767 }
768 XFillRectangle(mainDisplay, textBackingPixmap, xpmGC, 0, 0, bbox_w, bbox_h);
769 XSetForeground(mainDisplay, rotateGC, 0);
770 XFillRectangle(mainDisplay, textBackingBitmap, rotateGC, 0, 0, bbox_w,
771 bbox_h);
772 XFillRectangle(mainDisplay, textBackingBgBitmap, rotateGC, 0, 0, bbox_w,
773 bbox_h);
774 XSetForeground(mainDisplay, rotateGC, 1);
775
776 ResetDirtyBBoxInfo();
777 transPat = FALSE;
778 penPat = SOLIDPAT;
779 PaintMiniLines(mainDisplay, textBackingBgBitmap, rotateGC, 1,
780 x, baseline_y, minilines, FALSE, TRUE);
781
782 penPat = text_ptr->pen;
783 PaintMiniLines(mainDisplay, textBackingBitmap, rotateGC, 1,
784 x, baseline_y, minilines, FALSE, TRUE);
785 PaintMiniLines(mainDisplay, textBackingPixmap, xpmGC, mainDepth,
786 x, baseline_y, minilines, FALSE, FALSE);
787
788 penPat = saved_pen;
789 transPat = saved_trans_pat;
790
791 return TRUE;
792 }
793
794 #ifdef NOT_DEFINED
795 #ifdef _TGIF_DBG /* debug, do not translate */
796 static
DebugCachedTextBitmapImage(image,before,w,h,min_lbearing,max_rextra)797 void DebugCachedTextBitmapImage(image, before, w, h, min_lbearing, max_rextra)
798 XImage *image;
799 int before, w, h, min_lbearing, max_rextra;
800 {
801 int i=0;
802
803 if (before) fprintf(stderr, "\n");
804 fprintf(stderr, " w = %1d\n", w);
805 fprintf(stderr, " h = %1d\n", h);
806 if (before) {
807 fprintf(stderr, "min_lbearing = %1d\n", min_lbearing);
808 fprintf(stderr, " max_rextra = %1d\n", max_rextra);
809 }
810 for (i=0; i < h; i++) {
811 int j=0;
812
813 for (j=0; j < w; j++) {
814 int data=XGetPixel(image,j,i);
815
816 fprintf(stderr, "%c%s", (data==1 ? 'X' : ' '), (j+1 == w ? "\n" : ""));
817 }
818 }
819 }
820 #endif /* _TGIF_DBG */
821 #endif /* NOT_DEFINED */
822
MakeCachedTextBitmap(ObjPtr)823 void MakeCachedTextBitmap(ObjPtr)
824 struct ObjRec *ObjPtr;
825 {
826 int r=0, c=0, bbox_w=0, bbox_h=0, num_cols=0, num_rows=0;
827 int watch_cursor=FALSE, do_msg=FALSE, min_lbearing=0, max_rextra=0;
828 int flat=FALSE, skinny=FALSE, start_row=0, start_col=0, ok=FALSE;
829 struct MtrxRec mtrx;
830 Pixmap dest_bitmap=None, dest_bg_bitmap=None, dest_pixmap=None;
831 XImage *src_image=NULL, *src_bitmap_image=NULL, *src_bitmap_bg_image=NULL;
832 XImage *dest_image=NULL, *dest_bitmap_image=NULL, *dest_bitmap_bg_image=NULL;
833 struct TextRec *text_ptr=ObjPtr->detail.t;
834
835 if (ObjPtr->ctm == NULL && text_ptr->cached_bitmap != None &&
836 text_ptr->cached_zoomed == zoomedIn &&
837 text_ptr->cached_zoom == zoomScale) {
838 return;
839 }
840 if (ObjPtr->obbox.ltx==ObjPtr->obbox.rbx ||
841 ObjPtr->obbox.lty==ObjPtr->obbox.rby) {
842 return;
843 }
844 InvalidateTextCache(text_ptr);
845
846 if (PRTGIF) {
847 RecalcTextMetrics(text_ptr, ObjPtr->x, text_ptr->baseline_y);
848 }
849 if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
850 if (RestoreEditTextSize(ObjPtr, TRUE)) {
851 UpdTextBBox(ObjPtr);
852 }
853 }
854 if (text_ptr->read_only) {
855 min_lbearing = text_ptr->min_lbearing;
856 max_rextra = text_ptr->max_rextra;
857 bbox_w = text_ptr->orig_w;
858 bbox_h = text_ptr->orig_h;
859 } else {
860 min_lbearing = text_ptr->min_lbearing;
861 max_rextra = text_ptr->max_rextra;
862 bbox_w = text_ptr->w - min_lbearing + max_rextra;
863 bbox_h = text_ptr->h;
864 }
865 ok = PaintBackingPixmap(text_ptr, bbox_w, bbox_h, min_lbearing,
866 max_rextra, text_ptr->minilines.first->asc);
867 if (curChoice == DRAWTEXT && textCursorShown && ObjPtr == curTextObj) {
868 if (RestoreEditTextSize(ObjPtr, FALSE)) {
869 UpdTextBBox(ObjPtr);
870 }
871 }
872 if (!ok) {
873 return;
874 }
875 watch_cursor = watchCursorOnMainWindow;
876 if (!watch_cursor && !RedrawDuringScrolling()) {
877 SetWatchCursor(drawWindow);
878 SetWatchCursor(mainWindow);
879 } else {
880 CheckInterrupt(TRUE);
881 }
882 src_image = XGetImage(mainDisplay, textBackingPixmap, 0, 0, bbox_w, bbox_h,
883 AllPlanes, ZPixmap);
884 src_bitmap_image = XGetImage(mainDisplay, textBackingBitmap, 0, 0,
885 bbox_w, bbox_h, 1, ZPixmap);
886 src_bitmap_bg_image = XGetImage(mainDisplay, textBackingBgBitmap, 0, 0,
887 bbox_w, bbox_h, 1, ZPixmap);
888
889 if (ObjPtr->ctm == NULL) {
890 if (text_ptr->read_only) {
891 num_cols = ObjPtr->bbox.rbx - ObjPtr->bbox.ltx - 2;
892 num_rows = ObjPtr->bbox.rby - ObjPtr->bbox.lty - 2;
893 } else {
894 num_cols = bbox_w; num_rows = bbox_h;
895 }
896 if (zoomedIn || zoomScale == 0) {
897 num_cols <<= zoomScale;
898 num_rows <<= zoomScale;
899 } else {
900 num_cols >>= zoomScale;
901 num_rows >>= zoomScale;
902 }
903 } else {
904 num_cols = ZOOMED_SIZE(ObjPtr->bbox.rbx - ObjPtr->bbox.ltx - 2);
905 num_rows = ZOOMED_SIZE(ObjPtr->bbox.rby - ObjPtr->bbox.lty - 2);
906 }
907 if (num_cols == 0) {
908 skinny = TRUE;
909 num_cols = 1;
910 }
911 if (num_rows == 0) {
912 flat = TRUE;
913 num_rows = 1;
914 }
915 do_msg = (((num_rows*num_cols)>=0x4000) && !RedrawDuringScrolling());
916 if (do_msg) {
917 SaveStatusStrings();
918 SetStringStatus(TgLoadCachedString(CSTID_CACHING_TEXT_BMP));
919 XSync(mainDisplay, False);
920 }
921 dest_bitmap = XCreatePixmap(mainDisplay,mainWindow,num_cols,num_rows,1);
922 dest_bg_bitmap = XCreatePixmap(mainDisplay,mainWindow,num_cols,num_rows,1);
923 XSetForeground(mainDisplay, rotateGC, 0);
924 XFillRectangle(mainDisplay,dest_bitmap,rotateGC,0,0,num_cols,num_rows);
925 XFillRectangle(mainDisplay,dest_bg_bitmap,rotateGC,0,0,num_cols,num_rows);
926 dest_pixmap = XCreatePixmap(mainDisplay, mainWindow, num_cols, num_rows,
927 mainDepth);
928 XFillRectangle(mainDisplay, dest_pixmap, xpmGC, 0, 0, num_cols, num_rows);
929
930 dest_image = XGetImage(mainDisplay, dest_pixmap, 0, 0, num_cols,
931 num_rows, AllPlanes, ZPixmap);
932 dest_bitmap_image = XGetImage(mainDisplay, dest_bitmap, 0, 0, num_cols,
933 num_rows, 1, ZPixmap);
934 dest_bitmap_bg_image = XGetImage(mainDisplay, dest_bg_bitmap, 0, 0, num_cols,
935 num_rows, 1, ZPixmap);
936
937 if (!flat && !skinny) {
938 #ifdef NOT_DEFINED
939 #ifdef _TGIF_DBG
940 DebugCachedTextBitmapImage(src_bitmap_image, TRUE, bbox_w, bbox_h,
941 min_lbearing, max_rextra);
942 #endif /* _TGIF_DBG */
943 #endif /* NOT_DEFINED */
944 if (ObjPtr->ctm == NULL) {
945 mtrx.image_w = (float)bbox_w;
946 mtrx.image_h = (float)bbox_h;
947 mtrx.w = (float)num_cols;
948 mtrx.h = (float)num_rows;
949 mtrx.rotate = ROTATE0;
950 mtrx.flip = NO_FLIP;
951
952 CalcTransform(&mtrx);
953
954 start_col = (mtrx.transformed_w >= 0.0) ? 0 : (-num_cols)+1;
955 start_row = (mtrx.transformed_h >= 0.0) ? 0 : (-num_rows)+1;
956
957 for (r=0; r < num_rows; r++) {
958 double part_x, part_y;
959
960 if (do_msg && ((r & 0xf) == 0)) {
961 int percent=(r*10000/num_rows)/100;
962
963 sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROGRESS_PERCENT),
964 percent);
965 SetStringStatus(gszMsgBox);
966 XSync(mainDisplay, False);
967 }
968 part_x = ((double)(r+start_row)+0.5)*(mtrx.rev_m[1][0]);
969 part_y = ((double)(r+start_row)+0.5)*(mtrx.rev_m[1][1]);
970 for (c=0; c < num_cols; c++) {
971 double x, y;
972
973 x = part_x+((double)(c+start_col)+0.5)*(mtrx.rev_m[0][0]);
974 y = part_y+((double)(c+start_col)+0.5)*(mtrx.rev_m[0][1]);
975 if (x >= ((double)0) && x < ((double)bbox_w) &&
976 y >= ((double)0) && y < ((double)bbox_h)) {
977 int new_x=(int)x, new_y=(int)y;
978
979 if (new_x < 0) new_x = 0;
980 if (new_x >= bbox_w) new_x = bbox_w-1;
981 if (new_y < 0) new_y = 0;
982 if (new_y >= bbox_h) new_y = bbox_h-1;
983 if (XGetPixel(src_bitmap_image, new_x, new_y) == 1) {
984 int dest_pixel=XGetPixel(src_image, new_x, new_y);
985
986 XPutPixel(dest_bitmap_image, c, r, 1);
987 XPutPixel(dest_image, c, r, dest_pixel);
988 }
989 if (XGetPixel(src_bitmap_bg_image, new_x, new_y) == 1) {
990 XPutPixel(dest_bitmap_bg_image, c, r, 1);
991 }
992 }
993 }
994 }
995 } else {
996 int abs_offset_x=ObjPtr->bbox.ltx+1-ObjPtr->x;
997 int abs_offset_y=ObjPtr->bbox.lty+1-ObjPtr->y;
998 int abs_adj_x=ObjPtr->x-ObjPtr->orig_obbox.ltx;
999 int abs_adj_y=ObjPtr->y-ObjPtr->orig_obbox.lty;
1000
1001 for (r=0; r < num_rows; r++) {
1002 int y=abs_offset_y+ABS_SIZE(r);
1003 double dy=((double)y)+0.5;
1004
1005 if (do_msg && ((r & 0xf) == 0)) {
1006 int percent=(r*10000/num_rows)/100;
1007
1008 sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROGRESS_PERCENT),
1009 percent);
1010 SetStringStatus(gszMsgBox);
1011 XSync(mainDisplay, False);
1012 }
1013 for (c=0; c < num_cols; c++) {
1014 int x=abs_offset_x+ABS_SIZE(c);
1015 double dx=((double)x)+0.5;
1016 double new_dx=((double)0), new_dy=((double)0);
1017
1018 ReverseTransformDoublePointThroughCTM(dx, dy, ObjPtr->ctm,
1019 &new_dx, &new_dy);
1020 new_dx += (double)abs_adj_x;
1021 new_dy += (double)abs_adj_y;
1022 if (new_dx >= ((double)0) && new_dx < ((double)bbox_w) &&
1023 new_dy >= ((double)0) && new_dy < ((double)bbox_h)) {
1024 int new_x=(int)new_dx, new_y=(int)new_dy;
1025
1026 if (new_x < 0) new_x = 0;
1027 if (new_x >= bbox_w) new_x = bbox_w-1;
1028 if (new_y < 0) new_y = 0;
1029 if (new_y >= bbox_h) new_y = bbox_h-1;
1030 if (XGetPixel(src_bitmap_image, new_x, new_y) == 1) {
1031 int dest_pixel=XGetPixel(src_image, new_x, new_y);
1032
1033 XPutPixel(dest_bitmap_image, c, r, 1);
1034 XPutPixel(dest_image, c, r, dest_pixel);
1035 }
1036 if (XGetPixel(src_bitmap_bg_image, new_x, new_y) == 1) {
1037 XPutPixel(dest_bitmap_bg_image, c, r, 1);
1038 }
1039 }
1040 }
1041 }
1042 memcpy(&text_ptr->cached_ctm,ObjPtr->ctm,sizeof(struct XfrmMtrxRec));
1043 }
1044 #ifdef NOT_DEFINED
1045 #ifdef _TGIF_DBG
1046 DebugCachedTextBitmapImage(dest_bitmap_image, FALSE, num_cols, num_rows,
1047 0, 0);
1048 #endif /* _TGIF_DBG */
1049 #endif /* NOT_DEFINED */
1050 }
1051 if (do_msg) {
1052 SetStringStatus(TgLoadCachedString(CSTID_FINISHED_CACHEING_TEXT_BMP));
1053 XSync(mainDisplay, False);
1054 }
1055 XPutImage(mainDisplay, dest_bitmap, rotateGC, dest_bitmap_image, 0, 0, 0, 0,
1056 num_cols, num_rows);
1057 XPutImage(mainDisplay, dest_bg_bitmap, rotateGC, dest_bitmap_bg_image, 0, 0,
1058 0, 0, num_cols, num_rows);
1059 XPutImage(mainDisplay, dest_pixmap, xpmGC, dest_image, 0, 0, 0, 0,
1060 num_cols, num_rows);
1061 if (do_msg) RestoreStatusStrings();
1062
1063 text_ptr->cached_bitmap = dest_bitmap;
1064 text_ptr->cached_bg_bitmap = dest_bg_bitmap;
1065 text_ptr->cached_pixmap = dest_pixmap;
1066 text_ptr->cached_zoomed = zoomedIn;
1067 text_ptr->cached_zoom = zoomScale;
1068 XDestroyImage(src_image);
1069 XDestroyImage(src_bitmap_image);
1070 XDestroyImage(src_bitmap_bg_image);
1071 XDestroyImage(dest_image);
1072 XDestroyImage(dest_bitmap_image);
1073 XDestroyImage(dest_bitmap_bg_image);
1074
1075 if (!watch_cursor && !RedrawDuringScrolling()) {
1076 SetDefaultCursor(mainWindow);
1077 ShowCursor();
1078 } else {
1079 CheckInterrupt(TRUE);
1080 }
1081 }
1082
CleanOuterInnerSel()1083 void CleanOuterInnerSel()
1084 {
1085 register struct SelRec *sel_ptr, *next_sel;
1086
1087 if (outerSel != NULL) {
1088 for (sel_ptr=outerSel; sel_ptr != NULL; sel_ptr=next_sel) {
1089 next_sel = sel_ptr->next;
1090 free(sel_ptr);
1091 }
1092 outerSel = innerSel = NULL;
1093 }
1094 }
1095
UpdateOuterInnerSel(obj_ptr)1096 void UpdateOuterInnerSel(obj_ptr)
1097 struct ObjRec *obj_ptr;
1098 /* outerSel is at the top of the chain and innerSel is at the bottom */
1099 {
1100 AddObjIntoSel(obj_ptr, NULL, outerSel, &outerSel, &innerSel);
1101 }
1102
1103 /*
1104 * Need to check for pins.
1105 */
1106
1107 static
SubFindTextObj(ObjPtr,XOff,YOff,obj_to_be_found)1108 struct ObjRec *SubFindTextObj(ObjPtr, XOff, YOff, obj_to_be_found)
1109 struct ObjRec *ObjPtr, *obj_to_be_found;
1110 int XOff, YOff;
1111 {
1112 register struct ObjRec *obj_ptr;
1113 register struct AttrRec *attr_ptr;
1114 struct ObjRec *found_text_obj;
1115
1116 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr!=NULL; obj_ptr=obj_ptr->next) {
1117 if (ObjPtr->type == OBJ_PIN && obj_ptr != GetPinObj(ObjPtr)) {
1118 continue;
1119 }
1120 obj_ptr->tmp_parent = ObjPtr;
1121 if (obj_to_be_found == NULL) {
1122 if (obj_ptr->type == OBJ_TEXT &&
1123 XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1124 YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1125 XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1126 YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1127 return obj_ptr;
1128 } else {
1129 attr_ptr = obj_ptr->fattr;
1130 for (; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1131 if (XOff>=OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1132 YOff>=OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1133 XOff<=OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1134 YOff<=OFFSET_Y(attr_ptr->obj->bbox.rby)+3 &&
1135 attr_ptr->shown == TRUE) {
1136 return attr_ptr->obj;
1137 }
1138 }
1139 switch (obj_ptr->type) {
1140 case OBJ_GROUP:
1141 case OBJ_ICON:
1142 case OBJ_SYM:
1143 case OBJ_PIN: break;
1144 default: continue;
1145 }
1146 if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1147 YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1148 XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1149 YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1150 if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1151 obj_to_be_found)) != NULL) {
1152 UpdateOuterInnerSel(obj_ptr);
1153 return found_text_obj;
1154 }
1155 }
1156 }
1157 } else {
1158 if (obj_ptr == obj_to_be_found) {
1159 return obj_ptr;
1160 } else {
1161 attr_ptr = obj_ptr->fattr;
1162 for (; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1163 if (attr_ptr->obj == obj_to_be_found) {
1164 return attr_ptr->obj;
1165 }
1166 }
1167 switch (obj_ptr->type) {
1168 case OBJ_GROUP:
1169 case OBJ_ICON:
1170 case OBJ_SYM:
1171 case OBJ_PIN: break;
1172 default: continue;
1173 }
1174 if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1175 obj_to_be_found)) != NULL) {
1176 UpdateOuterInnerSel(obj_ptr);
1177 return found_text_obj;
1178 }
1179 }
1180 }
1181 }
1182 return NULL;
1183 }
1184
FindTextObj(XOff,YOff,obj_to_be_found)1185 struct ObjRec *FindTextObj(XOff, YOff, obj_to_be_found)
1186 int XOff, YOff;
1187 struct ObjRec *obj_to_be_found;
1188 /* XOff and YOff are screen offsets */
1189 {
1190 register struct ObjRec *obj_ptr;
1191 register struct AttrRec *attr_ptr;
1192 struct ObjRec *found_text_obj;
1193
1194 CleanOuterInnerSel();
1195
1196 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
1197 obj_ptr->tmp_parent = NULL;
1198 if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1199 continue;
1200 }
1201 if (obj_to_be_found == NULL) {
1202 if (obj_ptr->type == OBJ_TEXT &&
1203 XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1204 YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1205 XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1206 YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1207 return obj_ptr;
1208 } else {
1209 attr_ptr = obj_ptr->fattr;
1210 for (; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1211 if (XOff>=OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1212 YOff>=OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1213 XOff<=OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1214 YOff<=OFFSET_Y(attr_ptr->obj->bbox.rby)+3 &&
1215 attr_ptr->shown == TRUE) {
1216 return attr_ptr->obj;
1217 }
1218 }
1219 if (!groupedTextEditable) continue;
1220
1221 switch (obj_ptr->type) {
1222 case OBJ_GROUP:
1223 case OBJ_ICON:
1224 case OBJ_SYM:
1225 case OBJ_PIN: break;
1226 default: continue;
1227 }
1228 if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1229 YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1230 XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1231 YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1232 if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1233 } else if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1234 obj_to_be_found)) != NULL) {
1235 UpdateOuterInnerSel(obj_ptr);
1236 return found_text_obj;
1237 }
1238 }
1239 }
1240 } else {
1241 if (obj_ptr == obj_to_be_found) {
1242 return obj_ptr;
1243 } else {
1244 attr_ptr = obj_ptr->fattr;
1245 for (; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1246 if (attr_ptr->obj == obj_to_be_found) {
1247 return attr_ptr->obj;
1248 }
1249 }
1250 if (!groupedTextEditable) continue;
1251
1252 switch (obj_ptr->type) {
1253 case OBJ_GROUP:
1254 case OBJ_ICON:
1255 case OBJ_SYM:
1256 case OBJ_PIN: break;
1257 default: continue;
1258 }
1259 if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1260 } else if ((found_text_obj=SubFindTextObj(obj_ptr, XOff, YOff,
1261 obj_to_be_found)) != NULL) {
1262 UpdateOuterInnerSel(obj_ptr);
1263 return found_text_obj;
1264 }
1265 }
1266 }
1267 }
1268 return NULL;
1269 }
1270
UnlinkCurTextFromInnerSel()1271 void UnlinkCurTextFromInnerSel()
1272 {
1273 register struct GroupRec *group_obj=innerSel->obj->detail.r;
1274
1275 if (group_obj->first == group_obj->last) {
1276 if (outerSel != innerSel || innerSel->obj->fattr != NULL) {
1277 #ifdef _TGIF_DBG /* debug, do not translate */
1278 sprintf(gszMsgBox, "%s %s. %s! %s %s.",
1279 "Error! The text object within a composite object which you",
1280 "have just erased caused all ancestors to be deleted",
1281 "You may see ghost images now",
1282 "Please undo and try ungroup the ancestor object first",
1283 "before erasing the text");
1284 if (PRTGIF) {
1285 fprintf(stderr, "%s\n", gszMsgBox);
1286 } else {
1287 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1288 }
1289 #endif /* _TGIF_DBG */
1290 }
1291 DelObj(outerSel->obj);
1292 CleanOuterInnerSel();
1293 curTextObj = NULL;
1294 return;
1295 } else if (curTextObj == group_obj->first) {
1296 curTextObj->next->prev = NULL;
1297 group_obj->first = curTextObj->next;
1298 } else if (curTextObj == group_obj->last) {
1299 curTextObj->prev->next = NULL;
1300 group_obj->last = curTextObj->prev;
1301 } else {
1302 curTextObj->prev->next = curTextObj->next;
1303 curTextObj->next->prev = curTextObj->prev;
1304 }
1305 curTextObj->prev = curTextObj->next = NULL;
1306 }
1307
AdjAncestorsBBox()1308 void AdjAncestorsBBox()
1309 {
1310 register struct SelRec *sel_ptr;
1311
1312 for (sel_ptr=innerSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1313 AdjObjBBox(sel_ptr->obj);
1314 }
1315 }
1316
1317 static
DumpTextPath(FP,ObjPtr)1318 void DumpTextPath(FP, ObjPtr)
1319 FILE *FP;
1320 struct ObjRec *ObjPtr;
1321 {
1322 struct TextRec *text_ptr=ObjPtr->detail.t;
1323 MiniLinesInfo *minilines=(&text_ptr->minilines);
1324 int x=ObjPtr->x, y=ObjPtr->y, trans_pat=ObjPtr->trans_pat;
1325
1326 fprintf(FP, " %s\n", gPsCmd[PS_GSAVE]);
1327 fprintf(FP, " 1 %s\n", gPsCmd[PS_SETLINEWIDTH]);
1328 if (ObjPtr->ctm != NULL) {
1329 float m[6];
1330
1331 m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
1332 m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
1333 m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
1334 m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
1335 fprintf(FP, " %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
1336 gPsCmd[PS_TRANSLATE]);
1337 fprintf(FP, " [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
1338 m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
1339 ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
1340 x = y = 0;
1341 }
1342 switch (penPat) {
1343 case SOLIDPAT: break;
1344 case BACKPAT:
1345 if (!trans_pat) {
1346 fprintf(FP, " 1 %s\n", gPsCmd[PS_SETGRAY]);
1347 }
1348 break;
1349 default:
1350 if (!colorDump && useGray) {
1351 GrayCheck(penPat);
1352 fprintf(FP, " %s %s\n", GrayStr(penPat), gPsCmd[PS_SETGRAY]);
1353 }
1354 break;
1355 }
1356 fprintf(FP, " %1d %1d %s\n", x, y+minilines->first->asc,
1357 gPsCmd[PS_MOVETO]);
1358 if (preDumpSetup) PSUseMiniLines();
1359 DumpMiniLines(minilines, x, y+minilines->first->asc, FP, &ObjPtr->obbox,
1360 TRUE, 6);
1361
1362 #ifdef _TGIF_DBG
1363 CleanUpIndentStrings();
1364 #endif /* _TGIF_DBG */
1365
1366 fprintf(FP, " %s\n", gPsCmd[PS_GRESTORE]);
1367 }
1368
1369 static
DumpSimpleTextBBoxPath(FP,just,x,lty,rby,indent)1370 void DumpSimpleTextBBoxPath(FP, just, x, lty, rby, indent)
1371 FILE *FP;
1372 int just, x, lty, rby, indent;
1373 {
1374 int i=0;
1375
1376 if (psUseShortHand) {
1377 for (i=0; i < indent; i++) fprintf(FP, " ");
1378 fprintf(FP, "%s %1d %1d %s ",
1379 gPsCmd[PS_NEWPATH],
1380 x, lty, gPsCmd[PS_MOVETO]);
1381 switch (just) {
1382 case JUST_L: break;
1383 case JUST_C:
1384 fprintf(FP, "tgifstrw 2 %s %s 0 %s ",
1385 gPsCmd[PS_DIV], gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1386 break;
1387 case JUST_R:
1388 fprintf(FP, "tgifstrw %s 0 %s ", gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1389 break;
1390 }
1391 fprintf(FP, "tgifstrw 0 %s 0 %1d %s tgifstrw neg 0 %s %s ",
1392 gPsCmd[PS_RLINETO], rby-lty, gPsCmd[PS_RLINETO],
1393 gPsCmd[PS_RLINETO], gPsCmd[PS_CLOSEPATH]);
1394 } else {
1395 for (i=0; i < indent; i++) fprintf(FP, " ");
1396 fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
1397 for (i=0; i < indent; i++) fprintf(FP, " ");
1398
1399 fprintf(FP, " %1d %1d %s ", x, lty, gPsCmd[PS_MOVETO]);
1400 switch (just) {
1401 case JUST_L: break;
1402 case JUST_C:
1403 fprintf(FP, "tgifstrw 2 %s %s 0 %s\n",
1404 gPsCmd[PS_DIV], gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1405 for (i=0; i < indent+3; i++) fprintf(FP, " ");
1406 break;
1407 case JUST_R:
1408 fprintf(FP, "tgifstrw %s 0 %s\n", gPsCmd[PS_NEG], gPsCmd[PS_RMOVETO]);
1409 for (i=0; i < indent+3; i++) fprintf(FP, " ");
1410 break;
1411 }
1412 fprintf(FP, "tgifstrw 0 %s ", gPsCmd[PS_RLINETO]);
1413 fprintf(FP, "0 %1d %s ", rby-lty, gPsCmd[PS_RLINETO]);
1414 fprintf(FP, "tgifstrw neg 0 %s\n", gPsCmd[PS_RLINETO]);
1415 for (i=0; i < indent; i++) fprintf(FP, " ");
1416 fprintf(FP, "%s ", gPsCmd[PS_CLOSEPATH]);
1417 }
1418 }
1419
1420 static
DumpTextFill(FP,ObjPtr)1421 void DumpTextFill(FP, ObjPtr)
1422 FILE *FP;
1423 struct ObjRec *ObjPtr;
1424 {
1425 struct TextRec *text_ptr=ObjPtr->detail.t;
1426 int fill=text_ptr->fill, trans_pat=ObjPtr->trans_pat, ltx, lty, rbx, rby;
1427 int color_index=ObjPtr->color;
1428 int simple_text=SimpleTextObj(text_ptr);
1429
1430 if (simple_text) {
1431 fprintf(FP, " /tgifstrw 0 def\n");
1432 DumpSimpleTextPath(FP, ObjPtr);
1433 }
1434 DumpRGBColorLine(FP, color_index, 0, TRUE);
1435
1436 if (ObjPtr->ctm == NULL) {
1437 ltx = ObjPtr->bbox.ltx;
1438 lty = ObjPtr->bbox.lty;
1439 rbx = ObjPtr->bbox.rbx-1;
1440 rby = ObjPtr->bbox.rby-1;
1441 } else {
1442 ltx = ObjPtr->detail.t->orig_bbox.ltx;
1443 lty = ObjPtr->detail.t->orig_bbox.lty;
1444 rbx = ObjPtr->detail.t->orig_bbox.rbx-1;
1445 rby = ObjPtr->detail.t->orig_bbox.rby-1;
1446 }
1447 if (ObjPtr->ctm != NULL) {
1448 float m[6];
1449
1450 fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
1451 m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
1452 m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
1453 m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
1454 m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
1455 fprintf(FP, " %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
1456 gPsCmd[PS_TRANSLATE]);
1457 fprintf(FP, " [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
1458 m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
1459 ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
1460 fprintf(FP, " %1d %s %1d %s %s\n",
1461 ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
1462 gPsCmd[PS_TRANSLATE]);
1463 }
1464 switch (fill) {
1465 case NONEPAT: break;
1466 case SOLIDPAT:
1467 if (simple_text) {
1468 DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1469 ObjPtr->x, lty, rby, 0);
1470 } else {
1471 DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
1472 }
1473 fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
1474 break;
1475 case BACKPAT:
1476 if (!trans_pat) {
1477 if (simple_text) {
1478 DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1479 ObjPtr->x, lty, rby, 0);
1480 } else {
1481 DumpRectPath(FP, ltx, lty, rbx, rby, 0, FALSE);
1482 }
1483 fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
1484 DumpRGBColorLine(FP, color_index, 0, TRUE);
1485 }
1486 break;
1487 default:
1488 /* patterned */
1489 fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
1490 if (colorDump || !useGray) {
1491 if (!trans_pat) {
1492 if (simple_text) {
1493 DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1494 ObjPtr->x, lty, rby, 3);
1495 } else {
1496 DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1497 }
1498 fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
1499 DumpRGBColorLine(FP, color_index, 3, TRUE);
1500 }
1501 } else {
1502 GrayCheck(fill);
1503 fprintf(FP, " %s %s\n", GrayStr(fill), gPsCmd[PS_SETGRAY]);
1504 }
1505 if (colorDump || !useGray) {
1506 if (preDumpSetup) PSUseColorPattern();
1507 if (simple_text) {
1508 DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1509 ObjPtr->x, lty, rby, 3);
1510 } else {
1511 DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1512 }
1513 fprintf(FP, "%s %s\n", gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
1514 DumpPatFill(FP, fill, ObjPtr->bbox, 3, TRUE);
1515 } else {
1516 if (simple_text) {
1517 DumpSimpleTextBBoxPath(FP, text_ptr->minilines.just,
1518 ObjPtr->x, lty, rby, 3);
1519 } else {
1520 DumpRectPath(FP, ltx, lty, rbx, rby, 3, FALSE);
1521 }
1522 fprintf(FP, "%s\n", gPsCmd[PS_FILL]);
1523 }
1524 fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
1525 break;
1526 }
1527 if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
1528 }
1529
DumpTextObj(FP,ObjPtr)1530 void DumpTextObj(FP, ObjPtr)
1531 FILE *FP;
1532 register struct ObjRec *ObjPtr;
1533 {
1534 struct TextRec *text_ptr=ObjPtr->detail.t;
1535 MiniLinesInfo *minilines=(&text_ptr->minilines);
1536 int pen=text_ptr->pen, fill=text_ptr->fill, trans_pat=ObjPtr->trans_pat;
1537 int underline_y_offset=text_ptr->underline_y_offset;
1538 int overline_y_offset=text_ptr->overline_y_offset;
1539
1540 if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
1541 (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
1542 return;
1543 }
1544 if (ObjPtr->ctm != NULL && (ObjPtr->obbox.ltx == ObjPtr->obbox.rbx ||
1545 ObjPtr->obbox.lty == ObjPtr->obbox.rby)) {
1546 /* zero width or height text */
1547 return;
1548 }
1549 fprintf(FP, "%% TEXT\n");
1550 fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
1551
1552 if (!PRTGIF) SaveCurFont();
1553
1554 ObjFontInfoToCurFontInfo(text_ptr);
1555
1556 penPat = pen;
1557 transPat = trans_pat;
1558 objFill = fill;
1559 curUnderlineYOffset = underline_y_offset;
1560 curOverlineYOffset = overline_y_offset;
1561
1562 if (PRTGIF || text_ptr->read_only) {
1563 canvasFontAsc = minilines->first->asc;
1564 canvasFontDes = minilines->first->des;
1565 textCursorH = canvasFontAsc + canvasFontDes;
1566 }
1567 /* fill the bounding rectangle */
1568 DumpTextFill(FP, ObjPtr);
1569
1570 if (penPat == NONEPAT) {
1571 fprintf(FP, "\n");
1572 if (!PRTGIF) RestoreCurFont();
1573 return;
1574 }
1575 if ((colorDump || !useGray) && penPat>BACKPAT && curFont==FONT_COU) {
1576 if (PRTGIF) {
1577 fprintf(stderr, "%s\n",
1578 TgLoadString(STID_WARN_PRINT_COURIER_IN_COLOR));
1579 fprintf(stderr, "%s\n",
1580 TgLoadString(STID_MAY_CAUSE_ERROR_IN_PRINTOUT));
1581 } else {
1582 TwoLineMsg(TgLoadString(STID_WARN_PRINT_COURIER_IN_COLOR),
1583 TgLoadString(STID_MAY_CAUSE_ERROR_IN_PRINTOUT));
1584 }
1585 }
1586 if ((colorDump || !useGray) && penPat > BACKPAT && !trans_pat) {
1587 int tmp_pen = penPat;
1588
1589 penPat = BACKPAT;
1590 DumpTextPath(FP, ObjPtr);
1591 penPat = tmp_pen;
1592 }
1593 if (!(penPat == BACKPAT && trans_pat)) {
1594 DumpTextPath(FP, ObjPtr);
1595 }
1596 fprintf(FP, "\n");
1597 if (!PRTGIF) RestoreCurFont();
1598 }
1599
1600 static
NeedToCacheStrSeg(pStrSeg)1601 int NeedToCacheStrSeg(pStrSeg)
1602 StrSegInfo *pStrSeg;
1603 {
1604 return (pStrSeg->double_byte && pStrSeg->double_byte_vertical);
1605 }
1606
1607 static
NeedToCacheStrBlock(pStrBlock)1608 int NeedToCacheStrBlock(pStrBlock)
1609 StrBlockInfo *pStrBlock;
1610 {
1611 switch (pStrBlock->type) {
1612 case SB_SIMPLE: return NeedToCacheStrSeg(pStrBlock->seg);
1613 case SB_CHAR_SPACE: return FALSE;
1614
1615 case SB_SUPSUB_LEFT:
1616 case SB_SUPSUB_CENTER:
1617 case SB_SUPSUB_RIGHT:
1618 if (pStrBlock->sup != NULL && NeedToCacheMiniLines(pStrBlock->sup)) {
1619 return TRUE;
1620 }
1621 if (pStrBlock->sub != NULL && NeedToCacheMiniLines(pStrBlock->sub)) {
1622 return TRUE;
1623 }
1624 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1625 return NeedToCacheStrSeg(pStrBlock->seg);
1626 }
1627 break;
1628 }
1629 return FALSE;
1630 }
1631
1632 static
NeedToCacheMiniLine(pMiniLine)1633 int NeedToCacheMiniLine(pMiniLine)
1634 MiniLineInfo *pMiniLine;
1635 {
1636 StrBlockInfo *pStrBlock=NULL;
1637
1638 for (pStrBlock=pMiniLine->first_block; pStrBlock != NULL;
1639 pStrBlock=pStrBlock->next) {
1640 if (NeedToCacheStrBlock(pStrBlock)) {
1641 return TRUE;
1642 }
1643 }
1644 return FALSE;
1645 }
1646
NeedToCacheMiniLines(minilines)1647 int NeedToCacheMiniLines(minilines)
1648 MiniLinesInfo *minilines;
1649 {
1650 MiniLineInfo *pMiniLine=NULL;
1651
1652 for (pMiniLine=minilines->first; pMiniLine != NULL;
1653 pMiniLine=pMiniLine->next) {
1654 if (NeedToCacheMiniLine(pMiniLine)) {
1655 return TRUE;
1656 }
1657 }
1658 return FALSE;
1659 }
1660
NeedsToCacheTextObj(ObjPtr)1661 int NeedsToCacheTextObj(ObjPtr)
1662 struct ObjRec *ObjPtr;
1663 {
1664 struct TextRec *text_ptr=ObjPtr->detail.t;
1665
1666 if (ObjPtr->ctm != NULL || zoomScale != 0 || text_ptr->read_only) {
1667 return TRUE;
1668 }
1669 return NeedToCacheMiniLines(&text_ptr->minilines);
1670 }
1671
SaveString(FP,S)1672 void SaveString(FP, S)
1673 FILE *FP;
1674 register char *S;
1675 {
1676 for ( ; *S != '\0'; S++) {
1677 if (*S == '\\') {
1678 if (fprintf(FP, "%s", "\\\\") == EOF) writeFileFailed = TRUE;
1679 } else if (*S == '"') {
1680 if (doubleQuoteDoubleQuote) {
1681 if (fprintf(FP, "%s", "\"\"") == EOF) writeFileFailed = TRUE;
1682 } else {
1683 if (fprintf(FP, "%s", "\\\"") == EOF) writeFileFailed = TRUE;
1684 }
1685 } else if ((*S) & 0x80) {
1686 if (fprintf(FP, "\\%o", (*S)&0xff) == EOF) writeFileFailed = TRUE;
1687 } else {
1688 if (fputc(*S, FP) == EOF) writeFileFailed = TRUE;
1689 }
1690 }
1691 }
1692
SaveDoubleByteString(FP,S)1693 void SaveDoubleByteString(FP, S)
1694 FILE *FP;
1695 register char *S;
1696 {
1697 for ( ; *S != '\0'; S++) {
1698 if ((*S)&0x80) {
1699 if (fprintf(FP, "\\%03o\\%03o", S[0]&0xff, S[1]&0xff) == EOF) {
1700 writeFileFailed = TRUE;
1701 }
1702 S++;
1703 if (*S == '\0') break;
1704 } else if (*S == '\\') {
1705 if (fprintf(FP, "%s", "\\\\") == EOF) writeFileFailed = TRUE;
1706 } else if (*S == '"') {
1707 if (doubleQuoteDoubleQuote) {
1708 if (fprintf(FP, "%s", "\"\"") == EOF) writeFileFailed = TRUE;
1709 } else {
1710 if (fprintf(FP, "%s", "\\\"") == EOF) writeFileFailed = TRUE;
1711 }
1712 } else {
1713 if (fputc(*S, FP) == EOF) writeFileFailed = TRUE;
1714 }
1715 }
1716 }
1717
1718 static
SaveStrSeg(FP,pStrSeg)1719 void SaveStrSeg(FP, pStrSeg)
1720 FILE *FP;
1721 StrSegInfo *pStrSeg;
1722 /*
1723 * str_seg()
1724 */
1725 {
1726 char font_str[MAXSTRING];
1727 int overunder=((pStrSeg->overline_on<<1)+pStrSeg->underline_on);
1728
1729 GetPSFontStr(pStrSeg->font, pStrSeg->style, font_str);
1730 /* font_str starts with the '/' character */
1731
1732 if (fprintf(FP, "str_seg('%s',", colorMenuItems[pStrSeg->color]) == EOF) {
1733 writeFileFailed = TRUE;
1734 }
1735 /*
1736 * When the new file format (version 38) is implemented, make sure to
1737 * save the DontReencode related information (dontreencode) in the file!
1738 */
1739 if (fprintf(FP,
1740 "'%s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
1741 &font_str[1], pStrSeg->style, pStrSeg->sz_unit,
1742 pStrSeg->w, pStrSeg->asc, pStrSeg->des, pStrSeg->min_lbearing,
1743 pStrSeg->max_rextra, overunder,
1744 pStrSeg->double_byte, pStrSeg->double_byte_mod_bytes,
1745 pStrSeg->double_byte_vertical, pStrSeg->direction) == EOF) {
1746 writeFileFailed = TRUE;
1747 }
1748 if (fprintf(FP, "\n\t\"") == EOF) writeFileFailed = TRUE;
1749 if (pStrSeg->double_byte) {
1750 SaveDoubleByteString(FP, pStrSeg->dyn_str.s);
1751 } else {
1752 SaveString(FP, pStrSeg->dyn_str.s);
1753 }
1754 if (fprintf(FP, "\")") == EOF) writeFileFailed = TRUE;
1755 }
1756
1757 static
SaveAStrBlock(FP,pStrBlock)1758 void SaveAStrBlock(FP, pStrBlock)
1759 FILE *FP;
1760 StrBlockInfo *pStrBlock;
1761 /*
1762 * str_block()
1763 */
1764 {
1765 int has_sup=FALSE, has_sub=FALSE;
1766 int something_saved=FALSE;
1767
1768 switch (pStrBlock->type) {
1769 case SB_SUPSUB_LEFT:
1770 case SB_SUPSUB_CENTER:
1771 case SB_SUPSUB_RIGHT:
1772 if (pStrBlock->sup != NULL) has_sup = TRUE;
1773 if (pStrBlock->sub != NULL) has_sub = TRUE;
1774 break;
1775 }
1776 if (fprintf(FP, "str_block(%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d",
1777 pStrBlock->type, pStrBlock->w, pStrBlock->asc, pStrBlock->des,
1778 pStrBlock->min_lbearing, pStrBlock->max_rextra,
1779 pStrBlock->special_char_w, has_sup, has_sub) == EOF) {
1780 writeFileFailed = TRUE;
1781 }
1782 switch (pStrBlock->type) {
1783 case SB_SIMPLE:
1784 if (fprintf(FP, ",[\n") == EOF) writeFileFailed = TRUE;
1785 SaveStrSeg(FP, pStrBlock->seg);
1786 if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1787 break;
1788 case SB_CHAR_SPACE:
1789 break;
1790
1791 case SB_SUPSUB_LEFT:
1792 case SB_SUPSUB_CENTER:
1793 case SB_SUPSUB_RIGHT:
1794 if (fprintf(FP, ",[\n") == EOF) writeFileFailed = TRUE;
1795
1796 if (pStrBlock->sup != NULL) {
1797 SaveMiniLines(FP, pStrBlock->sup);
1798 something_saved = TRUE;
1799 }
1800 if (pStrBlock->sub != NULL) {
1801 if (something_saved) {
1802 if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1803 }
1804 SaveMiniLines(FP, pStrBlock->sub);
1805 something_saved = TRUE;
1806 }
1807 if (pStrBlock->type == SB_SUPSUB_CENTER) {
1808 if (something_saved) {
1809 if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1810 }
1811 /* pStrBlock->seg better not be NULL or it will crash */
1812 SaveStrSeg(FP, pStrBlock->seg);
1813 something_saved = TRUE;
1814 }
1815 if (something_saved) {
1816 if (fprintf(FP, "\n]") == EOF) writeFileFailed = TRUE;
1817 } else {
1818 if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1819 }
1820 break;
1821 }
1822 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
1823 }
1824
1825 static
SaveStrBlocks(FP,pFirstStrBlock)1826 void SaveStrBlocks(FP, pFirstStrBlock)
1827 FILE *FP;
1828 StrBlockInfo *pFirstStrBlock;
1829 /*
1830 * ... [
1831 * str_block(),
1832 * str_block(),
1833 * ...
1834 * str_block()
1835 * ]
1836 */
1837 {
1838 StrBlockInfo *pStrBlock;
1839
1840 if (fprintf(FP, "[\n") == EOF) writeFileFailed = TRUE;
1841
1842 for (pStrBlock=pFirstStrBlock; pStrBlock != NULL;
1843 pStrBlock=pStrBlock->next) {
1844 SaveAStrBlock(FP, pStrBlock);
1845 if (pStrBlock->next != NULL) {
1846 if (fprintf(FP, ",\n") == EOF) {
1847 writeFileFailed = TRUE;
1848 }
1849 }
1850 }
1851 if (pFirstStrBlock == NULL) {
1852 if (fprintf(FP, "]") == EOF) writeFileFailed = TRUE;
1853 } else {
1854 if (fprintf(FP, "\n]") == EOF) writeFileFailed = TRUE;
1855 }
1856 }
1857
1858 static
SaveAMiniLine(FP,pMiniLine)1859 void SaveAMiniLine(FP, pMiniLine)
1860 FILE *FP;
1861 MiniLineInfo *pMiniLine;
1862 /*
1863 * mini_line(w,asc,des,min_lbearing,max_rextra,v_gap)
1864 */
1865 {
1866 if (pMiniLine == pMiniLine->owner_minilines->first &&
1867 pMiniLine->v_gap != 0) {
1868 TgAssert(FALSE, "First mini_line has non-zero v_gap in SaveAMiniLine()",
1869 "It's set to 0");
1870 pMiniLine->v_gap = 0;
1871 }
1872 if (fprintf(FP, "mini_line(%1d,%1d,%1d,%1d,%1d,%1d,",
1873 pMiniLine->w, pMiniLine->asc, pMiniLine->des, pMiniLine->min_lbearing,
1874 pMiniLine->max_rextra, pMiniLine->v_gap) == EOF) {
1875 writeFileFailed = TRUE;
1876 }
1877 SaveStrBlocks(FP, pMiniLine->first_block);
1878
1879 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
1880 }
1881
SaveMiniLines(FP,minilines)1882 void SaveMiniLines(FP, minilines)
1883 FILE *FP;
1884 MiniLinesInfo *minilines;
1885 /*
1886 * ... [
1887 * minilines(w,h,min_lbearing,max_rextra,just,v_space,baseline_offset,[
1888 * mini_line(),
1889 * mini_line(),
1890 * ...
1891 * mini_line()
1892 * ])
1893 * ]
1894 */
1895 {
1896 MiniLineInfo *pMiniLine=NULL;
1897
1898 if (fprintf(FP, "minilines(%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n",
1899 minilines->w, minilines->h, minilines->min_lbearing,
1900 minilines->max_rextra, minilines->just, minilines->v_space,
1901 minilines->baseline_offset) == EOF) {
1902 writeFileFailed = TRUE;
1903 }
1904 for (pMiniLine=minilines->first; pMiniLine != NULL;
1905 pMiniLine=pMiniLine->next) {
1906 SaveAMiniLine(FP, pMiniLine);
1907 if (pMiniLine->next != NULL) {
1908 if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
1909 }
1910 }
1911 if (fprintf(FP, "\n])") == EOF) writeFileFailed = TRUE;
1912 }
1913
CombineOverUnderYOffsets(underline_y_offset,overline_y_offset,pn_combined)1914 void CombineOverUnderYOffsets(underline_y_offset, overline_y_offset,
1915 pn_combined)
1916 int underline_y_offset, overline_y_offset, *pn_combined;
1917 {
1918 underline_y_offset = (underline_y_offset & 0x0ffff);
1919 overline_y_offset = (overline_y_offset & 0x0ffff);
1920 *pn_combined = ((overline_y_offset << 16) | underline_y_offset);
1921 }
1922
UncombineOverUnderYOffsets(combined,pn_underline_y_offset,pn_overline_y_offset)1923 void UncombineOverUnderYOffsets(combined, pn_underline_y_offset,
1924 pn_overline_y_offset)
1925 int combined, *pn_underline_y_offset, *pn_overline_y_offset;
1926 {
1927 int underline_y_offset=(combined & 0x0ffff);
1928 int overline_y_offset=((combined >> 16) & 0x0ffff);
1929
1930 if ((underline_y_offset & 0x08000) == 0x08000) {
1931 underline_y_offset = (0x010000 - abs(underline_y_offset));
1932 underline_y_offset = -underline_y_offset;
1933 }
1934 if ((overline_y_offset & 0x08000) == 0x08000) {
1935 overline_y_offset = (0x010000 - abs(overline_y_offset));
1936 overline_y_offset = -overline_y_offset;
1937 }
1938 *pn_underline_y_offset = underline_y_offset;
1939 *pn_overline_y_offset = overline_y_offset;
1940 }
1941
SaveTextObj(FP,ObjPtr)1942 void SaveTextObj(FP, ObjPtr)
1943 FILE *FP;
1944 struct ObjRec *ObjPtr;
1945 {
1946 struct TextRec *text_ptr=ObjPtr->detail.t;
1947 int compressed=FALSE, combined_y_offset=0;
1948
1949 CombineOverUnderYOffsets(text_ptr->underline_y_offset,
1950 text_ptr->overline_y_offset, &combined_y_offset);
1951 if (fprintf(FP, "text('%s',", colorMenuItems[ObjPtr->color]) == EOF) {
1952 writeFileFailed = TRUE;
1953 }
1954 if (fprintf(FP,
1955 "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
1956 ObjPtr->x, ObjPtr->y, text_ptr->lines, text_ptr->minilines.just,
1957 text_ptr->pen, ObjPtr->obbox.rbx-ObjPtr->obbox.ltx,
1958 ObjPtr->obbox.rby-ObjPtr->obbox.lty, ObjPtr->id,
1959 text_ptr->minilines.first->first_block->asc,
1960 text_ptr->minilines.first->first_block->des) == EOF) {
1961 writeFileFailed = TRUE;
1962 }
1963 if (fprintf(FP,
1964 "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,\"\",",
1965 text_ptr->fill, text_ptr->minilines.v_space, ObjPtr->rotation,
1966 ObjPtr->locked, combined_y_offset, text_ptr->w,
1967 text_ptr->h, text_ptr->min_lbearing, text_ptr->max_rextra) == EOF) {
1968 writeFileFailed = TRUE;
1969 }
1970 if (fprintf(FP,
1971 "%1d,%1d,%1d,%1d,%1d,'',",
1972 compressed, ObjPtr->ctm!=NULL, ObjPtr->invisible,
1973 ObjPtr->trans_pat, text_ptr->baseline_y) == EOF) {
1974 writeFileFailed = TRUE;
1975 }
1976 if (ObjPtr->ctm != NULL && fprintf(FP,
1977 "[\n\t%1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d,%1d,%1d,%1d,%1d],",
1978 ObjPtr->x, ObjPtr->y,
1979 ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
1980 ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
1981 ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
1982 ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
1983 ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY],
1984 text_ptr->orig_bbox.ltx, text_ptr->orig_bbox.lty,
1985 text_ptr->orig_bbox.rbx, text_ptr->orig_bbox.rby) == EOF) {
1986 writeFileFailed = TRUE;
1987 }
1988 if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
1989 if (fprintf(FP, "[\n") == EOF) writeFileFailed = TRUE;
1990 if (text_ptr->minilines.baseline_offset != 0) {
1991 TgAssert(FALSE,
1992 "Minilines of text object has bad baseline_offset in SaveTextObj()",
1993 "It's set to 0");
1994 text_ptr->minilines.baseline_offset = 0;
1995 }
1996 SaveMiniLines(FP, &text_ptr->minilines);
1997 if (fprintf(FP, "])") == EOF) writeFileFailed = TRUE;
1998 }
1999
SaveHexString(FP,buf)2000 void SaveHexString(FP, buf)
2001 FILE *FP;
2002 char *buf;
2003 {
2004 for ( ; *buf != '\0'; buf++) {
2005 int ival=0;
2006
2007 ival = ((((unsigned int)(*buf)) >> 4) & 0x0f);
2008 if (ival >= 10) {
2009 fprintf(FP, "%c", (char)(((int)'a')+(ival-10)));
2010 } else {
2011 fprintf(FP, "%c", (char)(((int)'0')+ival));
2012 }
2013 ival = (((unsigned int)(*buf)) & 0x0f);
2014 if (ival >= 10) {
2015 fprintf(FP, "%c", (char)(((int)'a')+(ival-10)));
2016 } else {
2017 fprintf(FP, "%c", (char)(((int)'0')+ival));
2018 }
2019 }
2020 }
2021
ReadString(Str)2022 char *ReadString(Str)
2023 char *Str;
2024 {
2025 register char *s=NULL;
2026
2027 if (Str == NULL) return NULL;
2028
2029 for (s=Str; *s != '\0'; s++) {
2030 if (*s == '"') {
2031 if (s[1] == '"') {
2032 UtilStrCpy(s, s+1);
2033 } else {
2034 break;
2035 }
2036 } else if (*s == '\\') {
2037 if (s[1] >= '0' && s[1] <= '3') {
2038 if (s[2] >= '0' && s[2] <= '7' && s[3] >= '0' && s[3] <= '7') {
2039 *s = (char)(((s[1]-'0')<<6)+((s[2]-'0')<<3)+(s[3]-'0'));
2040 UtilStrCpy(s+1, s+4);
2041 } else {
2042 sprintf(gszMsgBox,
2043 TgLoadString(STID_BAD_OCTAL_STRING_ENCOUNTERED),
2044 s[1], s[2], s[3]);
2045 if (PRTGIF) {
2046 fprintf(stderr, "%s\n", gszMsgBox);
2047 } else {
2048 Msg(gszMsgBox);
2049 }
2050 UtilStrCpy(s, s+1);
2051 }
2052 } else {
2053 UtilStrCpy(s, s+1);
2054 }
2055 }
2056 }
2057 if (*s == '"') s++;
2058 return s;
2059 }
2060
CreateStrSegFromString(buf,pOwnerStrBlock)2061 StrSegInfo *CreateStrSegFromString(buf, pOwnerStrBlock)
2062 char *buf;
2063 StrBlockInfo *pOwnerStrBlock;
2064 {
2065 StrSegInfo *pStrSeg=NewStrSeg();
2066
2067 DynStrSet(&pStrSeg->dyn_str, buf);
2068
2069 pStrSeg->color = colorIndex;
2070 pStrSeg->font = curFont;
2071 pStrSeg->style = curStyle;
2072 pStrSeg->sz_unit = GetCurSzUnit();
2073 if (mainDisplay != NULL) {
2074 strcpy(pStrSeg->color_str, colorMenuItems[colorIndex]);
2075 }
2076 pStrSeg->double_byte = canvasFontDoubleByte;
2077 pStrSeg->double_byte_mod_bytes = canvasFontDoubleByteModBytes;
2078 pStrSeg->double_byte_vertical = canvasFontDoubleByteVertical;
2079 pStrSeg->direction = canvasFontDirection;
2080 pStrSeg->dontreencode = canvasFontDontReencode;
2081 pStrSeg->underline_on = curUnderlineOn;
2082 pStrSeg->overline_on = curOverlineOn;
2083
2084 pStrSeg->asc = canvasFontAsc;
2085 pStrSeg->des = canvasFontDes;
2086 if (mainDisplay != NULL) {
2087 pStrSeg->w = MyTextWidth(canvasFontPtr, pStrSeg->dyn_str.s,
2088 pStrSeg->dyn_str.sz-1);
2089 }
2090 pStrSeg->owner = pOwnerStrBlock;
2091
2092 return pStrSeg;
2093 }
2094
CreateStrBlockFromString(buf,pOwnerMiniLine)2095 StrBlockInfo *CreateStrBlockFromString(buf, pOwnerMiniLine)
2096 char *buf;
2097 MiniLineInfo *pOwnerMiniLine;
2098 {
2099 StrBlockInfo *pStrBlock=NewStrBlock();
2100
2101 pStrBlock->seg = CreateStrSegFromString(buf, pStrBlock);
2102 pStrBlock->type = SB_SIMPLE;
2103 pStrBlock->owner_mini_line = pOwnerMiniLine;
2104
2105 return pStrBlock;
2106 }
2107
CreateMiniLineFromString(buf,ppFirstMiniLine,ppLastMiniLine)2108 MiniLineInfo *CreateMiniLineFromString(buf, ppFirstMiniLine, ppLastMiniLine)
2109 char *buf;
2110 MiniLineInfo **ppFirstMiniLine, **ppLastMiniLine;
2111 {
2112 MiniLineInfo *pMiniLine=NewMiniLine();
2113
2114 if (canvasFontDoubleByte) {
2115 struct StrRec *pStr=NULL, *pStr1=NULL;
2116
2117 pStr = SegmentDoubleByteString(buf);
2118 for (pStr1=pStr; pStr1 != NULL; pStr1=pStr1->next) {
2119 int str_seg_double_byte=TRUE;
2120 StrBlockInfo *pStrBlock=CreateStrBlockFromString(pStr1->dyn_str.s,
2121 pMiniLine);
2122
2123 if (*pStr1->dyn_str.s != '\0') {
2124 str_seg_double_byte = ((*pStr1->dyn_str.s) & 0x80);
2125 }
2126 pStrBlock->prev = pMiniLine->last_block;
2127 if (pMiniLine->first_block == NULL) {
2128 pMiniLine->first_block = pStrBlock;
2129 } else {
2130 pMiniLine->last_block->next = pStrBlock;
2131 }
2132 pMiniLine->last_block = pStrBlock;
2133
2134 if (str_seg_double_byte == FALSE) {
2135 pStrBlock->seg->font = defaultSingleByteFont;
2136 pStrBlock->seg->double_byte = FALSE;
2137 pStrBlock->seg->double_byte_mod_bytes = FALSE;
2138 pStrBlock->seg->double_byte_vertical = FALSE;
2139 }
2140 }
2141 FreeStrList(pStr);
2142 } else {
2143 StrBlockInfo *pStrBlock=CreateStrBlockFromString(buf, pMiniLine);
2144
2145 pMiniLine->first_block = pMiniLine->last_block = pStrBlock;
2146 }
2147 if (ppFirstMiniLine != NULL && ppLastMiniLine != NULL) {
2148 pMiniLine->prev = (*ppLastMiniLine);
2149 pMiniLine->next = NULL;;
2150 if ((*ppLastMiniLine) == NULL) {
2151 (*ppFirstMiniLine) = pMiniLine;
2152 } else {
2153 (*ppLastMiniLine)->next = pMiniLine;
2154 }
2155 (*ppLastMiniLine) = pMiniLine;
2156 }
2157 return pMiniLine;
2158 }
2159
FormTextObjectFromFile(FP,AbsX,AbsBaselineY)2160 struct ObjRec *FormTextObjectFromFile(FP, AbsX, AbsBaselineY)
2161 FILE *FP;
2162 int AbsX, AbsBaselineY;
2163 {
2164 MiniLineInfo *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
2165 struct ObjRec *obj_ptr=NULL;
2166 struct TextRec *text_ptr=NULL;
2167 int num_lines=0;
2168
2169 obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
2170 if (obj_ptr == NULL) FailAllocMessage();
2171 memset(obj_ptr, 0, sizeof(struct ObjRec));
2172
2173 text_ptr = (struct TextRec *)malloc(sizeof(struct TextRec));
2174 if (text_ptr == NULL) FailAllocMessage();
2175 memset(text_ptr, 0, sizeof(struct TextRec));
2176
2177 if (FP != NULL) {
2178 char *buf=NULL;
2179
2180 while ((buf=UtilGetALine(FP)) != NULL) {
2181 MiniLineInfo *pMiniLine=CreateMiniLineFromString(buf,
2182 &pFirstMiniLine, &pLastMiniLine);
2183
2184 if (pMiniLine != NULL) {
2185 num_lines++;
2186 }
2187 free(buf);
2188 }
2189 }
2190 if (num_lines == 0) {
2191 CreateMiniLineFromString("", &pFirstMiniLine, &pLastMiniLine);
2192
2193 num_lines++;
2194 }
2195 text_ptr->lines = num_lines;
2196 text_ptr->minilines.first = pFirstMiniLine;
2197 text_ptr->minilines.last = pLastMiniLine;
2198 text_ptr->baseline_y = AbsBaselineY;
2199
2200 CopyCurInfoIntoTextPtr(obj_ptr, text_ptr);
2201
2202 obj_ptr->x = AbsX;
2203 obj_ptr->y = AbsBaselineY-text_ptr->minilines.first->asc;
2204 obj_ptr->type = OBJ_TEXT;
2205 obj_ptr->color = colorIndex;
2206 if (mainDisplay != NULL) {
2207 UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
2208 colorMenuItems[colorIndex]);
2209 }
2210 obj_ptr->id = objId++;;
2211 obj_ptr->dirty = FALSE;
2212 obj_ptr->rotation = 0;
2213 obj_ptr->detail.t = text_ptr;
2214 obj_ptr->fattr = obj_ptr->lattr = NULL;
2215 obj_ptr->ctm = NULL;
2216
2217 RecalcTextMetrics(text_ptr, AbsX, AbsBaselineY);
2218
2219 SetTextBBox(obj_ptr, textJust, text_ptr->w, text_ptr->h,
2220 text_ptr->min_lbearing, text_ptr->max_rextra, ROTATE0);
2221 AdjObjBBox(obj_ptr);
2222 return obj_ptr;
2223 }
2224
2225 static
PaintLeftText(Str,Just,LtX,LtY)2226 int PaintLeftText(Str, Just, LtX, LtY)
2227 char *Str;
2228 int Just, LtX, LtY;
2229 /* LtX and LtY are UNSCALED screen offset */
2230 {
2231 register int amount;
2232
2233 if (zoomScale != 0) {
2234 LtX = ZOOMED_SIZE(LtX);
2235 LtY = ZOOMED_SIZE(LtY);
2236 amount = MyTextWidth(canvasFontPtr, Str, strlen(Str));
2237 BlurText(drawWindow, drawGC, LtX, LtY,
2238 (zoomedIn ? ((amount<<zoomScale)+1) : (amount>>zoomScale)+1),
2239 (zoomedIn ? (textCursorH<<zoomScale)+1 :
2240 (textCursorH>>zoomScale)+1));
2241 return amount;
2242 }
2243
2244 LtY += canvasFontAsc;
2245 amount = MyTextWidth(canvasFontPtr, Str, strlen(Str));
2246 MyDrawString(mainDisplay, drawWindow, drawGC, mainDepth, LtX, LtY,
2247 Str, strlen(Str));
2248
2249 return amount; /* return the length of the painted string */
2250 }
2251
RepaintFirstStr(ObjPtr,Str)2252 void RepaintFirstStr(ObjPtr, Str)
2253 struct ObjRec *ObjPtr;
2254 char *Str;
2255 /* Replace (graphically) the FIRST string of the text in ObjPtr by Str */
2256 {
2257 struct TextRec *text_ptr=ObjPtr->detail.t;
2258 char *s=GetTextPtrFirstStrSeg(text_ptr)->dyn_str.s, *s1=Str;
2259 char tmp_str[MAXSTRING+1], *c_ptr;
2260 int len;
2261 struct BBRec bbox;
2262 XGCValues values;
2263
2264 bbox.ltx = ObjPtr->obbox.ltx; bbox.lty = ObjPtr->obbox.lty;
2265 bbox.rbx = ObjPtr->obbox.rbx; bbox.rby = ObjPtr->obbox.rby;
2266
2267 c_ptr = tmp_str;
2268 for ( ; *s != '\0' && *s1 != '\0' && *s1 == *s; *c_ptr++ = *s++, s1++) ;
2269
2270 if (*s == *s1) return; /* no updates */
2271 text_ptr->attr->owner->dirty = TRUE;
2272 *c_ptr = '\0';
2273
2274 PushCurFont();
2275 ObjFontInfoToCurFontInfo(text_ptr);
2276 SetCanvasFont();
2277
2278 if (*s != '\0') {
2279 values.foreground = GetDrawingBgPixel(INVALID, INVALID);
2280 values.function = GXcopy;
2281 values.fill_style = FillSolid;
2282 XChangeGC(mainDisplay, drawGC,
2283 GCForeground | GCFunction | GCFillStyle, &values);
2284
2285 len = MyTextWidth(canvasFontPtr, tmp_str, strlen(tmp_str));
2286 XFillRectangle(mainDisplay, drawWindow, drawGC, OFFSET_X(bbox.ltx+len),
2287 OFFSET_Y(bbox.lty),
2288 (zoomedIn ? ((bbox.rbx-bbox.ltx-len)<<zoomScale)+1 :
2289 ((bbox.rbx-bbox.ltx-len)>>zoomScale)+1),
2290 (zoomedIn ? (textCursorH<<zoomScale)+1 :
2291 (textCursorH>>zoomScale)+1));
2292
2293 values.foreground = colorPixels[ObjPtr->color];
2294 XChangeGC(mainDisplay, drawGC, GCForeground, &values);
2295 } else {
2296 values.foreground = colorPixels[ObjPtr->color];
2297 values.function = GXcopy;
2298 values.fill_style = FillSolid;
2299 XChangeGC(mainDisplay, drawGC,
2300 GCForeground | GCFunction | GCFillStyle, &values);
2301 }
2302
2303 ObjPtr->bbox.rbx = ObjPtr->obbox.rbx = bbox.ltx + PaintLeftText(Str,
2304 textJust, bbox.ltx-drawOrigX, bbox.lty-drawOrigY);
2305
2306 PopCurFont();
2307 }
2308